Пример #1
0
        internal void ResolveAABBAABBStatic(PhysicsBody2D BodyS, PhysicsBody2D BodyD)
        {
            Shapes.AABB BA = BodyS.shape as Shapes.AABB;
            Shapes.AABB BB = BodyD.shape as Shapes.AABB;

            Vector3 delta = BB.transform.Position - BA.transform.Position;
            Vector3 tD    = (BA.Dimensions + BB.Dimensions) / 2;

            if (Math.Abs(delta.X) > Math.Abs(delta.Z))
            {
                if (delta.X < 0)
                {// Left
                    BodyD.transform.parent.Position = BodyS.transform.Position - new Vector3(tD.X, 0, 0);
                }
                else
                {// Right
                    BodyD.transform.parent.Position = BodyS.transform.Position + new Vector3(tD.X, 0, 0);
                }
            }
            else
            {
                if (delta.Z < 0)
                {// Top
                    BodyD.transform.parent.Position = BodyS.transform.Position - new Vector3(0, 0, tD.Z);
                }
                else
                {// Bottom
                    BodyD.transform.parent.Position = BodyS.transform.Position + new Vector3(0, 0, tD.Z);
                }
            }
        }
Пример #2
0
        internal List <int> CalculateBoundsIndices(PhysicsBody2D body)
        {
            List <int> indices     = new List <int>();
            AABB       boundingBox = body.shape.GetBoundingBox();
            int        dimension   = (int)Math.Max(boundingBox.Dimensions.X, boundingBox.Dimensions.Z) / 4;

            int x = (int)Math.Floor(body.transform.Position.X / PhysicsSettings.BOUNDINGBOX_LARGEST);
            int z = (int)Math.Floor(body.transform.Position.Z / PhysicsSettings.BOUNDINGBOX_LARGEST);

            indices.Add(x + (z * (int)Math.Sqrt(int.MaxValue / 2)));

            for (int i_x = 0; i_x < dimension; ++i_x)
            {
                for (int i_z = 0; i_z < dimension; ++i_z)
                {
                    if (i_x == 0 || i_x == dimension - 1 || i_z == 0 || i_z == dimension - 1)
                    {
                        Transform newTransform = new Transform();
                        newTransform.Transformation = Matrix.Identity;
                        newTransform.Position       = new Vector3((i_x - (int)Math.Floor(dimension / 2.0f)) * PhysicsSettings.BOUNDINGBOX_LARGEST + x * PhysicsSettings.BOUNDINGBOX_LARGEST, 0, (i_z - (int)Math.Floor(dimension / 2.0f)) * PhysicsSettings.BOUNDINGBOX_LARGEST + z * PhysicsSettings.BOUNDINGBOX_LARGEST) - bounds_transform.Position;
                        int newIndex = CalculateBoundsIndex(newTransform);
                        if (!indices.Contains(newIndex))
                        {
                            indices.Add(newIndex);
                        }
                    }
                }
            }

            return(indices);
        }
Пример #3
0
        /// <summary>
        /// Adds a PhysicsBody to the Physics engine, bodies add themselves when made, this rarely needs to be called outside of the PhysicsBody constructor
        /// </summary>
        /// <param name="body">The body to be added</param>
        internal void AddBody(PhysicsBody2D body)
        {
            if (!bodies_All.Contains(body))
            {
                bodies_All.Add(body);
            }
            else
            {
                AddChunk(body);
            }

            //if (body.flagBodyType.HasFlag(BodyType.STATIC))
            //{
            if (bounds == null)
            {
                bounds           = new List <PhysicsBoundingChunk2D>();
                bounds_hashtable = new Dictionary <int, PhysicsBoundingChunk2D>();

                AddChunk(body);
            }
            else
            {
                AddChunk(body);
            }

            if (!body.flagBodyType.HasFlag(BodyType.STATIC))
            {
                if (!bodies_Active.Contains(body))
                {
                    bodies_Active.Add(body);
                }
            }
        }
Пример #4
0
 /// <summary>
 /// Removes a collision delegate from the physics body
 /// </summary>
 /// <param name="callback">The delegate to be removed</param>
 /// <param name="body">The body to remove the delegate from</param>
 internal void UnregisterCollisionCallback(Collision2D.OnCollision callback, PhysicsBody2D body)
 {
     // First check to see if the registry contains this key
     if (registery_CollisionCallbacks.ContainsKey(body))
     {
         body.collisionCallbacks.Remove(callback);
     }
 }
