/// <summary> /// Checks if this wall blocks /// a view ray from Start to End /// </summary> /// <param name="Start"></param> /// <param name="End"></param> /// <returns>True if blocked, false if OK</returns> public bool IsBlockingSight(V3 Start, V3 End) { V2 P1 = GetP1(); V2 P2 = GetP2(); // 2D V2 Start2D = new V2(Start.X, Start.Z); V2 End2D = new V2(End.X, End.Z); // calculate the sides of the points (returns -1, 0 or 1) int startside = Start2D.GetSide(P1, P2); int endside = End2D.GetSide(P1, P2); // if points are not on same side // the infinite lines cross if (startside != endside) { // verify also the finite line segments cross V2 intersect; if (MathUtil.IntersectLineLine(Start2D, End2D, P1, P2, out intersect)) { // the vector/ray between start and end V3 diff = End - Start; // solve 3d linear equation to get rayheight R2 // (height of possible intersection) // // ( R1 ) (P1) (Q1) // ( R2 ) = (P2) + lambda * (Q2) // ( R3 ) (P3) (Q3) // // using: // R = intersect // P = Start // Q = diff (Direction) // get lambda scale Real lambda = 1.0f; if (diff.X != 0) { lambda = (intersect.X - Start.X) / diff.X; } else if (diff.Z != 0) { lambda = (intersect.Y - Start.Z) / diff.Z; } // calculate the rayheight based on linear 3d equation Real rayheight = Start.Y + lambda * diff.Y; // compare height with wallheights // use average of both endpoints (in case its sloped) // do not care about the sides Real h3 = (Z3 + ZZ3) / 2.0f; Real h2 = (Z2 + ZZ2) / 2.0f; Real h1 = (Z1 + ZZ1) / 2.0f; Real h0 = (Z0 + ZZ0) / 2.0f; bool a, b; // test upper part a = (LeftSide != null && LeftSide.ResourceUpper != null && (LeftSide.Flags.IsNoLookThrough || !LeftSide.Flags.IsTransparent)); b = (RightSide != null && RightSide.ResourceUpper != null && (RightSide.Flags.IsNoLookThrough || !RightSide.Flags.IsTransparent)); if ((a || b) && rayheight < h3 && rayheight > h2) { return(true); } // test middle part a = (LeftSide != null && LeftSide.ResourceMiddle != null && (LeftSide.Flags.IsNoLookThrough || !LeftSide.Flags.IsTransparent)); b = (RightSide != null && RightSide.ResourceMiddle != null && (RightSide.Flags.IsNoLookThrough || !RightSide.Flags.IsTransparent)); if ((a || b) && rayheight < h2 && rayheight > h1) { return(true); } // test lower part (nolookthrough) a = (LeftSide != null && LeftSide.ResourceLower != null); b = (RightSide != null && RightSide.ResourceLower != null); if ((a || b) && rayheight < h1 && rayheight > h0) { return(true); } } } return(false); }
public void GetSide() { int expected; int returned; V2 s; V2 p1, p2; /**************************************************/ // --- TEST --- // p1=p2=s=0, no line s = new V2(0.0f, 0.0f); p1 = new V2(0.0f, 0.0f); p2 = new V2(0.0f, 0.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // p1=s s = new V2(0.0f, 0.0f); p1 = new V2(0.0f, 0.0f); p2 = new V2(0.0f, 1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // p2=s s = new V2(0.0f, 1.0f); p1 = new V2(0.0f, 0.0f); p2 = new V2(0.0f, 1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); /**************************************************/ // --- TEST --- // s is somewhere on line s = new V2(0.5f, 0.5f); p1 = new V2(0.0f, 0.0f); p2 = new V2(1.0f, 1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // s is somewhere on line s = new V2(-0.5f, -0.5f); p1 = new V2(0.0f, 0.0f); p2 = new V2(-1.0f, -1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // s is somewhere on line s = new V2(-0.5f, 0.5f); p1 = new V2(0.0f, 0.0f); p2 = new V2(-1.0f, 1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // s is somewhere on line s = new V2(0.5f, -0.5f); p1 = new V2(0.0f, 0.0f); p2 = new V2(1.0f, -1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); /**************************************************/ // --- TEST --- // s is not on line segment, but on same infinite line s = new V2(2.0f, 2.0f); p1 = new V2(0.0f, 0.0f); p2 = new V2(1.0f, 1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // s is not on line segment, but on same infinite line s = new V2(-2.0f, -2.0f); p1 = new V2(0.0f, 0.0f); p2 = new V2(1.0f, 1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // s is not on line segment, but very far on same infinite line s = new V2(-2000000.0f, -2000000.0f); p1 = new V2(0.0f, 0.0f); p2 = new V2(1.0f, 1.0f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // s is left of line, but close (in bbox) s = new V2(0.45f, 0.55f); p1 = new V2(0.0f, 0.0f); p2 = new V2(1.0f, 1.0f); expected = 1; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // s is left of line and far away (outside bbox) s = new V2(0.0f, 1000.0f); p1 = new V2(0.0f, 0.0f); p2 = new V2(1.0f, 1.0f); expected = 1; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); // --- TEST --- // s is on line s = new V2(14304f, 32512f); p1 = new V2(15872f, 32512f); p2 = new V2(3433.6f, 32512f); expected = 0; returned = s.GetSide(p1, p2); Assert.AreEqual(expected, returned); }
/// <summary> /// Checks if this wall blocks a /// move between Start and End /// </summary> /// <param name="Start">A 3D location</param> /// <param name="End">A 2D location</param> /// <param name="PlayerHeight">Height of the player for ceiling collisions</param> /// <returns></returns> public bool IsBlocking(V3 Start, V2 End, Real PlayerHeight) { V2 P1 = GetP1(); V2 P2 = GetP2(); V2 Start2D = new V2(Start.X, Start.Z); // calculate the sides of the points (returns -1, 0 or 1) int startside = Start2D.GetSide(P1, P2); int endside = End.GetSide(P1, P2); // if points are not on same side // the infinite lines cross if (startside != endside) { // verify also the finite line segments cross V2 intersect; if (MathUtil.IntersectLineLine(Start2D, End, P1, P2, out intersect)) { // verify the side we've crossed is flaggged as "nonpassable" // if so, we actually have a collision if ((startside < 0 && LeftSide != null && !LeftSide.Flags.IsPassable) || (startside > 0 && RightSide != null && !RightSide.Flags.IsPassable)) { return(true); } // still check the stepheight from oldheight to new floor if passable // for too high steps Real endheight = 0.0f; Real diff; if (endside <= 0 && LeftSector != null) { endheight = LeftSector.CalculateFloorHeight((int)End.X, (int)End.Y, true); } else if (endside > 0 && RightSector != null) { endheight = RightSector.CalculateFloorHeight((int)End.X, (int)End.Y, true); } diff = endheight - Start.Y; // diff is bigger than max. step height, we have a collision if (diff > GeometryConstants.MAXSTEPHEIGHT) { return(true); } // check the ceiling heights if (endside <= 0 && LeftSector != null) { endheight = LeftSector.CalculateCeilingHeight((int)End.X, (int)End.Y); } else if (endside > 0 && RightSector != null) { endheight = RightSector.CalculateCeilingHeight((int)End.X, (int)End.Y); } // diff is bigger than max. step height, we have a collision if (endheight < Start.Y + PlayerHeight) { return(true); } } } return(false); }