/// <summary> /// Check for collisions between two bodies at a certain range of z-coordinates (height). /// </summary> /// <param name="b1">The first body to check.</param> /// <param name="b2">The second body to check.</param> /// <param name="mtv">The MTV of the layered collision.</param> /// <returns>The MTV of the intersection.</returns> private CollisionData GetLayeredCollision(Body b1, Body b2, CollisionData mtv) { // If there is no layered collision between the bodies, stop here. if (!mtv.HasCollision) { return mtv; } // Get the dynamic and static body. Body a = b1.IsStatic ? b2 : b1; Body b = (a == b1) ? b2 : b1; // Get the min and max heights for both bodies. Vector2 h1 = new Vector2(a.Shape.BottomDepth, a.Shape.GetTopDepth(a.LayeredPosition)); Vector2 h2 = new Vector2(b.Shape.BottomDepth, b.Shape.GetTopDepth(a.LayeredPosition)); // Get min and max heights for possible collisions between the bodies. Vector2 heights = Calculator.GetMiddleValues(h1, h2); // If there were no matching heights found, no collision possible. if ((heights.X < 0 && heights.Y > 0) || (h2.Y - h1.X) < 3) { return mtv; } //A collision has been found. mtv.HasCollision = true; // Return the MTV. return mtv; }
/// <summary> /// Check for collision between two bodies where one is coming from above the other. /// This is a preemptive step due to the use of body velocity to project future positions. /// </summary> /// <param name="b1">The first body to check.</param> /// <param name="b2">The second body to check.</param> /// <param name="mtv">The MTV of the collision.</param> /// <returns>Whether there was a ground collision or not, from the first body's perspective</returns> private bool CheckGroundCollision(Body b1, Body b2, CollisionData mtv) { // The first body has to be dynamic or if there is no layered collision between the bodies, stop here. if (!mtv.HasCollision) { return false; } // Get the dynamic and static body. Body a = b1.IsStatic ? b2 : b1; Body b = (a == b1) ? b2 : b1; // Both bodies' depth positions. Vector2 h1 = new Vector2(a.Shape.BottomDepth, a.Shape.TopDepth); Vector2 h2 = new Vector2(b.Shape.BottomDepth, b.Shape.GetTopDepth(a.LayeredPosition)); // The difference in height. double diff = h1.X - h2.Y; // If the distance between the bodies is either greater than the threshold or less than the velocity needed to collide, no collision. if (diff > Math.Max(-a.Velocity.Z + _Gravity, 0) || (h2.Y - h1.X) > 2) { return false; } // There must be a ground collision after all. return true; }
/// <summary> /// Pull two bodies that are intersecting apart by using the MTV. /// </summary> /// <param name="b1">The first body to check.</param> /// <param name="b2">The second body to check.</param> /// <param name="mtv">The MTV of the collision.</param> private void ClearIntersection(Body b1, Body b2, CollisionData mtv) { // If the MTV is null, stop here. if (!mtv.HasCollision) { return; } // Add the MTV to the first body and subtract it from the second. Only move dynamic bodies! if (!b1.IsStatic) { b1.Shape.LayeredPosition = b1.Shape.LayeredPosition + mtv.Axis * mtv.Overlap; b1.Velocity = Vector3.Zero; } if (!b2.IsStatic) { b2.Shape.LayeredPosition = b2.Shape.LayeredPosition - mtv.Axis * mtv.Overlap; b2.Velocity = Vector3.Zero; } }
/// <summary> /// Do a narrow phase collision check between two shapes by using SAT (Separating Axis Theorem). /// If a collision has occurred, get the MTV (Minimum Translation Vector) of the two intersecting shapes. /// </summary> /// <param name="s1">The first shape to check.</param> /// <param name="s2">The second shape to check.</param> /// <returns>The MTV of the intersection.</returns> public CollisionData NarrowPhase(Shape s1, Shape s2) { // The minimum amount of overlap. Start real high. float overlap = float.MaxValue; //The collision data. CollisionData data = new CollisionData(s1, s2); // The smallest axis found. Vector2 smallest = Vector2.Zero; try { // Get the axes of both bodies. Vector2[][] axes = new Vector2[][] { s1.GetAxes(), s2.GetAxes() }; // Iterate over the axes of both bodies. foreach (Vector2[] v in axes) { // Iterate over both bodies' axes. foreach (Vector2 a in v) { // Project both bodies onto the axis. Vector2 p1 = s1.Project(a); Vector2 p2 = s2.Project(a); // Get the overlap. float o = Calculator.GetOverlap(p1, p2); // Do the projections overlap? if (o == -1) { // We can guarantee that the shapes do not overlap. return data; } else { // Check for minimum. if (o < overlap) { // Store the minimum overlap and the axis it was projected upon. Make sure that the separation vector is pointing the right way. overlap = o; smallest = a; } } } } } catch (Exception e) { Console.WriteLine(this + ": Narrow Phase Error. (" + e + ")"); } // We now know that every axis had an overlap on it, which means we can guarantee an intersection between the bodies. data.HasCollision = true; data.Axis = smallest; data.Overlap = overlap; //Return the collision data. return data; }