/// <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; } }