/// <summary> /// Handles the collisions. /// </summary> /// <param name="direction">The direction.</param> /// <param name="source">The source.</param> public static void HandleCollisions(Direction direction, IMovingCollidable source) { // Safety-check the singleton if (_collisionManager == null) { return; } if (source.IsActive) { var sourcePreviousBoundingBox = source.PreviousBoundingBox; // Loop through the possible targets foreach (var target in _collisionManager._collisionTree.Retrieve(source)) { // Initialize variables var sourceBoundingBox = source.BoundingBox; var targetBoundingBox = target.BoundingBox; // Determine if source and target currently overlap (e.g. a collision has occurred if ((source != target) && sourceBoundingBox.Intersects(targetBoundingBox)) { // Initialize the variables var collisionOffset = Vector2.Zero; var sourceDirection = Direction.None; var targetDirection = Direction.None; // Evaluate only in the directions specfied if (direction.HasFlag(Direction.Top)) { // Source Top if (source.PreviousBoundingBox.Top >= targetBoundingBox.Bottom) { collisionOffset = new Vector2(collisionOffset.X, targetBoundingBox.Bottom - sourceBoundingBox.Top); sourceDirection |= Direction.Top; targetDirection |= Direction.Bottom; } } if (direction.HasFlag(Direction.Bottom)) { // Source Bottom if (source.PreviousBoundingBox.Bottom <= targetBoundingBox.Top) { collisionOffset = new Vector2(collisionOffset.X, targetBoundingBox.Top - sourceBoundingBox.Bottom); sourceDirection |= Direction.Bottom; targetDirection |= Direction.Top; } } if (direction.HasFlag(Direction.Left)) { // Source Left if (source.PreviousBoundingBox.Left >= targetBoundingBox.Right) { collisionOffset = new Vector2(targetBoundingBox.Right - sourceBoundingBox.Left, collisionOffset.Y); sourceDirection |= Direction.Left; targetDirection |= Direction.Right; } } if (direction.HasFlag(Direction.Right)) { // Source Right if (source.PreviousBoundingBox.Right <= targetBoundingBox.Left) { collisionOffset = new Vector2(targetBoundingBox.Left - sourceBoundingBox.Right, collisionOffset.Y); sourceDirection |= Direction.Right; targetDirection |= Direction.Left; } } // Handle the collision if one occurred if (sourceDirection != Direction.None) { // Tell the source and target about the collision source.HandleCollisions(new CollisionInfo(source, target, sourceDirection, collisionOffset)); target.HandleCollisions(new CollisionInfo(target, source, targetDirection, -collisionOffset)); } } } } }
private static void TryCorrectPosition(Rectangle tryPosition, TFirst moveableObject, ICollidable collidable, IMovingCollidable movingCollidable, bool correctX, bool correctY, bool correctPastOriginal = false) { float newX = tryPosition.Center.X; float newY = tryPosition.Center.Y; float deltaX = 0, deltaY = 0; if (correctPastOriginal) { newX = newX.Approach(moveableObject.Motion.FrameStartPosition.Center.X, 1); newY = newY.Approach(moveableObject.Motion.FrameStartPosition.Center.Y, 1); deltaX = (newX - moveableObject.Motion.FrameStartPosition.Center.X).Unit(); deltaY = (newY - moveableObject.Motion.FrameStartPosition.Center.Y).Unit(); if (deltaX == 0 && deltaY == 0) { if (movingCollidable == null) { deltaY = -1; } else { deltaY = (newY - movingCollidable.Position.Center.Y).Unit(); } } } while (collidable.DetectCollision(tryPosition, true)) { float newX2 = newX, newY2 = newY; if (correctPastOriginal) { newX2 = newX + deltaX; newY2 = newY + deltaY; } else { if (correctX) { newX2 = newX.Approach(moveableObject.Motion.FrameStartPosition.Center.X, 1); } if (correctY) { newY2 = newY.Approach(moveableObject.Motion.FrameStartPosition.Center.Y, 1); } } if (newX2 == newX && newY2 == newY) { newX = newX2; newY = newY2; break; } else { newX = newX2; newY = newY2; } tryPosition.Center = new Vector2(newX, newY); } }