public void Collide(TimeSpan frameDuration, ICollidableCircle object1, ICollidableCircle object2) { // Calculate the difference between the two objects. Vector2 difference = object1.Position - object2.Position; float distanceAtFrameEnd = difference.Length(); // Calculate the distance that a collision would occur at. float collisionDistance = (object1.Diameter / 2f) + (object2.Diameter / 2f); // Check of the objects are closer that the collision distance. if (distanceAtFrameEnd < collisionDistance) { // Move both objects back to the exact point of collision. float millisecondsAfterCollision = MoveBackToCollisionPoint(frameDuration, object1, object2, distanceAtFrameEnd, collisionDistance); // Calculate the normal of the collision plane. Vector2 normalPlane = difference; normalPlane.Normalize(); // Calculate the collision plane. Vector2 collisionPlane = new Vector2(-normalPlane.Y, normalPlane.X); Vector2 vel1_after; Vector2 vel2_after; CalculatePostCollisionVelocityVectors(object1, object2, normalPlane, collisionPlane, out vel1_after, out vel2_after); // Reapply the move-back from before the collision (using the post collision velocity) Vector2 object1AdjustedPositionAfterCollision = object1.Position + vel1_after * millisecondsAfterCollision; Vector2 object2AdjustedPositionAfterCollision = object2.Position + vel2_after * millisecondsAfterCollision; // Set the objects new positions and velocities. object1.SetState(object1AdjustedPositionAfterCollision, vel1_after); object2.SetState(object2AdjustedPositionAfterCollision, vel2_after); } }
public override bool CanCollide(ICollidable object1, ICollidable object2) { ICollidableCircle typeCorrectedObject1 = object1 as ICollidableCircle; ICollidableCircle typeCorrectedObject2 = object2 as ICollidableCircle; return(typeCorrectedObject1 != null && typeCorrectedObject2 != null); }
private static float MoveBackToCollisionPoint(TimeSpan frameDuration, ICollidableCircle object1, ICollidableCircle object2) { float distanceAtFrameEnd = (object1.Position - object2.Position).Length(); float collisionDistance = (object1.Diameter / 2f) + (object2.Diameter / 2f); return(MoveBackToCollisionPoint(frameDuration, object1, object2, distanceAtFrameEnd, collisionDistance)); }
private static float MoveBackToCollisionPoint(TimeSpan frameDuration, ICollidableCircle object1, ICollidableCircle object2, float distanceAtFrameEnd, float collisionDistance) { // Calculate the position of each object at the start of the frame. float object1PosAtFrameStart_X = (float)(object1.Position.X - object1.Velocity.X * frameDuration.TotalMilliseconds); float object1PosAtFrameStart_Y = (float)(object1.Position.Y - object1.Velocity.Y * frameDuration.TotalMilliseconds); Vector2 object1PosAtFrameStart = new Vector2(object1PosAtFrameStart_X, object1PosAtFrameStart_Y); float object2PosAtFrameStart_X = (float)(object2.Position.X - object2.Velocity.X * frameDuration.TotalMilliseconds); float object2PosAtFrameStart_Y = (float)(object2.Position.Y - object2.Velocity.Y * frameDuration.TotalMilliseconds); Vector2 object2PosAtFrameStart = new Vector2(object2PosAtFrameStart_X, object2PosAtFrameStart_Y); // Calculate the distance between the objects at the start of the frame. Vector2 differenceAtFrameStart = object2PosAtFrameStart - object1PosAtFrameStart; float distanceAtFrameStart = differenceAtFrameStart.Length(); // Calculate the total change in distance during the frame, and the required change to reach the collision. float distanceTotalDelta = distanceAtFrameEnd - distanceAtFrameStart; float distanceDeltaToCollision = collisionDistance - distanceAtFrameStart; // Calculate the percentage change to the collision and after the collision. float percentageDeltaToCollision = distanceDeltaToCollision / distanceTotalDelta; float percentageDeltaAfterCollision = 1 - percentageDeltaToCollision; // Calculte the time before and after the collision in the frame. double millisecondsToCollision = frameDuration.TotalMilliseconds * percentageDeltaToCollision; float millisecondsAfterCollision = (float)(frameDuration.TotalMilliseconds * percentageDeltaAfterCollision); // Calculate and move the objects to their positions at the point of collision. float object1PosAtCollision_X = (float)(object1PosAtFrameStart_X + object1.Velocity.X * millisecondsToCollision); float object1PosAtCollision_Y = (float)(object1PosAtFrameStart_Y + object1.Velocity.Y * millisecondsToCollision); Vector2 object1PosAtCollision = new Vector2(object1PosAtCollision_X, object1PosAtCollision_Y); object1.SetPosition(object1PosAtCollision); float object2PosAtCollision_X = (float)(object2PosAtFrameStart_X + object2.Velocity.X * millisecondsToCollision); float object2PosAtCollision_Y = (float)(object2PosAtFrameStart_Y + object2.Velocity.Y * millisecondsToCollision); Vector2 object2PosAtCollision = new Vector2(object2PosAtCollision_X, object2PosAtCollision_Y); object2.SetPosition(object2PosAtCollision); return(millisecondsAfterCollision); }
public override void Collide(TimeSpan frameDuration, ICollidable object1, ICollidable object2) { ICollidableCircle typeCorrectedObject1 = object1 as ICollidableCircle; IColliadableAxisAlignedRectangle typeCorrectedObject2 = object2 as IColliadableAxisAlignedRectangle; if (typeCorrectedObject1 != null && typeCorrectedObject2 != null) { Collide(frameDuration, typeCorrectedObject2, typeCorrectedObject1); } else { IColliadableAxisAlignedRectangle typeCorrectedObject1_reverse = object1 as IColliadableAxisAlignedRectangle; ICollidableCircle typeCorrectedObject2_reverse = object2 as ICollidableCircle; if (typeCorrectedObject1_reverse != null && typeCorrectedObject2_reverse != null) { Collide(frameDuration, typeCorrectedObject1_reverse, typeCorrectedObject2_reverse); } } }
private static float MoveBackToCollisionPoint(TimeSpan frameDuration, ICollidableCircle object1, ICollidableCircle object2, float distanceAtFrameEnd, float collisionDistance) { // Calculate the position of each object at the start of the frame. float object1PosAtFrameStart_X = (float)(object1.Position.X - object1.Velocity.X * frameDuration.TotalMilliseconds); float object1PosAtFrameStart_Y = (float)(object1.Position.Y - object1.Velocity.Y * frameDuration.TotalMilliseconds); Vector2 object1PosAtFrameStart = new Vector2(object1PosAtFrameStart_X, object1PosAtFrameStart_Y); float object2PosAtFrameStart_X = (float)(object2.Position.X - object2.Velocity.X * frameDuration.TotalMilliseconds); float object2PosAtFrameStart_Y = (float)(object2.Position.Y - object2.Velocity.Y * frameDuration.TotalMilliseconds); Vector2 object2PosAtFrameStart = new Vector2(object2PosAtFrameStart_X, object2PosAtFrameStart_Y); // Calculate the distance between the objects at the start of the frame. Vector2 differenceAtFrameStart = object2PosAtFrameStart - object1PosAtFrameStart; float distanceAtFrameStart = differenceAtFrameStart.Length(); // Calculate the total change in distance during the frame, and the required change to reach the collision. float distanceTotalDelta = distanceAtFrameEnd - distanceAtFrameStart; float distanceDeltaToCollision = collisionDistance - distanceAtFrameStart; // Calculate the percentage change to the collision and after the collision. float percentageDeltaToCollision = distanceDeltaToCollision / distanceTotalDelta; float percentageDeltaAfterCollision = 1 - percentageDeltaToCollision; // Calculte the time before and after the collision in the frame. double millisecondsToCollision = frameDuration.TotalMilliseconds * percentageDeltaToCollision; float millisecondsAfterCollision = (float)(frameDuration.TotalMilliseconds * percentageDeltaAfterCollision); // Calculate and move the objects to their positions at the point of collision. float object1PosAtCollision_X = (float)(object1PosAtFrameStart_X + object1.Velocity.X * millisecondsToCollision); float object1PosAtCollision_Y = (float)(object1PosAtFrameStart_Y + object1.Velocity.Y * millisecondsToCollision); Vector2 object1PosAtCollision = new Vector2(object1PosAtCollision_X, object1PosAtCollision_Y); object1.SetPosition(object1PosAtCollision); float object2PosAtCollision_X = (float)(object2PosAtFrameStart_X + object2.Velocity.X * millisecondsToCollision); float object2PosAtCollision_Y = (float)(object2PosAtFrameStart_Y + object2.Velocity.Y * millisecondsToCollision); Vector2 object2PosAtCollision = new Vector2(object2PosAtCollision_X, object2PosAtCollision_Y); object2.SetPosition(object2PosAtCollision); return millisecondsAfterCollision; }
public override bool CanCollide(ICollidable object1, ICollidable object2) { ICollidableCircle typeCorrectedObject1 = object1 as ICollidableCircle; IColliadableAxisAlignedRectangle typeCorrectedObject2 = object2 as IColliadableAxisAlignedRectangle; if (typeCorrectedObject1 != null && typeCorrectedObject2 != null) { return(true); } else { IColliadableAxisAlignedRectangle typeCorrectedObject1_reverse = object1 as IColliadableAxisAlignedRectangle; ICollidableCircle typeCorrectedObject2_reverse = object2 as ICollidableCircle; if (typeCorrectedObject1_reverse != null && typeCorrectedObject2_reverse != null) { return(true); } else { return(false); } } }
private static float MoveBackToCollisionPoint(TimeSpan frameDuration, ICollidableCircle object1, ICollidableCircle object2) { float distanceAtFrameEnd = (object1.Position - object2.Position).Length(); float collisionDistance = (object1.Diameter / 2f) + (object2.Diameter / 2f); return MoveBackToCollisionPoint(frameDuration, object1, object2, distanceAtFrameEnd, collisionDistance); }
public void Collide(TimeSpan frameDuration, IColliadableAxisAlignedRectangle object1, ICollidableCircle object2) { // Calculate the 4 corners of the rectangle. Vector2 rectVertex_v1 = new Vector2(object1.Position.X - (object1.Width / 2), object1.Position.Y - (object1.Height / 2)); Vector2 rectVertex_v2 = new Vector2(object1.Position.X - (object1.Width / 2), object1.Position.Y + (object1.Height / 2)); Vector2 rectVertex_v3 = new Vector2(object1.Position.X + (object1.Width / 2), object1.Position.Y + (object1.Height / 2)); Vector2 rectVertex_v4 = new Vector2(object1.Position.X + (object1.Width / 2), object1.Position.Y - (object1.Height / 2)); // Calculate the 4 corners of the outer collision zone (based on the size of the circle). Vector2 rectOuterVertex_v1 = new Vector2(object1.Position.X - (object1.Width / 2) - object2.Radius, object1.Position.Y - (object1.Height / 2) - object2.Radius); Vector2 rectOuterVertex_v2 = new Vector2(object1.Position.X - (object1.Width / 2) - object2.Radius, object1.Position.Y + (object1.Height / 2) + object2.Radius); Vector2 rectOuterVertex_v3 = new Vector2(object1.Position.X + (object1.Width / 2) + object2.Radius, object1.Position.Y + (object1.Height / 2) + object2.Radius); Vector2 rectOuterVertex_v4 = new Vector2(object1.Position.X + (object1.Width / 2) + object2.Radius, object1.Position.Y - (object1.Height / 2) - object2.Radius); // Calculate the 4 outer zone sides. Vector2 rectOuterSide1 = rectOuterVertex_v2 - rectOuterVertex_v1; Vector2 rectOuterSide2 = rectOuterVertex_v3 - rectOuterVertex_v2; Vector2 rectOuterSide3 = rectOuterVertex_v4 - rectOuterVertex_v3; Vector2 rectOuterSide4 = rectOuterVertex_v1 - rectOuterVertex_v4; // Calcualte the vectors & distances to each of the outer corners. Vector2 vecToOuterV1 = object2.Position - rectOuterVertex_v1; Vector2 vecToOuterV2 = object2.Position - rectOuterVertex_v2; Vector2 vecToOuterV3 = object2.Position - rectOuterVertex_v3; Vector2 vecToOuterV4 = object2.Position - rectOuterVertex_v4; float distToOuterSide1 = ((rectOuterSide1 * vecToOuterV1).Length() / rectOuterSide1.Length()); float distToOuterSide2 = ((rectOuterSide2 * vecToOuterV2).Length() / rectOuterSide2.Length()); float distToOuterSide3 = ((rectOuterSide3 * vecToOuterV3).Length() / rectOuterSide3.Length()); float distToOuterSide4 = ((rectOuterSide4 * vecToOuterV4).Length() / rectOuterSide4.Length()); // Calcualte the vectors & distances to each of the actual corners. Vector2 vecToVertex1 = object2.Position - rectVertex_v1; Vector2 vecToVertex2 = object2.Position - rectVertex_v2; Vector2 vecToVertex3 = object2.Position - rectVertex_v3; Vector2 vecToVertex4 = object2.Position - rectVertex_v4; float distToVetex1 = vecToVertex1.Length(); float distToVetex2 = vecToVertex2.Length(); float distToVetex3 = vecToVertex3.Length(); float distToVetex4 = vecToVertex4.Length(); bool isPastSide1 = Vector2.Dot(vecToOuterV1, rectOuterSide1) > 0; bool isPastSide2 = Vector2.Dot(vecToOuterV2, rectOuterSide2) > 0; bool isPastSide3 = Vector2.Dot(vecToOuterV3, rectOuterSide3) > 0; bool isPastSide4 = Vector2.Dot(vecToOuterV4, rectOuterSide4) > 0; // Code for calculating the angle between. Not needed any more. //float c = v / (vecToV1.Length() * rect_side1.Length()); //var angleBetween = MathHelper.ToDegrees((float)Math.Acos(c)); /* There are 8 collision zones: * _____________ * : 1 __8__ 7 : * : | | : * : 2 | | 6 : * : |___| : * :_3___4___5_: * * Zones 2, 4, 6 & 8 are collisions with a flat surface of the AA rectangle. * Zones 1, 3, 5 & 7 are *potential* collisions with a corner. * In these zones we must test again that the circle has actually hit the corner of the AA rect. */ bool collision = false; Vector2 collisionPlane = Vector2.Zero; Vector2 normalPlane = Vector2.Zero; if (isPastSide1 && isPastSide2 && isPastSide3 && isPastSide4) { // The centre of the cirle is somewhere within the outer collision zone. // Now figure out which zone it's in and find the collision & normal planes. if (distToOuterSide1 < object2.Radius) { // Zones 1, 8, 7 if (distToOuterSide2 < object2.Radius) { // Zone 1. collision = distToVetex1 < object2.Radius; if (collision) { normalPlane = vecToVertex1; normalPlane.Normalize(); collisionPlane = new Vector2(-normalPlane.Y, normalPlane.X); collisionPlane.Normalize(); } } else if (distToOuterSide3 < object2.Radius) { // Zone 7. collision = distToVetex2 < object2.Radius; if (collision) { normalPlane = vecToVertex4; normalPlane.Normalize(); collisionPlane = new Vector2(-normalPlane.Y, normalPlane.X); collisionPlane.Normalize(); } } else { // Zone 8. collision = true; collisionPlane = rectOuterSide4; collisionPlane.Normalize(); normalPlane = new Vector2(-1 * collisionPlane.Y, collisionPlane.X); normalPlane.Normalize(); } } else if (distToOuterSide3 < object2.Radius) { // Zones 3, 4, 5. if (distToOuterSide2 < object2.Radius) { // Zone 3. collision = distToVetex3 < object2.Radius; if (collision) { normalPlane = vecToVertex2; normalPlane.Normalize(); collisionPlane = new Vector2(-normalPlane.Y, normalPlane.X); collisionPlane.Normalize(); } } else if (distToOuterSide3 < object2.Radius) { // Zone 5. collision = distToVetex4 < object2.Radius; if (collision) { normalPlane = vecToVertex3; normalPlane.Normalize(); collisionPlane = new Vector2(-normalPlane.Y, normalPlane.X); collisionPlane.Normalize(); } } else { // Zone 4. collision = true; collisionPlane = rectOuterSide2; collisionPlane.Normalize(); normalPlane = new Vector2(-1 * collisionPlane.Y, collisionPlane.X); normalPlane.Normalize(); } } else if (distToOuterSide2 < 50) { // Zone 2. collision = true; collisionPlane = rectOuterSide1; collisionPlane.Normalize(); normalPlane = new Vector2(-1 * collisionPlane.Y, collisionPlane.X); normalPlane.Normalize(); } else if (distToOuterSide4 < 50) { // Zone 6. collision = true; collisionPlane = rectOuterSide3; collisionPlane.Normalize(); normalPlane = new Vector2(-1 * collisionPlane.Y, collisionPlane.X); normalPlane.Normalize(); } if (collision) { // Once we know there was a collision, we can apply it to the objects. Vector2 vel1_after; Vector2 vel2_after; CalculatePostCollisionVelocityVectors(object1, object2, normalPlane, collisionPlane, out vel1_after, out vel2_after); // Set the objects new positions and velocities. object1.SetVelocity(vel1_after); object2.SetVelocity(vel2_after); } } }