public CollisionContact(CollisionContact contact) : this(contact.A, contact.B, contact.Normal, contact.Distance) { }
private bool IsInternalEdge(CollisionContact contact) { return false; }
private bool CalculateCollisionCorrection(GameTime gameTime, ref CollisionContact contact) { //Non-stationary object ICutlassCollidable first = contact.A; //Stationary object ICutlassCollidable second = contact.B; Vector2 halfExtents = new Vector2(second.CurrentFrameBoundingRect.Width / 2, second.CurrentFrameBoundingRect.Height / 2); BoundingRectangle firstPlusHalfExtents = new BoundingRectangle(first.CurrentFrameBoundingRect.Left - halfExtents.X, first.CurrentFrameBoundingRect.Top - halfExtents.Y, first.CurrentFrameBoundingRect.Width + 2 * halfExtents.X, first.CurrentFrameBoundingRect.Height + 2 * halfExtents.Y); //Get closest point Vector2 closestPoint = second.CurrentFrameBoundingRect.Center; //X Axis float x = second.CurrentFrameBoundingRect.Center.X; if (x < firstPlusHalfExtents.Left) x = firstPlusHalfExtents.Left; if (x > firstPlusHalfExtents.Right) x = firstPlusHalfExtents.Right; closestPoint.X = x; //Y Axis float y = second.CurrentFrameBoundingRect.Center.Y; if (y < firstPlusHalfExtents.Top) y = firstPlusHalfExtents.Top; if (y > firstPlusHalfExtents.Bottom) y = firstPlusHalfExtents.Bottom; closestPoint.Y = y; //Check if second's center is inside fisrtPlusHalfExtents. If so, find closest edge for negative distance. if (closestPoint == second.CurrentFrameBoundingRect.Center) { Vector2 distanceToClosestEdge; //X Axis if (Math.Abs(closestPoint.X - firstPlusHalfExtents.Right) > Math.Abs(closestPoint.X - firstPlusHalfExtents.Left)) distanceToClosestEdge.X = closestPoint.X - firstPlusHalfExtents.Left; else distanceToClosestEdge.X = closestPoint.X - firstPlusHalfExtents.Right; //Y Axis if (Math.Abs(closestPoint.Y - firstPlusHalfExtents.Bottom) > Math.Abs(closestPoint.Y - firstPlusHalfExtents.Top)) distanceToClosestEdge.Y = closestPoint.Y - firstPlusHalfExtents.Top; else distanceToClosestEdge.Y = closestPoint.Y - firstPlusHalfExtents.Bottom; //Minimum Vector2 axisMinor = VectorUtilities.MinorAxis(distanceToClosestEdge); closestPoint = closestPoint + axisMinor; } //Calculate distance and Normal Vector2 distance = closestPoint - second.CurrentFrameBoundingRect.Center; contact.Distance = VectorUtilities.MaximumComponent(distance); if (contact.Distance == 0.0f)//right up against each other, will get invalid normal. { //On Top if (first.CurrentFrameBoundingRect.Bottom == second.CurrentFrameBoundingRect.Top) { contact.Normal = new Vector2(0.0f, -1.0f); if ((first.Side & CollisionSide.Bottom) == 0 || (second.Side & CollisionSide.Top) == 0) return false; } //To the Right else if (first.CurrentFrameBoundingRect.Left == second.CurrentFrameBoundingRect.Right) { contact.Normal = new Vector2(1.0f, 0.0f); if ((first.Side & CollisionSide.Left) == 0 || (second.Side & CollisionSide.Right) == 0) return false; } //On Bottom else if (first.CurrentFrameBoundingRect.Top == second.CurrentFrameBoundingRect.Bottom) { contact.Normal = new Vector2(0.0f, 1.0f); if ((first.Side & CollisionSide.Top) == 0 || (second.Side & CollisionSide.Bottom) == 0) return false; } //To the Left else if (first.CurrentFrameBoundingRect.Right == second.CurrentFrameBoundingRect.Left) { contact.Normal = new Vector2(-1.0f, 0.0f); if ((first.Side & CollisionSide.Right) == 0 || (second.Side & CollisionSide.Left) == 0) return false; } } else { contact.Normal = VectorUtilities.NormalizedMajorAxis(distance); } //On top if (contact.Normal.Y == -1.0f && ((first.Side & CollisionSide.Bottom) == 0 || (second.Side & CollisionSide.Top) == 0)) { return false; } //To the Right else if (contact.Normal.X == 1.0f && ((first.Side & CollisionSide.Left) == 0 || (second.Side & CollisionSide.Right) == 0)) { return false; } //On Bottom else if (contact.Normal.Y == 1.0f && ((first.Side & CollisionSide.Top) == 0 || (second.Side & CollisionSide.Bottom) == 0)) { return false; } //To the Left else if (contact.Normal.X == -1.0f && ((first.Side & CollisionSide.Right) == 0 || (second.Side & CollisionSide.Left) == 0)) { return false; } Boolean returnValue = false; //Collision Direction is X if (Math.Abs(contact.Normal.X) >= Math.Abs(contact.Normal.Y) && (((first.Velocity.X * gameTime.ElapsedGameTime.TotalMilliseconds) + contact.Distance) * contact.Normal.X < 0)) returnValue = true; //Collision Direction is Y if (Math.Abs(contact.Normal.X) <= Math.Abs(contact.Normal.Y) && (((first.Velocity.Y * gameTime.ElapsedGameTime.TotalMilliseconds) + contact.Distance) * contact.Normal.Y < 0)) returnValue = true; return returnValue; }
private void CheckCollisionsInGroup(GameTime gameTime, List<ICutlassCollidable> collidableObjects) { if (collidableObjects == null || collidableObjects.Count <= 1) return; for (int i = 0; i < collidableObjects.Count; i++) { ICutlassCollidable first = collidableObjects[i]; for (int j = i + 1; j < collidableObjects.Count; j++) { ICutlassCollidable second = collidableObjects[j]; bool collisionCategoriesOverlap = CheckCollisionCategories(first, second); //If both are stationary, or neither is stationary, detect collision but don't do anything about it. if (first.Stationary == second.Stationary) { if (collisionCategoriesOverlap && first.NextFrameBoundingRect.Intersects(second.NextFrameBoundingRect)) { first.CollisionDetected(second); second.CollisionDetected(first); } } //If only one is stationary, detect collision and correct non-stationary object else { //contact.A is non-stationary object. CollisionContact collisionContact; if (first.Stationary) collisionContact = new CollisionContact() { A = second, B = first }; else collisionContact = new CollisionContact() { A = first, B = second }; if (collisionCategoriesOverlap && CalculateCollisionCorrection(gameTime, ref collisionContact) && !IsInternalEdge(collisionContact)) { collisionContact.A.CollisionDetectedWithCorrection(collisionContact.B, collisionContact.Normal, collisionContact.Distance); collisionContact.B.CollisionDetected(collisionContact.A); } } } } }