Ejemplo n.º 1
0
        /// <summary>
        /// Test one axis with SAT.
        /// Updates result if there is a "better" hit
        /// </summary>
        private static void testAxis(Projection prj1, Projection prj2, Vector relativeVelocity, Vector axis, CollisionResult result, double remainingFrameFraction, int axisOwner)
        {
            bool isIntersecting = false, willIntersect = false;
            double t = 0; //Collision time

            //Positive distance means we don't have an overlap. Negative means we have an overlap.
            double distance = prj1.GetDistance(prj2);

            #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT
            Log.Write("\tTesting axis " + axis + ", relative vel: " + relativeVelocity, Log.DEBUG);
            Log.Write("\tProjection 1: " + prj1 + " Projection 2: " + prj2, Log.DEBUG);
            Log.Write("\tDistance " + distance, Log.DEBUG);
            #endif

            //Already intersecting?
            if (distance < 0)
            {
                isIntersecting = true;
                #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT
                Log.Write("\tIntersecting.", Log.DEBUG);
                #endif
            }
            else
            {
                //Calculate velocity component in direction of axis
                double velAxis = axis.DotProduct(relativeVelocity);

                //if (velAxis < Constants.MinDouble) velAxis = 0;

                #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT
                Log.Write("\tNot intersecting. Velocity along axis: " + velAxis, Log.DEBUG);
                #endif

                //If projection of polygon 2 is to the right of polygon 1, AND we have a positive velocity along the axis
                //OR projection of polygon 1 is to the left of polygon 2 AND we have a negative velocity along axis
                //then we might have a collision in the future. If not, the objects are either moving in separate directions
                //or they are staying still.
                if ((velAxis > 0 && prj2.Min >= prj1.Max) || (velAxis < 0 && prj1.Min >= prj2.Max))
                {
                    //If the axis belongs to object 1, and it's facing the opposite direction of the velocity,
                    //then ignore it because it can't collide. Also, if the axis belongs to object 2,
                    //and the axis faces the same direction as the velocity, also ignore it.
                    #if DEBUG_COLLISION_OBJECT_POLYGON
                    Log.Write("\tAxis dot Velocity: " + axis.DotProduct(relativeVelocity) * (axisOwner == 0 ? -1 : 1) + " Axis: " + axis, Log.DEBUG);
                    #endif

                    //Ignore this test if the axis faces the wrong way
                    if (axis.DotProduct(relativeVelocity) * (axisOwner == 0 ? -1 : 1) > Constants.MinDouble)
                    {
                        #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT
                        Log.Write("\tIgnoring test because the edge faces the wrong way. Dot: " + axis.DotProduct(relativeVelocity) * (axisOwner == 0 ? -1 : 1) + "Owner: " + axisOwner);
                        #endif
                        distance = double.NegativeInfinity;
                        isIntersecting = true;
                    }
                    else
                    {
                        t = distance / Math.Abs(velAxis);

                        if (t < remainingFrameFraction)
                            willIntersect = true;

                        #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT
                        Log.Write("\tCollision time: " + t, Log.DEBUG);
                        #endif
                    }
                }
                #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT
                else
                {
                    Log.Write("\tMoving the wrong way. No collision.", Log.DEBUG);
                }
                #endif
            }

            //Find the "best" guess of HOW the objects collides.
            //That is, what direction, and what normal was intersected first.
            if ((!result.isIntersecting && !result.hasIntersected) || //If the result intersection flags are both false, this is the first test.
                (result.isIntersecting && (willIntersect || (isIntersecting && result.distance < distance))) || //Previous result was an overlapping one, while the latest result indicate o1 and o2 will collide in the future instead,
                (result.hasIntersected && willIntersect && t > result.collisionTime)) //Previous result was that o1 and o2 collides in the future, but this result indicates that they collide later.
            {
                result.isIntersecting = isIntersecting;
                result.hasIntersected = willIntersect;
                result.collisionTime = t;
                result.distance = distance;
                result.hitNormal = axis;

                #if DEBUG_COLLISION_OBJECT_POLYGON || DEBUG_COLLISION_OBJECT_OBJECT
                Log.Write("\tNew best axis", Log.DEBUG);
                #endif
            }
            //No intersection now or in the future.
            else if (!isIntersecting && !willIntersect)
            {
                result.hasIntersected = false;
                result.isIntersecting = false;
            }
        }