Пример #5
0
 /// <summary>
 /// Adds a collision delegate to the physics bodies list of callbacks
 /// This enables something using the delegate to be alerted when the body in question collides with something else
 /// </summary>
 /// <param name="callback">The delegate to be added</param>
 /// <param name="body">The body to add the delegate to</param>
 internal void RegisterCollisionCallback(Collision2D.OnCollision callback, PhysicsBody2D body)
 {
     // First check to see if the registry contains this key
     if (!registery_CollisionCallbacks.ContainsKey(body))
     {
         // If the registry does not contain the body, add the body, and its list of callbacks
         registery_CollisionCallbacks.Add(body, body.collisionCallbacks);
     }
     // Add the new callback to the list
     body.collisionCallbacks.Add(callback);
 }
Пример #6
0
        private static Collision2D Helper_EvaluateCollisions(PhysicsBody2D bodyA, PhysicsBody2D bodyB)
        {
            foreach (Collision2D collision in bodyA.collisions)
            {
                if ((collision.BodyB == bodyB && collision.BodyA == bodyA) || (collision.BodyA == bodyB && collision.BodyB == bodyA))
                {
                    return(collision);
                }
            }

            return(new Collision2D(bodyA, bodyB));
        }
        /// <summary>
        /// Attempts to add a body to the bounding chunk, the criteria for failure are:
        /// The body is not static
        /// The body is not overlapping the bounds
        /// </summary>
        /// <param name="body">The body to add</param>
        /// <returns>True on success, False on failure</returns>
        public bool AddBody(PhysicsBody2D body)
        {
            bool added = false;

            //for (int i = 0; i < PhysicsEngine.PhysicsSettings.BOUNDINGBOX_ORDERS; ++i)
            //{
            //    foreach (AABB bounds in orderToIndex[i])
            //    {
            //        if (bounds.OverlapTest(body.shape))
            //        {
            //            if (body.flagBodyType.HasFlag(PhysicsEngine.BodyType.STATIC))
            //            {
            //                statics[bounds].Add(body);
            //            }
            //            else
            //            {
            //                dynamics[bounds].Add(body);
            //            }
            //            body.chunks.Add(this);
            //            added = true;
            //        }
            //    }
            //}

            for (int i = ShapeToOrder(body.shape); i < PhysicsEngine.PhysicsSettings.BOUNDINGBOX_ORDERS; ++i)
            {
                foreach (AABB bounds in orderToIndex[i])
                {
                    if (bounds.OverlapTest(body.shape, bounds.transform, body.transform))
                    {
                        if (body.flagBodyType.HasFlag(PhysicsEngine.BodyType.STATIC))
                        {
                            if (!statics[bounds].Contains(body))
                            {
                                statics[bounds].Add(body);
                            }
                        }
                        else
                        {
                            if (!dynamics[bounds].Contains(body))
                            {
                                dynamics[bounds].Add(body);
                            }
                        }
                        body.chunks.Add(this);
                        added = true;
                    }
                }
            }

            return(added);
        }
Пример #8
0
 /// <summary>
 /// Given a body get all its collision callbacks
 /// </summary>
 /// <param name="body">The body to get callbacks from</param>
 /// <returns></returns>
 internal List <Collision2D.OnCollision> GetCollisionCallbacks(PhysicsBody2D body)
 {
     // First check to see if the registry contains this key
     if (registery_CollisionCallbacks.ContainsKey(body))
     {
         // If it has this body, get its list
         return(registery_CollisionCallbacks[body]);
     }
     else
     {
         return(null);
     }
 }
Пример #9
0
        // TODO fix Circle vs Circle Static collision resolution
        internal void ResolveCircleCircleStatic(PhysicsBody2D BodyS, PhysicsBody2D BodyD)
        {
            Shapes.Circle BA = BodyS.shape as Shapes.Circle;
            Shapes.Circle BB = BodyD.shape as Shapes.Circle;
            Vector3       dN = Vector3.Normalize(BA.lastOverlap_delta);
            float         dR = BA.lastOverlap_radius;

            BodyD.transform.parent.Position = BodyS.transform.Position + dN * dR;

            if (BodyD.Velocity.LengthSquared() > 0)
            {
                float projection = 2 * -Vector3.Dot(BodyD.Velocity * Math.Min(BodyD.Restitution, BodyS.Restitution), dN);

                BodyD.Velocity = BodyD.Velocity + projection * dN;
            }
        }
        /// <summary>
        /// Given a body this method returns all bodies around that body in this bounding chunk
        /// </summary>
        /// <param name="body">The body to get neighbours of</param>
        /// <returns>Either a list of bodies, if the body is within this bounding chunk, or an empty list, if it is not</returns>
        public List <PhysicsBody2D> GetNearbyBodies(PhysicsBody2D body)
        {
            List <PhysicsBody2D> bodies = new List <PhysicsBody2D>();

            // Since every AABB in this chunk has a list that contains all the objects in that AABB and all the children AABB I only need to check against the AABBs at the same 'order' as the bodies shape
            for (int i = ShapeToOrder(body.shape); i < PhysicsEngine.PhysicsSettings.BOUNDINGBOX_ORDERS; ++i)
            {
                foreach (AABB bounds in orderToIndex[i])
                {
                    if (bounds.OverlapTest(body.shape, bounds.transform, body.transform))
                    {
                        bodies.AddRange(statics[bounds]);
                        bodies.AddRange(dynamics[bounds]);
                    }
                }
            }

            return(bodies);
        }
 // TODO RemoveBody from PhysicsBoundingChunk2D can probably be way better
 public void RemoveBody(PhysicsBody2D body)
 {
     foreach (AABB bounds in bounds)
     {
         if (body.flagBodyType.HasFlag(PhysicsEngine.BodyType.STATIC))
         {
             if (statics[bounds].Contains(body))
             {
                 statics[bounds].Remove(body);
             }
         }
         else
         {
             if (dynamics[bounds].Contains(body))
             {
                 dynamics[bounds].Remove(body);
             }
         }
     }
 }
