/// <summary> /// Applies position and velocity changes as a result of the collision. /// </summary> /// <param name="collider"></param> /// <param name="collisionData"></param> public static void ResolveCollision(CollisionData collisionData) { //return if there wan't a collision if (!collisionData.DidCollide) { return; } Collider myCollider = collisionData.MyCollider; Collider otherCollider = collisionData.OtherCollider; float v1xf, v2xf; //calculate restitution float restitution = collisionData.Restitution; //find the velocity of both objects in the direction of the collision float v1xi = Vector2.Dot(myCollider.Body.Vel, collisionData.CollisionAngle); float v2xi = Vector2.Dot(otherCollider.Body.Vel, collisionData.CollisionAngle); //find time since collision float timeSinceCollision; if (v1xi - v2xi == 0) { timeSinceCollision = 0; } else { timeSinceCollision = collisionData.CollisionDepth / (v1xi - v2xi); } //Don't resolve the collision if the objects are moving away from each other if (timeSinceCollision < 0) { return; } //limit how far objects can be pushed if (timeSinceCollision > 1f / 30) { timeSinceCollision = 1f / 30; } //It's rewind time! (update positions) myCollider.Body.Pos -= myCollider.Body.Vel * timeSinceCollision; otherCollider.Body.Pos -= otherCollider.Body.Vel * timeSinceCollision; //find the velocity of both objects perpendicular to the collision Vector2 v1y = myCollider.body.Vel - v1xi * collisionData.CollisionAngle; Vector2 v2y = otherCollider.Body.Vel - v2xi * collisionData.CollisionAngle; //calculate the difference of the final velocities (I think?) float gamma = restitution * (v1xi - v2xi); if (myCollider.body.HasInfiniteMass) { //if both objects have infinite mass if (otherCollider.body.HasInfiniteMass) { v1xf = v1xi; v2xf = v2xi; } //if this object has infinite mass else { v1xf = v1xi; v2xf = gamma + v1xi; } } //if the other object has infinite mass else if (otherCollider.body.HasInfiniteMass) { v1xf = v2xi - gamma; v2xf = v2xi; } //otherwise else { //the big boy equation v1xf = ((myCollider.Body.Mass * v1xi + otherCollider.Body.Mass * v2xi) / otherCollider.Body.Mass - gamma) / (1 + myCollider.Body.Mass / otherCollider.Body.Mass); v2xf = gamma + v1xf; } //calculate and apply final velocities myCollider.Body.Vel = v1xf * collisionData.CollisionAngle + v1y; otherCollider.Body.Vel = v2xf * collisionData.CollisionAngle + v2y; //move the objects after the collision myCollider.Body.Pos += myCollider.Body.Vel * timeSinceCollision; otherCollider.Body.Pos += otherCollider.Body.Vel * timeSinceCollision; }
public override CollisionData CheckCollision(Collider collider) { //these values will be returned if there isn't a collision bool didCollide = false; float collisionDepth = 0; Vector2 collisionAngle = new Vector2(); if (collider is CircleCollider) { CircleCollider circleCollider = (CircleCollider)collider; //check for collision Vector2 r = circleCollider.Body.Pos + circleCollider.Pos - (Body.Pos + Pos); collisionDepth = (radius + circleCollider.Radius) - r.Length(); if (collisionDepth > 0) { didCollide = true; //collision angle r.Normalize(); collisionAngle = r; } } else if (collider is RectangleCollider) { RectangleCollider rectangleCollider = (RectangleCollider)collider; Vector2 myPos = Body.Pos + Pos; Vector2 otherPos = rectangleCollider.Body.Pos + rectangleCollider.Pos; //top left region if (myPos.X < otherPos.X && myPos.Y < otherPos.Y) { Vector2 r = otherPos - myPos; collisionDepth = radius - r.Length(); if (collisionDepth > 0) { didCollide = true; r.Normalize(); collisionAngle = r; } } //top right region else if (myPos.X > otherPos.X + rectangleCollider.Dimensions.X && myPos.Y < otherPos.Y) { Vector2 r = otherPos + new Vector2(rectangleCollider.Dimensions.X, 0) - myPos; collisionDepth = radius - r.Length(); if (collisionDepth > 0) { didCollide = true; r.Normalize(); collisionAngle = r; } } //bottom right region else if (myPos.X > otherPos.X + rectangleCollider.Dimensions.X && myPos.Y > otherPos.Y + rectangleCollider.Dimensions.Y) { Vector2 r = otherPos + rectangleCollider.Dimensions - myPos; collisionDepth = radius - r.Length(); if (collisionDepth > 0) { didCollide = true; r.Normalize(); collisionAngle = r; } } //bottom left region else if (myPos.X < otherPos.X && myPos.Y > otherPos.Y + rectangleCollider.Dimensions.Y) { Vector2 r = otherPos + new Vector2(0, rectangleCollider.Dimensions.Y) - myPos; collisionDepth = radius - r.Length(); if (collisionDepth > 0) { didCollide = true; r.Normalize(); collisionAngle = r; } } //if it isn't in any of those regions, it's basically a square else { Collider rectangularHull = new RectangleCollider(Body, CollisionGroup, new Vector2(Pos.X - Radius, pos.Y - Radius), new Vector2(radius * 2, radius * 2), OnCollision); CollisionData collisionData = rectangularHull.CheckCollision(rectangleCollider); didCollide = collisionData.DidCollide; collisionDepth = collisionData.CollisionDepth; collisionAngle = collisionData.CollisionAngle; } } return(new CollisionData(didCollide, collisionDepth, collisionAngle, this, collider)); }
public override CollisionData CheckCollision(Collider collider) { //these values will be returned if there isn't a collision bool didCollide = false; float collisionDepth = 0; Vector2 collisionAngle = new Vector2(); if (collider is RectangleCollider) { RectangleCollider rectangleCollider = (RectangleCollider)collider; Vector2 myPos = Body.Pos + Pos; Vector2 otherPos = rectangleCollider.Body.Pos + rectangleCollider.Pos; //check for collision if (myPos.Y < otherPos.Y + rectangleCollider.Dimensions.Y && myPos.Y + Dimensions.Y > otherPos.Y && myPos.X < otherPos.X + rectangleCollider.Dimensions.X && myPos.X + Dimensions.X > otherPos.X) { didCollide = true; //check if it's a vertical collision Vector2 r = otherPos - myPos; float collisionAngleConstant = (Dimensions.Y + rectangleCollider.Dimensions.Y) / (Dimensions.X + rectangleCollider.Dimensions.X); if (Math.Abs(r.Y) >= collisionAngleConstant * Math.Abs(r.X)) { if (myPos.Y < otherPos.Y) { collisionAngle = new Vector2(0, 1); //collision depth collisionDepth = myPos.Y + Dimensions.Y - otherPos.Y; } else { collisionAngle = new Vector2(0, -1); //collision depth collisionDepth = otherPos.Y + rectangleCollider.Dimensions.Y - myPos.Y; } } //if it's a horizontal collision else { if (myPos.X < otherPos.X) { collisionAngle = new Vector2(1, 0); //collision depth collisionDepth = myPos.X + Dimensions.X - otherPos.X; } else { collisionAngle = new Vector2(-1, 0); //collision depth collisionDepth = otherPos.X + rectangleCollider.Dimensions.X - myPos.X; } } } } else if (collider is CircleCollider) { CollisionData collisionData = collider.CheckCollision(this); didCollide = collisionData.DidCollide; collisionDepth = collisionData.CollisionDepth; collisionAngle = -collisionData.CollisionAngle; } return(new CollisionData(didCollide, collisionDepth, collisionAngle, this, collider)); }