Beispiel #1
0
 public CollisionContact(ICutlassCollidable a, ICutlassCollidable b, Vector2 normal, float distance)
 {
     A        = a;
     B        = b;
     Normal   = normal;
     Distance = distance;
 }
Beispiel #2
0
 public CollisionContact(ICutlassCollidable a, ICutlassCollidable b, Vector2 normal, float distance)
 {
     A = a;
     B = b;
     Normal = normal;
     Distance = distance;
 }
        private void AddCollidableObject(ICutlassCollidable collidableObject)
        {
            //Want to extend collisions slightly outside visible screen.
            BoundingRectangle collisionSpace = BoundingRectangle.Scale(_ViewScreen.VisibleArea, 1.1f, _ViewScreen.VisibleArea.Center);

            BoundingRectangle intersection = BoundingRectangle.Intersection(collidableObject.CurrentFrameBoundingRect, collisionSpace);

            int minHorizontalGroup = -1,
                maxHorizontalGroup = -1,
                minVerticalGroup   = -1,
                maxVerticalGroup   = -1;

            if (!intersection.IsZero)
            {
                float groupWidth  = collisionSpace.Width / _HorizontalGroups;
                float groupHeight = collisionSpace.Height / _VerticalGroups;

                minHorizontalGroup = Math.Max(0, (int)((intersection.Left - collisionSpace.Left) / groupWidth));
                maxHorizontalGroup = Math.Min(_HorizontalGroups - 1, (int)((intersection.Right - collisionSpace.Left) / groupWidth));
                minVerticalGroup   = Math.Max(0, (int)((intersection.Top - collisionSpace.Top) / groupHeight));
                maxVerticalGroup   = Math.Min(_VerticalGroups - 1, (int)((intersection.Bottom - collisionSpace.Top) / groupHeight));

                for (int i = minHorizontalGroup; i <= maxHorizontalGroup; i++)
                {
                    for (int j = minVerticalGroup; j <= maxVerticalGroup; j++)
                    {
                        if (_CurrentCollidableObjects[i, j] == null)
                        {
                            _CurrentCollidableObjects[i, j] = new List <ICutlassCollidable>();
                        }
                        _CurrentCollidableObjects[i, j].Add(collidableObject);
                    }
                }
            }
        }
Beispiel #4
0
        public void CollisionDetectedWithCorrection(ICutlassCollidable collisionTarget, Vector2 normal, float distance)
        {
            //Check for jumping through top-only collisions, or level-transition zones.
            if ((collisionTarget.Side == CollisionSide.Top && normal.Y == -1 && _IsJumpingDown) ||
                collisionTarget is LevelTransition)
            {
                return;
            }

            //get the separation and penetration separately, this is to stop penetration
            //from causing the obejcts to ping apart
            float separation  = Math.Max(distance, 0.0f);
            float penetration = Math.Min(distance, 0.0f);

            //get relative normal velocity so object will stop exactly on surface.
            float relativeNormalVelocity = 0.0f;

            relativeNormalVelocity = VectorUtilities.DotProduct(Velocity, normal);

            if (relativeNormalVelocity < 0)
            {
                //remove normal velocity
                Velocity -= normal * relativeNormalVelocity;
            }

            //is this ground?
            if (normal.Y < 0.0f)
            {
                _WasOnGround = true;
                //StandingOn.Add(contact.B);
            }
        }
        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);
                        }
                    }
                }
            }
        }
        public void AddObject(ICutlassSceneObject o)
        {
            SceneObjectId sceneObjectId;

            lock (_SceneObjectIdLock)
            {
                sceneObjectId = _NextSceneObjectId++;
            }

            Objects.Add(sceneObjectId, o);

            //Add object to necessary lists.
            ICutlassLoadable loadable = o as ICutlassLoadable;

            if (loadable != null)
            {
                LoadableObjects.Add(sceneObjectId, loadable);
            }

            ICutlassMovable movable = o as ICutlassMovable;

            if (movable != null)
            {
                MovableObjects.Add(sceneObjectId, movable);
            }

            ICutlassCollidable collidable = o as ICutlassCollidable;

            if (collidable != null)
            {
                CollidableObjects.Add(sceneObjectId, collidable);
            }

            ICutlassUpdateable updateable = o as ICutlassUpdateable;

            if (updateable != null)
            {
                UpdateableObjects.Add(sceneObjectId, updateable);
            }

            ICutlassDrawable drawable = o as ICutlassDrawable;

            if (drawable != null)
            {
                DrawableObjects.Add(sceneObjectId, drawable);
            }

            //If this scene has already been initialized, initialize this object now.
            if (_Initialized && loadable != null)
            {
                loadable.LoadContent();
            }
        }