Пример #12
0
        /// <summary>
        /// Call this method to test collisions
        /// This method wants to be called as the last piece of a collision pass, after all definite non-collisions have been ruled out
        /// </summary>
        /// <param name="BodyA">The first body</param>
        /// <param name="BodyB">The second body</param>
        /// <returns>An instance of Collision</returns>
        public static Collision2D Evaluate(PhysicsBody2D bodyA, PhysicsBody2D bodyB)
        {
            // No need to check collisions on a body with itself
            if (bodyA != bodyB)
            {
                // This needs to evaluate whether these 2 bodies already have a Collision between them, if so, evaluate it, and return it
                // If they don't it needs to make one, if they are colliding
                // If they aren't colliding return a new Collision with CollisionType none

                Collision2D collision;

                // Neither body has any collisions
                if (bodyA.collisions.Count == bodyB.collisions.Count && bodyA.collisions.Count == 0)
                {
                    // A new collision should be made
                    collision = new Collision2D(bodyA, bodyB);
                }
                else
                {
                    // An optimisation here is to check the smaller list of collisions
                    // Since it is an iteration
                    if (bodyA.collisions.Count <= bodyB.collisions.Count)
                    {
                        collision = Helper_EvaluateCollisions(bodyA, bodyB);
                    }
                    else
                    {
                        collision = Helper_EvaluateCollisions(bodyB, bodyA);
                    }
                }

                // Evaluate the collision
                //collision.Evaluate();
                // Return it
                return(collision);
            }
            else
            {
                return(null);
            }
        }
Пример #13
0
        public List <PhysicsBody2D> GetCollisionPass(PhysicsBody2D body)
        {
            // TODO broad phase collision pass on non-static bodies
            List <PhysicsBody2D> bodies = new List <PhysicsBody2D>();

            List <int> indices = CalculateBoundsIndices(body);

            foreach (int index in indices)
            {
                if (bounds_hashtable.ContainsKey(index))
                {
                    bodies.AddRange(bounds_hashtable[index].GetNearbyBodies(body));
                }
                else
                {
                    // This means there is no chunk there, and it must be made
                    AddChunk(body);
                }
            }

            return(bodies);
        }
Пример #14
0
        internal void ResolveCircleAABBStatic(PhysicsBody2D BodyS, PhysicsBody2D BodyD)
        {
            // TODO Circle AABB
            Shapes.Circle BA = (BodyS.shape is Shapes.Circle) ? BodyS.shape as Shapes.Circle : BodyD.shape as Shapes.Circle;
            Shapes.AABB   BB = (BodyS.shape is Shapes.Circle) ? BodyD.shape as Shapes.AABB : BodyS.shape as Shapes.AABB;

            // Might as well normalize the delta while we are at it
            Vector3 dN     = Vector3.Normalize(BA.lastOverlap_delta);
            float   theta  = (float)Math.Atan(dN.Z / dN.X);
            float   length = BB.LengthAtAngle(theta);

            // Time to move the circle and the aabb away from each other along the normal
            // Calculate a new center of mass for the system, and offset them both their radii away from this center of mass, along the normal, based on their mass percentage of the system
            float dR = length + BA.Radius;

            BodyD.transform.parent.Position = BodyS.transform.Position + (dN * dR);

            if (BodyB.Velocity.LengthSquared() > 0 && Vector3.Dot(Vector3.Normalize(BodyB.Velocity), dN) > 0)
            {
                float projection = 2 * -Vector3.Dot(BodyB.Velocity * MathHelper.Min(BodyB.Restitution, BodyA.Restitution), dN);

                if (BodyA.shape is Shapes.AABB)
                {
                    if (Math.Abs(dN.X) > Math.Abs(dN.Y))
                    {
                        BodyB.Velocity = new Vector3(-BodyB.Velocity.X, BodyB.Velocity.Y, BodyB.Velocity.Z);
                    }
                    else
                    {
                        BodyB.Velocity = new Vector3(BodyB.Velocity.X, BodyB.Velocity.Y, -BodyB.Velocity.Z);
                    }
                }
                else
                {
                    BodyB.Velocity = BodyB.Velocity + projection * BodyB.Mass * dN;
                }
            }
        }
