예제 #1
0
        /// <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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        /// <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);
        }