Beispiel #7
0
 public virtual void CollisionDetectedWithCorrection(ICutlassCollidable collisionTarget, Vector2 normal, float distance)
 {
 }
Beispiel #8
0
 public virtual void CollisionDetected(ICutlassCollidable collisionTarget)
 {
 }
        private void AddCollidableObject(ICutlassCollidable collidableObject)
        {
            //Want to extend collisions slightly outside visible screen.
            BoundingRectangle collisionSpace = BoundingRectangle.Scale(_ViewScreen.VisibleArea, 1.1f, _ViewScreen.VisibleArea.Center);

            BoundingRectangle intersection = BoundingRectangle.Intersection(collidableObject.CurrentFrameBoundingRect, collisionSpace);

            int minHorizontalGroup = -1,
                  maxHorizontalGroup = -1,
                  minVerticalGroup = -1,
                  maxVerticalGroup = -1;

            if (!intersection.IsZero)
            {
                float groupWidth = collisionSpace.Width / _HorizontalGroups;
                float groupHeight = collisionSpace.Height / _VerticalGroups;

                minHorizontalGroup = Math.Max(0, (int)((intersection.Left - collisionSpace.Left) / groupWidth));
                maxHorizontalGroup = Math.Min(_HorizontalGroups - 1, (int)((intersection.Right - collisionSpace.Left) / groupWidth));
                minVerticalGroup = Math.Max(0, (int)((intersection.Top - collisionSpace.Top) / groupHeight));
                maxVerticalGroup = Math.Min(_VerticalGroups - 1, (int)((intersection.Bottom - collisionSpace.Top) / groupHeight));

                for (int i = minHorizontalGroup; i <= maxHorizontalGroup; i++)
                    for (int j = minVerticalGroup; j <= maxVerticalGroup; j++)
                    {
                        if (_CurrentCollidableObjects[i, j] == null)
                            _CurrentCollidableObjects[i, j] = new List<ICutlassCollidable>();
                        _CurrentCollidableObjects[i, j].Add(collidableObject);
                    }
            }
        }
 private bool CheckCollisionCategories(ICutlassCollidable first, ICutlassCollidable second)
 {
     //No collision if their catgories don't overlap.
     return ((first.Category & second.CategoryMask) != 0 &&
         (second.Category & first.CategoryMask) != 0);
 }
Beispiel #11
0
 public virtual void CollisionDetectedWithCorrection(ICutlassCollidable collisionTarget, Vector2 normal, float distance)
 {
 }
Beispiel #12
0
 public virtual void CollisionDetected(ICutlassCollidable collisionTarget)
 {
 }
Beispiel #13
0
        public void CollisionDetectedWithCorrection(ICutlassCollidable collisionTarget, Vector2 normal, float distance)
        {
            //Check for jumping through top-only collisions, or level-transition zones.
            if ((collisionTarget.Side == CollisionSide.Top && normal.Y == -1 && _IsJumpingDown) ||
                collisionTarget is LevelTransition)
                return;

            //get the separation and penetration separately, this is to stop penetration
            //from causing the obejcts to ping apart
            float separation = Math.Max(distance, 0.0f);
            float penetration = Math.Min(distance, 0.0f);

            //get relative normal velocity so object will stop exactly on surface.
            float relativeNormalVelocity = 0.0f;

            relativeNormalVelocity = VectorUtilities.DotProduct(Velocity, normal);

            if (relativeNormalVelocity < 0)
            {
                //remove normal velocity
                Velocity -= normal * relativeNormalVelocity;
            }

            //is this ground?
            if (normal.Y < 0.0f)
            {
                _WasOnGround = true;
                //StandingOn.Add(contact.B);
            }
        }
        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 bool CheckCollisionCategories(ICutlassCollidable first, ICutlassCollidable second)
 {
     //No collision if their catgories don't overlap.
     return((first.Category & second.CategoryMask) != 0 &&
            (second.Category & first.CategoryMask) != 0);
 }