Пример #15
0
        private Collision2D(PhysicsBody2D A, PhysicsBody2D B)
        {
            // For ease of computing around static dynamic collisions I have decided the static body should always be BodyA
            if (A.flagBodyType.HasFlag(PhysicsEngine.BodyType.STATIC) || A.flagBodyType.HasFlag(PhysicsEngine.BodyType.KINEMATIC) || B.flagBodyType.HasFlag(PhysicsEngine.BodyType.STATIC) || B.flagBodyType.HasFlag(PhysicsEngine.BodyType.KINEMATIC))
            {
                if (A.flagBodyType.HasFlag(PhysicsEngine.BodyType.STATIC) || A.flagBodyType.HasFlag(PhysicsEngine.BodyType.KINEMATIC))
                {
                    BodyA = A;
                    BodyB = B;
                }
                else
                {
                    BodyA = B;
                    BodyB = A;
                }
            }
            else
            {
                BodyA = A;
                BodyB = B;
            }

            type = PhysicsEngine.CollisionType.NONE;
        }
 public bool BoundsTest(PhysicsBody2D body)
 {
     return(bounds[0].OverlapTest(body.shape, bounds[0].transform, body.transform));
 }
Пример #17
0
 internal void RemoveBody(PhysicsBody2D body)
 {
     bodies_Dead.Add(body);
 }
Пример #18
0
        internal void AddChunk(PhysicsBody2D body)
        {
            int index = CalculateBoundsIndex(body.transform);

            float x = (int)Math.Floor(body.transform.Position.X / PhysicsSettings.BOUNDINGBOX_LARGEST) * PhysicsSettings.BOUNDINGBOX_LARGEST;
            float z = (int)Math.Floor(body.transform.Position.Z / PhysicsSettings.BOUNDINGBOX_LARGEST) * PhysicsSettings.BOUNDINGBOX_LARGEST;

            if (bounds_hashtable.ContainsKey(index))
            {
                bounds_hashtable[index].AddBody(body);
            }
            else
            {
                bounds_transform          = new Transform();
                bounds_transform.Position = new Vector3(x, 0, z);

                bounds.Add(new PhysicsBoundingChunk2D(bounds_transform));
                bounds_hashtable.Add(index, bounds[bounds.Count - 1]);
                bounds[bounds.Count - 1].AddBody(body);
            }

            // If the body is so large that it takes up more than 1 chunk I need to know that, and build all the chunks it is in around the one at its center
            int       dimension    = 3;
            int       count        = 0;
            bool      tobig        = false;
            Transform newTransform = new Transform();

            while (!tobig)
            {
                for (int i_x = 0; i_x < dimension; ++i_x)
                {
                    for (int i_z = 0; i_z < dimension; ++i_z)
                    {
                        if (i_x == 0 || i_x == dimension - 1 || i_z == 0 || i_z == dimension - 1)
                        {
                            newTransform.Transformation = Matrix.Identity;
                            newTransform.Position       = new Vector3((i_x - (int)Math.Floor(dimension / 2.0f)) * PhysicsSettings.BOUNDINGBOX_LARGEST + x * PhysicsSettings.BOUNDINGBOX_LARGEST, 0, (i_z - (int)Math.Floor(dimension / 2.0f)) * PhysicsSettings.BOUNDINGBOX_LARGEST + z * PhysicsSettings.BOUNDINGBOX_LARGEST) - bounds_transform.Position;
                            int newIndex = CalculateBoundsIndex(newTransform);

                            if (bounds_hashtable.ContainsKey(newIndex))
                            {
                                if (bounds_hashtable[newIndex].BoundsTest(body))
                                {
                                    bounds_hashtable[newIndex].AddBody(body);
                                    count++;
                                }
                            }
                            else
                            {
                                PhysicsBoundingChunk2D newChunk = new PhysicsBoundingChunk2D(newTransform);
                                if (newChunk.BoundsTest(body))
                                {
                                    bounds.Add(newChunk);
                                    bounds_hashtable.Add(newIndex, newChunk);
                                    newChunk.AddBody(body);
                                    count++;
                                }
                            }
                        }
                    }
                }

                tobig = (count == 0) ? true : false;

                count      = 0;
                dimension += 2;
            }
        }