예제 #1
0
        /// <summary>
        /// Applies position and velocity changes as a result of the collision.
        /// </summary>
        /// <param name="collider"></param>
        /// <param name="collisionData"></param>
        public static void ResolveCollision(CollisionData collisionData)
        {
            //return if there wan't a collision
            if (!collisionData.DidCollide)
            {
                return;
            }

            Collider myCollider    = collisionData.MyCollider;
            Collider otherCollider = collisionData.OtherCollider;

            float v1xf, v2xf;
            //calculate restitution
            float restitution = collisionData.Restitution;

            //find the velocity of both objects in the direction of the collision
            float v1xi = Vector2.Dot(myCollider.Body.Vel, collisionData.CollisionAngle);
            float v2xi = Vector2.Dot(otherCollider.Body.Vel, collisionData.CollisionAngle);

            //find time since collision
            float timeSinceCollision;

            if (v1xi - v2xi == 0)
            {
                timeSinceCollision = 0;
            }
            else
            {
                timeSinceCollision = collisionData.CollisionDepth / (v1xi - v2xi);
            }
            //Don't resolve the collision if the objects are moving away from each other
            if (timeSinceCollision < 0)
            {
                return;
            }
            //limit how far objects can be pushed
            if (timeSinceCollision > 1f / 30)
            {
                timeSinceCollision = 1f / 30;
            }

            //It's rewind time! (update positions)
            myCollider.Body.Pos    -= myCollider.Body.Vel * timeSinceCollision;
            otherCollider.Body.Pos -= otherCollider.Body.Vel * timeSinceCollision;

            //find the velocity of both objects perpendicular to the collision
            Vector2 v1y = myCollider.body.Vel - v1xi * collisionData.CollisionAngle;
            Vector2 v2y = otherCollider.Body.Vel - v2xi * collisionData.CollisionAngle;

            //calculate the difference of the final velocities (I think?)
            float gamma = restitution * (v1xi - v2xi);

            if (myCollider.body.HasInfiniteMass)
            {
                //if both objects have infinite mass
                if (otherCollider.body.HasInfiniteMass)
                {
                    v1xf = v1xi;
                    v2xf = v2xi;
                }
                //if this object has infinite mass
                else
                {
                    v1xf = v1xi;
                    v2xf = gamma + v1xi;
                }
            }
            //if the other object has infinite mass
            else if (otherCollider.body.HasInfiniteMass)
            {
                v1xf = v2xi - gamma;
                v2xf = v2xi;
            }
            //otherwise
            else
            {
                //the big boy equation
                v1xf = ((myCollider.Body.Mass * v1xi + otherCollider.Body.Mass * v2xi) / otherCollider.Body.Mass - gamma) / (1 + myCollider.Body.Mass / otherCollider.Body.Mass);
                v2xf = gamma + v1xf;
            }

            //calculate and apply final velocities
            myCollider.Body.Vel    = v1xf * collisionData.CollisionAngle + v1y;
            otherCollider.Body.Vel = v2xf * collisionData.CollisionAngle + v2y;

            //move the objects after the collision
            myCollider.Body.Pos    += myCollider.Body.Vel * timeSinceCollision;
            otherCollider.Body.Pos += otherCollider.Body.Vel * timeSinceCollision;
        }
