// This function calculates Circle to OBB collisions public static CollisionInfo CircleToABBCollision(CollisionHull2D a, CollisionHull2D b) { // Find the closest point to the circle from the AABB Vector2 closestPointToCircle = new Vector2(Math.Max(b.GetMinimumCorner().x, Math.Min(a.GetPosition().x, b.GetMaximumCorner().x)), Math.Max(b.GetMinimumCorner().y, Math.Min(a.GetPosition().y, b.GetMaximumCorner().y))); // Get the distance between the closest point and the circle's position Vector2 distance = a.GetPosition() - closestPointToCircle; float distanceSquared = Vector2.Dot(distance, distance); // Calculate the penetration float penetration = a.GetDimensions().x - Mathf.Sqrt(distanceSquared); // Is the penetration a positive value if (penetration > 0) { // If yes, then inform the parents of the complex shape object (if applicable) ReportCollisionToParent(a, b); } else { // If no, return nothing return(null); } // Return full details of the Collision list if the two collide return(new CollisionInfo(a, b, penetration)); }
// This function computes AABB to AABB collisions public static CollisionInfo AABBToAABBCollision(CollisionHull2D a, CollisionHull2D b) { // Get the penetration values for both axes float penetration = 0.0f; // Calculate half extents along x axis for each object float a_extent = a.GetDimensions().x; float b_extent = b.GetDimensions().x; // Get the distance between a and b Vector2 n = (b.GetPosition() - a.GetPosition()); n = new Vector2(Mathf.Abs(n.x), Mathf.Abs(n.y)); // Calculate overlap on x axis float x_overlap = a_extent + b_extent - Mathf.Abs(n.x); // SAT test on x axis if (x_overlap > 0) { // Calculate half extents along x axis for each object a_extent = a.GetDimensions().y; b_extent = b.GetDimensions().y; // Calculate overlap on y axis float y_overlap = a_extent + b_extent - Mathf.Abs(n.y); // SAT test on y axis if (y_overlap > 0) { // Find out which axis is axis of least penetration if (x_overlap > y_overlap) { // If it is Y, then return Y's overlap penetration = y_overlap; } else { // If it is Y, then return X's overlap penetration = x_overlap; } } } // Do the two checks pass? if (penetration > 0) { // If yes, then inform the parents of the complex shape object (if applicable) ReportCollisionToParent(a, b); } else { // If no, return nothing return(null); } // Return full details of the Collision list if the two collide return(new CollisionInfo(a, b, penetration)); }
// This function gets the seperating velocity of two particles public static float CalculateSeparatingVelocity(CollisionHull2D shapeA, CollisionHull2D shapeB) { // Find all required values for calculation Vector2 differenceOfVelocity = (shapeA.gameObject.GetComponent <Particle2D>().velocity - shapeB.gameObject.GetComponent <Particle2D>().velocity) * -1; Vector2 differenceOfPosition = (shapeA.GetPosition() - shapeB.GetPosition()).normalized; // Return the dot product of both velocity and position return(Vector2.Dot(differenceOfVelocity, differenceOfPosition)); }
// This function gets the seperating velocity of two particles public static float CalculateSeparatingVelocity(CollisionHull2D shapeA, CollisionHull2D shapeB) { // Find all required values for calculation Vector2 differenceOfVelocity = (shapeA.gameObject.GetComponent <Particle2D>().velocity - shapeB.gameObject.GetComponent <Particle2D>().velocity) * -1; Vector2 differenceOfPosition = (shapeA.GetPosition() - shapeB.GetPosition()).normalized; // Return the dot product of both velocity and position // Since we are dealing with planes, there is no reason to check the X axis return(differenceOfPosition.y * differenceOfVelocity.y * COLLISION_AMPLIFIER); }
// This function intializes the collision info class based on given information public CollisionInfo(CollisionHull2D _a, CollisionHull2D _b, float _penetration) { // Is collision A's collision type have less priority to collision B? if (_a.collisionType > _b.collisionType) { // If yes, then switch their priorities a = _b; b = _a; } else { // If no, then keep them as so a = _a; b = _b; } // Based on collision hulls, calculate the rest of the values separatingVelocity = CollisionResolution.CalculateSeparatingVelocity(a, b); normal = (b.GetPosition() - a.GetPosition()).normalized; penetration = _penetration; }
// This function computes circle to circle collisions public static CollisionInfo CircleToCircleCollision(CollisionHull2D a, CollisionHull2D b) { // Calculate the distance between both colliders Vector2 distance = a.GetPosition() - b.GetPosition(); float penetration = a.GetDimensions().x + b.GetDimensions().x *(a.GetDimensions().x + b.GetDimensions().x) - Vector2.Dot(distance, distance); // Are the Radii less than or equal to the distance between both circles? if (penetration > 0) { // If yes, then inform the parents of the complex shape object (if applicable) ReportCollisionToParent(a, b); } else { // If no, return nothing return(null); } // Return result return(new CollisionInfo(a, b, penetration)); }
// This function calculate Circle to ABB collisions public static CollisionInfo CircleToOBBCollision(CollisionHull2D a, CollisionHull2D b) { Vector2 closestPointToCircle = new Vector2(Math.Max(b.GetMinimumCorner().x, Math.Min(a.GetPosition().x, b.GetMaximumCorner().x)), Math.Max(b.GetMinimumCorner().y, Math.Min(a.GetPosition().y, b.GetMaximumCorner().y))); Vector2 distance = a.GetPosition() - closestPointToCircle; float distanceSquared = Vector2.Dot(distance, distance); float penetration = a.GetDimensions().x - Mathf.Sqrt(distanceSquared); // Does the check pass? if (penetration > 0) { // If yes, then inform the parents of the complex shape object (if applicable) ReportCollisionToParent(a, b); } else { // If no, return nothing return(null); } // Return full details of the Collision list if the two collide return(new CollisionInfo(a, b, penetration)); }
// This function checks for a collision between two objects by projecting onto a specific axis public static float CheckOBBAxis(CollisionHull2D shapeA, CollisionHull2D shapeB, Vector2 rotationAxis) { // Create a list of all points from the OBB hull for shape A List <Vector2> shapeAPoints = new List <Vector2>(); shapeAPoints.Add(new Vector2(shapeA.GetPosition().x + shapeA.GetDimensions().x, shapeA.GetPosition().y + shapeA.GetDimensions().y)); shapeAPoints.Add(new Vector2(shapeA.GetPosition().x - shapeA.GetDimensions().x, shapeA.GetPosition().y - shapeA.GetDimensions().y)); shapeAPoints.Add(new Vector2(shapeA.GetPosition().x - shapeA.GetDimensions().x, shapeA.GetPosition().y + shapeA.GetDimensions().y)); shapeAPoints.Add(new Vector2(shapeA.GetPosition().x + shapeA.GetDimensions().x, shapeA.GetPosition().y - shapeA.GetDimensions().y)); // Create a list of all points from the OBB hull for shape B List <Vector2> shapeBPoints = new List <Vector2>(); shapeBPoints.Add(new Vector2(shapeB.GetPosition().x + shapeB.GetDimensions().x, shapeB.GetPosition().y + shapeB.GetDimensions().y)); shapeBPoints.Add(new Vector2(shapeB.GetPosition().x - shapeB.GetDimensions().x, shapeB.GetPosition().y - shapeB.GetDimensions().y)); shapeBPoints.Add(new Vector2(shapeB.GetPosition().x - shapeB.GetDimensions().x, shapeB.GetPosition().y + shapeB.GetDimensions().y)); shapeBPoints.Add(new Vector2(shapeB.GetPosition().x + shapeB.GetDimensions().x, shapeB.GetPosition().y - shapeB.GetDimensions().y)); // Initialized shape minimums and maximums float shapeAMin = Mathf.Infinity; float shapeAMax = -Mathf.Infinity; float shapeBMin = Mathf.Infinity; float shapeBMax = -Mathf.Infinity; // Set the total minimum and maximums float totalMin; float totalMax; // Initialize all points for axis checks for (int i = 0; i < shapeAPoints.Count; i++) { // Rotate original point shapeAPoints[i] = new Vector2(Mathf.Cos(shapeA.GetRotation()) * (shapeAPoints[i].x - shapeA.GetPosition().x) - Mathf.Sin(shapeA.GetRotation()) * (shapeAPoints[i].y - shapeA.GetPosition().y) + shapeA.GetPosition().x, Mathf.Sin(shapeA.GetRotation()) * (shapeAPoints[i].x - shapeA.GetPosition().x) + Mathf.Cos(shapeA.GetRotation()) * (shapeAPoints[i].y - shapeA.GetPosition().y) + shapeA.GetPosition().y); // Project point float temp = Vector2.Dot(shapeAPoints[i], rotationAxis); // Is the point less than the minimum? if (temp < shapeAMin) { // If yes, set it to the new minimum shapeAMin = temp; } // Is the point greater than the maximum? if (temp > shapeAMax) { // If yes, set it to the new maximum shapeAMax = temp; } // Rotate original point shapeBPoints[i] = new Vector2(Mathf.Cos(shapeB.GetRotation()) * (shapeBPoints[i].x - shapeB.GetPosition().x) - Mathf.Sin(shapeB.GetRotation()) * (shapeBPoints[i].y - shapeB.GetPosition().y) + shapeB.GetPosition().x, Mathf.Sin(shapeB.GetRotation()) * (shapeBPoints[i].x - shapeB.GetPosition().x) + Mathf.Cos(shapeB.GetRotation()) * (shapeBPoints[i].y - shapeB.GetPosition().y) + shapeB.GetPosition().y); // Project point temp = Vector2.Dot(shapeBPoints[i], rotationAxis); // Is the point less than the minimum? if (temp < shapeBMin) { // If yes, set it to the new minimum shapeBMin = temp; } // Is the point greater than the maximum if (temp > shapeBMax) { // If yes, set it to the new maximum shapeBMax = temp; } } // Is the B shape min greater than the A shape maximum if (shapeBMin > shapeAMin) { // If yes, set A to the new minimum totalMin = shapeAMin; } else { // If no, set B to the new minimum totalMin = shapeBMin; } // Is the A shape maximum greater than the B shape maximum if (shapeBMax < shapeAMax) { // If yes, set A to the new maximum totalMax = shapeAMax; } else { // If no, set B to the new maximum totalMax = shapeBMax; } // Do axis checks bool axisCheck = shapeAMin <= shapeBMax && shapeBMin <= shapeAMax; // Does the check pass? if (axisCheck) { // If yes, then return the penetration return(totalMin - totalMax); } else { // If no, return nothing return(Mathf.Infinity); } }