示例#1
0
 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);
                        }
                    }
                }
            }
        }
示例#5
0
 public CollisionContact(CollisionContact contact)
     : this(contact.A, contact.B, contact.Normal, contact.Distance)
 {
 }