예제 #2
0
        public override CollisionData CheckCollision(Collider collider)
        {
            //these values will be returned if there isn't a collision
            bool    didCollide     = false;
            float   collisionDepth = 0;
            Vector2 collisionAngle = new Vector2();

            if (collider is CircleCollider)
            {
                CircleCollider circleCollider = (CircleCollider)collider;

                //check for collision
                Vector2 r = circleCollider.Body.Pos + circleCollider.Pos - (Body.Pos + Pos);
                collisionDepth = (radius + circleCollider.Radius) - r.Length();
                if (collisionDepth > 0)
                {
                    didCollide = true;

                    //collision angle
                    r.Normalize();
                    collisionAngle = r;
                }
            }
            else if (collider is RectangleCollider)
            {
                RectangleCollider rectangleCollider = (RectangleCollider)collider;

                Vector2 myPos    = Body.Pos + Pos;
                Vector2 otherPos = rectangleCollider.Body.Pos + rectangleCollider.Pos;

                //top left region
                if (myPos.X < otherPos.X && myPos.Y < otherPos.Y)
                {
                    Vector2 r = otherPos - myPos;
                    collisionDepth = radius - r.Length();
                    if (collisionDepth > 0)
                    {
                        didCollide = true;
                        r.Normalize();
                        collisionAngle = r;
                    }
                }
                //top right region
                else if (myPos.X > otherPos.X + rectangleCollider.Dimensions.X && myPos.Y < otherPos.Y)
                {
                    Vector2 r = otherPos + new Vector2(rectangleCollider.Dimensions.X, 0) - myPos;
                    collisionDepth = radius - r.Length();
                    if (collisionDepth > 0)
                    {
                        didCollide = true;
                        r.Normalize();
                        collisionAngle = r;
                    }
                }
                //bottom right region
                else if (myPos.X > otherPos.X + rectangleCollider.Dimensions.X && myPos.Y > otherPos.Y + rectangleCollider.Dimensions.Y)
                {
                    Vector2 r = otherPos + rectangleCollider.Dimensions - myPos;
                    collisionDepth = radius - r.Length();
                    if (collisionDepth > 0)
                    {
                        didCollide = true;
                        r.Normalize();
                        collisionAngle = r;
                    }
                }
                //bottom left region
                else if (myPos.X < otherPos.X && myPos.Y > otherPos.Y + rectangleCollider.Dimensions.Y)
                {
                    Vector2 r = otherPos + new Vector2(0, rectangleCollider.Dimensions.Y) - myPos;
                    collisionDepth = radius - r.Length();
                    if (collisionDepth > 0)
                    {
                        didCollide = true;
                        r.Normalize();
                        collisionAngle = r;
                    }
                }
                //if it isn't in any of those regions, it's basically a square
                else
                {
                    Collider      rectangularHull = new RectangleCollider(Body, CollisionGroup, new Vector2(Pos.X - Radius, pos.Y - Radius), new Vector2(radius * 2, radius * 2), OnCollision);
                    CollisionData collisionData   = rectangularHull.CheckCollision(rectangleCollider);
                    didCollide     = collisionData.DidCollide;
                    collisionDepth = collisionData.CollisionDepth;
                    collisionAngle = collisionData.CollisionAngle;
                }
            }

            return(new CollisionData(didCollide, collisionDepth, collisionAngle, this, collider));
        }
예제 #3
0
        public override CollisionData CheckCollision(Collider collider)
        {
            //these values will be returned if there isn't a collision
            bool    didCollide     = false;
            float   collisionDepth = 0;
            Vector2 collisionAngle = new Vector2();

            if (collider is RectangleCollider)
            {
                RectangleCollider rectangleCollider = (RectangleCollider)collider;
                Vector2           myPos             = Body.Pos + Pos;
                Vector2           otherPos          = rectangleCollider.Body.Pos + rectangleCollider.Pos;

                //check for collision
                if (myPos.Y < otherPos.Y + rectangleCollider.Dimensions.Y && myPos.Y + Dimensions.Y > otherPos.Y && myPos.X < otherPos.X + rectangleCollider.Dimensions.X && myPos.X + Dimensions.X > otherPos.X)
                {
                    didCollide = true;

                    //check if it's a vertical collision
                    Vector2 r = otherPos - myPos;
                    float   collisionAngleConstant = (Dimensions.Y + rectangleCollider.Dimensions.Y) / (Dimensions.X + rectangleCollider.Dimensions.X);
                    if (Math.Abs(r.Y) >= collisionAngleConstant * Math.Abs(r.X))
                    {
                        if (myPos.Y < otherPos.Y)
                        {
                            collisionAngle = new Vector2(0, 1);
                            //collision depth
                            collisionDepth = myPos.Y + Dimensions.Y - otherPos.Y;
                        }
                        else
                        {
                            collisionAngle = new Vector2(0, -1);
                            //collision depth
                            collisionDepth = otherPos.Y + rectangleCollider.Dimensions.Y - myPos.Y;
                        }
                    }
                    //if it's a horizontal collision
                    else
                    {
                        if (myPos.X < otherPos.X)
                        {
                            collisionAngle = new Vector2(1, 0);
                            //collision depth
                            collisionDepth = myPos.X + Dimensions.X - otherPos.X;
                        }
                        else
                        {
                            collisionAngle = new Vector2(-1, 0);
                            //collision depth
                            collisionDepth = otherPos.X + rectangleCollider.Dimensions.X - myPos.X;
                        }
                    }
                }
            }
            else if (collider is CircleCollider)
            {
                CollisionData collisionData = collider.CheckCollision(this);
                didCollide     = collisionData.DidCollide;
                collisionDepth = collisionData.CollisionDepth;
                collisionAngle = -collisionData.CollisionAngle;
            }

            return(new CollisionData(didCollide, collisionDepth, collisionAngle, this, collider));
        }