Пример #1
0
        public static void MonitorCollision(Model sujet, ref Vector3 pos)
        {
			var collision = Program.game.MapSet ? Program.game.Map.Links[0] as Collision : null;

			if (sujet.Epaisseur < 0.1)
				return;

            bool jumping = sujet.Location.Y> sujet.LowestFloor+sujet.StairHeight && pos.Y > sujet.Location.Y;

            Vector3 refPosBottom = pos + new Vector3(0, sujet.StairHeight, 0);
            Vector3 refPosTop = pos + new Vector3(0, sujet.MaxVertex.Y, 0);

            Vector3 inter;
            Vector3 shadowAngle = Vector3.Zero;
            Vector3 globalBone0 = sujet.GetGlobalBone(0, Vector3.Zero);
            globalBone0.Y = sujet.MinVertex.Y;

            float tallest = Single.MinValue;
            float smallest = Single.MaxValue;
            shadowAngle = Vector3.Zero;
			
            Vector3 forwardCliffStart = new Vector3(0, 10f, sujet.Epaisseur * 1.1f);
            Vector3 forwardCliffEnd = new Vector3(0, -10f, sujet.Epaisseur * 1.1f);


            forwardCliffStart = Vector3.Transform(forwardCliffStart, sujet.Rotate_matrix);
            forwardCliffEnd = Vector3.Transform(forwardCliffEnd, sujet.Rotate_matrix);
            cliffBackwards = Vector3.Transform(cliffBackwards, sujet.Rotate_matrix);






			bool pushed = false;


            sujet.Attached = false;
			int moreRes = 0;
			if (Program.game.MapSet)
				moreRes = Program.game.Map.Supp.Count;

			if ((ScenePlayer.ScenePlaying  && ScenePlayer.AllowContactCollision) ||
                !ScenePlayer.ScenePlaying)
            if (!sujet.NPC && sujet.cState != Model.ControlState.Cliff)
            for (int i = 0; i < MainGame.ResourceFiles.Count + moreRes; i++)
            {
                Model mdl = null;
                if (i >= MainGame.ResourceFiles.Count)
                    mdl = Program.game.Map.Supp[i- MainGame.ResourceFiles.Count] as Model;
                else
                    mdl = MainGame.ResourceFiles[i] as Model;

				if (mdl == null) continue;
                if (sujet.ResourceIndex == mdl.ResourceIndex) continue;
				if (mdl.Collision == null)
				{
					if (mdl.Epaisseur < 1) continue;
							if (mdl.NPC || sujet.Masse <= mdl.Masse)
							{
								Vector2 sujetPos = new Vector2(pos.X, pos.Z);
								Vector2 mdlPos = new Vector2(mdl.Location.X, mdl.Location.Z);

								if (sujet.Location.Y > mdl.Location.Y-mdl.StairHeight*2f && sujet.Location.Y<mdl.Location.Y+mdl.MaxVertex.Y)
								{
									float hypo = Vector2.Distance(sujetPos, mdlPos);
									sujetPos -= mdlPos;
									sujetPos /= hypo;
									if (hypo < (mdl.Epaisseur + sujet.Epaisseur))
									{
										sujetPos = mdlPos + sujetPos * (mdl.Epaisseur + sujet.Epaisseur) * 1.1f;
										pos.X = sujetPos.X;
										pos.Z = sujetPos.Y;
									}
									/*else
									if (sujet.ResourceIndex == Program.game.mainCamera.Target.ResourceIndex &&  hypo < (mdl.Epaisseur + sujet.Epaisseur)*2f)
									{
										float val1 = (float)Math.Atan2(sujetPos.X, sujetPos.Y);
										float val2 = sujet.DestRotate + MainGame.PI;
										SrkBinary.MakePrincipal(ref val1);
										SrkBinary.MakePrincipal(ref val2);


										if (Math.Abs(val1-val2) < 1)
										{
											if (Program.game.mainCamera.LXY_read==0)
											{
												Program.game.mainCamera.LXY_read = 10;
												float cam_mdl_diff = (float)(Math.Atan2(Program.game.mainCamera.joyLY_, Program.game.mainCamera.joyLX_) + MathHelper.ToRadians(33));

												Program.game.mainCamera.joyLY_ = (float)Math.Sin(cam_mdl_diff);
												Program.game.mainCamera.joyLX_ = (float)Math.Cos(cam_mdl_diff);
											}
										}
									}*/
								}
							}
				}
				else


				for (int p=0;p< mdl.Collision.PolyCount; p++)
				{
					int start_ = mdl.Collision.StartEnds[p][0];
					int end_ = mdl.Collision.StartEnds[p][1];
					for (int j = start_; j < end_; j++)
					{
						Matrix mt = mdl.Skeleton.Bones[p].LocalMatrix;

						if (Vector3.Distance(mdl.Location,Vector3.Zero) > 0)
							mt = Matrix.Identity;
						Vector3 v1 = Vector3.Transform(
							Vector3.Transform(mdl.Collision.cols[mdl.Collision.indices[j][0][0]], mt), mdl.Rotate_matrix) + mdl.Location;
						Vector3 v2 = Vector3.Transform(
							Vector3.Transform(mdl.Collision.cols[mdl.Collision.indices[j][1][0]], mt), mdl.Rotate_matrix) + mdl.Location;
						Vector3 v3 = Vector3.Transform(
							Vector3.Transform(mdl.Collision.cols[mdl.Collision.indices[j][2][0]], mt), mdl.Rotate_matrix) + mdl.Location;

									var mt_mat = Matrix.CreateFromQuaternion(mt.Rotation);
						Vector3 n1 = Vector3.Transform(mdl.Collision.norms[mdl.Collision.indices[j][0][1]], mt_mat);
						Vector3 n2 = Vector3.Transform(mdl.Collision.norms[mdl.Collision.indices[j][1][1]], mt_mat);
						Vector3 n3 = Vector3.Transform(mdl.Collision.norms[mdl.Collision.indices[j][2][1]], mt_mat);
						Vector3 normal = (n1 + n2 + n3) / 3f;
                        
						if (mdl.NPC || sujet.Masse <= mdl.Masse)
						{
							bool newAttach = false;
							if (!ScenePlayer.ScenePlaying && normal.Y < -0.5)
								if (Inside(refPosTop, v1 - 10f * n1, v2 - 10f * n2, v3 - 10f * n3, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3))
								{
									if (normal.Y < -0.5)
										sujet.JumpCollisionCancel = true;
									Vector3 direction = refPosTop + normal * sujet.Epaisseur;
									if (intersect3D_RayTriangle(refPosTop, direction, v1, v2, v3, out inter) == 1)
									{
										//pos += ((inter + new Vector3(0, -height, 0))- pos)/10f;
										pos = (inter + new Vector3(0, -(sujet.MaxVertex.Y), 0));
										if (pos.Y < sujet.LowestFloor)
											pos.Y = sujet.LowestFloor;

										refPosTop = pos + new Vector3(0, sujet.MaxVertex.Y, 0);
									}
								}
							if (!ScenePlayer.ScenePlaying && Math.Abs(normal.Y) < 0.5f)
							{
								if (Inside(refPosBottom, v1 - 10f * n1, v2 - 10f * n2, v3 - 10f * n3, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3))
								{
									Vector3 direction = refPosBottom + normal * sujet.Epaisseur * 10f;
									if (jumping && normal.Y < -0.5)
										sujet.JumpCollisionCancel = true;
									if (intersect3D_RayTriangle(refPosBottom, direction, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3, out inter) == 1)
									{
										pos.X = inter.X;
										pos.Z = inter.Z;
										refPosBottom = pos + new Vector3(0, sujet.StairHeight, 0);
									}
								}

								if (Inside(refPosTop, v1 - 20f * n1, v2 - 20f * n2, v3 - 20f * n3, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3))
								{
									Vector3 direction = refPosTop + normal * sujet.Epaisseur * 10f;
									if (intersect3D_RayTriangle(refPosTop, direction, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3, out inter) == 1)
									{
										pos.X = inter.X;
										pos.Z = inter.Z;
										refPosTop = pos + new Vector3(0, sujet.MaxVertex.Y, 0);
									}
								}
							}
							else if (normal.Y > 0.5)
							{
								if (intersect3D_RayTriangle(pos + globalBone0 + new Vector3(0, 50000, 0), pos + globalBone0 + new Vector3(0, -50000, 0), v1, v2, v3, out inter) == 1)
								{
									if (Math.Abs(inter.Y-pos.Y)<sujet.StairHeight)
									{
										if (inter.Y < smallest)
										{
											smallest = inter.Y;
										}
										if (inter.Y <= sujet.Location.Y + sujet.StairHeight * 1.5f && inter.Y > tallest)
										{
											shadowAngle = new Vector3(
											0,
											(float)Math.Atan2(normal.Z, normal.Y),
											(float)Math.Atan2(-normal.X, normal.Y));
											tallest = inter.Y;
										}
									}
								}
							}
							if (tallest > Single.MinValue / 2f)
							{
								if (tallest < sujet.Location.Y + sujet.StairHeight * 1.5f)
								{
									sujet.LowestFloor = tallest;
									newAttach = true;
								}
							}
							else if (smallest < Single.MaxValue / 2f)
							{
								if (smallest < sujet.Location.Y + sujet.StairHeight * 1.5f)
								{
									sujet.LowestFloor = smallest;
									newAttach = true;
								}
							}
							if (newAttach && Math.Abs(pos.Y-sujet.LowestFloor)<1)
							{
											if (collision!=null)
												collision.AttachTo(mdl, sujet);
							}
                        
							/*if (!ScenePlayer.ScenePlaying && Math.Abs(normal.Y) < 0.5f)
							{
								if (Inside(refPosBottom, v1 - 20f * n1, v2 - 20f * n2, v3 - 20f * n3, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3))
								{
									Vector3 direction = refPosBottom + normal * sujet.Epaisseur * 10f;

									if (intersect3D_RayTriangle(refPosBottom, direction, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3, out inter) == 1)
									{
										pushed = true;
										pos.X = inter.X;
										pos.Z = inter.Z;
										refPosBottom = pos + new Vector3(0, sujet.StairHeight, 0);
									}
								}

								if (Inside(refPosTop, v1 - 20f * n1, v2 - 20f * n2, v3 - 20f * n3, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3))
								{
									Vector3 direction = refPosTop + normal * sujet.Epaisseur * 10f;
									if (intersect3D_RayTriangle(refPosTop, direction, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3, out inter) == 1)
									{
										pushed = true;
										pos.X = inter.X;
										pos.Z = inter.Z;
										refPosTop = pos + new Vector3(0, sujet.MaxVertex.Y, 0);
									}
								}
							}*/
						}
                    

					}

				}
            }
            sujet.ShadowMatrixSurface = Matrix.CreateFromYawPitchRoll(shadowAngle.X, shadowAngle.Y, shadowAngle.Z);
			bool cliff = sujet.cState == Model.ControlState.Cliff || sujet.cState == Model.ControlState.UnCliff;

			if (collision == null)
				return;
			collision.UpdateIndex(sujet.Location);

			int start = collision.StartEnds[collision.CurrIndex][0];
			int end = collision.StartEnds[collision.CurrIndex][1];
			for (int i = start; i < end; i++)
            {
                Vector3 v1 = collision.cols[collision.indices[i][0][0]];
                Vector3 v2 = collision.cols[collision.indices[i][1][0]];
                Vector3 v3 = collision.cols[collision.indices[i][2][0]];

                Vector3 n1 = collision.norms[collision.indices[i][0][1]];
                Vector3 n2 = collision.norms[collision.indices[i][1][1]];
                Vector3 n3 = collision.norms[collision.indices[i][2][1]];
                Vector3 normal = (n1 + n2 + n3) / 3f;


                if (!cliff && !ScenePlayer.ScenePlaying && normal.Y < -0.5)
                if (Inside(refPosTop, v1 - 20f * n1, v2 - 20f * n2, v3 - 20f * n3, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3))
                {
                    Vector3 direction = refPosTop + normal * sujet.Epaisseur;
                    if (intersect3D_RayTriangle(refPosTop, direction, v1, v2, v3, out inter) == 1)
                    {
                        //pos += ((inter + new Vector3(0, -height, 0))- pos)/10f;
                        pos = (inter + new Vector3(0, -(sujet.MaxVertex.Y), 0));
                        if (pos.Y < sujet.LowestFloor)
                            pos.Y = sujet.LowestFloor;

                        refPosTop = pos + new Vector3(0, sujet.MaxVertex.Y, 0);
                    }
                }
                if (!cliff && !ScenePlayer.ScenePlaying && Math.Abs(normal.Y) < 0.5f)
                {
                    if (Inside(refPosBottom, v1-20f*n1, v2 - 20f * n2, v3 - 20f * n3, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3))
                    {
                        Vector3 direction = refPosBottom + normal * sujet.Epaisseur * 10f;
                        if (jumping && normal.Y < -0.5)
                            sujet.JumpCollisionCancel = true;
                        if (intersect3D_RayTriangle(refPosBottom, direction, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3, out inter) == 1)
                        {
                            pos = (inter + new Vector3(0, -sujet.StairHeight, 0));
                            refPosBottom = pos + new Vector3(0, sujet.StairHeight, 0);
                        }
                    }

                    if (Inside(refPosTop, v1 - 20f * n1, v2 - 20f * n2, v3 - 20f * n3, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3))
                    {
                        Vector3 direction = refPosTop + normal * sujet.Epaisseur * 10f;
                        if (intersect3D_RayTriangle(refPosTop, direction, v1 + sujet.Epaisseur * n1, v2 + sujet.Epaisseur * n2, v3 + sujet.Epaisseur * n3, out inter) == 1)
                        {
                            pos = (inter + new Vector3(0, -(sujet.MaxVertex.Y), 0));
                            if (pos.Y < sujet.LowestFloor)
                                pos.Y = sujet.LowestFloor;

                            refPosTop = pos + new Vector3(0, sujet.MaxVertex.Y, 0);
                        }
                    }
                }
                else if (normal.Y>0.5)
				{
					if (!cliff && !ScenePlayer.ScenePlaying && sujet.cState == Model.ControlState.Fall && !sujet.CliffCancel && (sujet.Links.Count == 0 || sujet.Links[0].ResourceIndex != 39))
                    {
                        if (intersect3D_RayTriangle(refPosTop + forwardCliffStart, refPosTop + forwardCliffEnd, v1, v2, v3, out inter) == 1 && inter.Y > refPosTop.Y + forwardCliffEnd.Y)
                        {
                            Vector3 coin = inter;


							int ordre = 0;  /* V1V2  V2V3  V3V1*/
							float nearest = Single.MaxValue;

							Vector3 va_vb = v1 * 1f;
							Vector3 step_va_vb = (v2 - v1) / Vector3.Distance(v2, v1);
							
							while (Vector3.Distance(va_vb, v2) > sujet.Epaisseur * 2f)
							{
								va_vb += step_va_vb;
								float dist2d = MainGame.Vector3Distance2D(va_vb, refPosTop);
								if (dist2d < nearest)
								{
									coin = va_vb * 1f;
									nearest = dist2d;
									ordre = 0;
								}
							}

							va_vb = v2 * 1f;
							step_va_vb = (v3 - v2) / Vector3.Distance(v3, v2);

							while (Vector3.Distance(va_vb, v3) > sujet.Epaisseur * 2f)
							{
								va_vb += step_va_vb;
								float dist2d = MainGame.Vector3Distance2D(va_vb, refPosTop);
								if (dist2d < nearest)
								{
									coin = va_vb * 1f;
									nearest = dist2d;
									ordre = 1;
								}
							}

							va_vb = v3 * 1f;
							step_va_vb = (v1 - v3) / Vector3.Distance(v1, v3);

							while (Vector3.Distance(va_vb, v1) > sujet.Epaisseur * 2f)
							{
								va_vb += step_va_vb;
								float dist2d = MainGame.Vector3Distance2D(va_vb, refPosTop);
								if (dist2d < nearest)
								{
									coin = va_vb *1f;
									nearest = dist2d;
									ordre = 2;
								}
							}


							float angle = 0;

                            if (ordre == 0)
                            {
                                Vector3 v1v2Base = v2 - v1;
                                v1v2Base /= Vector3.Distance(Vector3.Zero, v1v2Base);
                                angle = (float)Math.Atan2(v1v2Base.X, v1v2Base.Z);
                            }
                            if (ordre == 1)
                            {
                                Vector3 v2v3Base = v3 - v2;
                                v2v3Base /= Vector3.Distance(Vector3.Zero, v2v3Base);
                                angle = (float)Math.Atan2(v2v3Base.X, v2v3Base.Z);
                            }
                            if (ordre == 2)
                            {
                                Vector3 v3v1Base = v1 - v3;
                                v3v1Base /= Vector3.Distance(Vector3.Zero, v3v1Base);
                                angle = (float)Math.Atan2(v3v1Base.X, v3v1Base.Z);
							}


							if (coin.Y > sujet.LowestFloor + sujet.MaxVertex.Y)
                            {
								float newDest = angle + MainGame.PI / 2f;
								SrkBinary.MakePrincipal(ref newDest);

								sujet.DestRotate = newDest;
                                sujet.Rotate = sujet.DestRotate;
                                sujet.cState = Model.ControlState.Cliff;

								//Program.game.cursors[0].Position = coin;
								/*try
                                {
                                    string[] input = File.ReadAllLines("data.txt");
                                    cliffBackwards.X = MainGame.SingleParse(input[0]);
                                    cliffBackwards.Y = MainGame.SingleParse(input[1]);
                                    cliffBackwards.Z = MainGame.SingleParse(input[2]);
                                    cliffBackwards = Vector3.Transform(cliffBackwards, rotYMat);

                                }
                                catch
                                {

                                }*/
								

								/*string[] text = File.ReadAllLines(@"D:\Desktop\KHDebug\KHDebug\bin\DesktopGL\AnyCPU\Debug\Content\Models\P_EX100\Joints.txt");
								text = text[9].Split(':')[1].Split(',');
								sujet.CliffPosition.X = MainGame.SingleParse(text[0]);
								sujet.CliffPosition.Y = MainGame.SingleParse(text[1]);
								sujet.CliffPosition.Z = MainGame.SingleParse(text[2]);*/

								cliffBackwards = Vector3.Transform(sujet.CliffPosition, sujet.Rotate_matrix);
                                pos = coin - cliffBackwards;

								sujet.locBlock = 10;
								sujet.loc = pos;
								sujet.locAction = sujet.loc;

								return;
                            }

                            
                        }

                    }

                    if (intersect3D_RayTriangle(pos + globalBone0+new Vector3(0, 50000, 0), pos + globalBone0 + new Vector3(0, -50000, 0), v1, v2, v3, out inter) ==1)
                    {
						if (Single.IsNaN(sujet.LastLand.X))
						{
							if (inter.Y < smallest)
							{
								smallest = inter.Y;
							}
							if (inter.Y <= sujet.Location.Y + sujet.StairHeight * 1.5f && inter.Y > tallest)
							{
								shadowAngle = new Vector3(
								0,
								(float)Math.Atan2(normal.Z, normal.Y),
								(float)Math.Atan2(-normal.X, normal.Y));
								tallest = inter.Y;
							}
						}
                    }
                }
                if (tallest > Single.MinValue / 2f)
                {
                    if (tallest <sujet.Location.Y + sujet.StairHeight * 1.5f)
                    sujet.LowestFloor = tallest;
                }
                else if (smallest < Single.MaxValue / 2f)
                {
                    if (smallest < sujet.Location.Y + sujet.StairHeight * 1.5f)
                        sujet.LowestFloor = smallest;
                }
            }
            sujet.ShadowMatrixSurface = Matrix.CreateFromYawPitchRoll(shadowAngle.X, shadowAngle.Y, shadowAngle.Z);
            if (pushed && pos.Y<sujet.LowestFloor)
            {
                pos.Y = sujet.LowestFloor;
            }
        }