예제 #1
0
        public void Handle(ref Manifold manifold, Rigidbody.Rigidbody a, Rigidbody.Rigidbody b)
        {
            Circle A = (Circle)a.Shape;
            Circle B = (Circle)b.Shape;

            Vector2 normal = b.transform.position - a.transform.position;

            float distance = normal.magnitude;
            float radius   = A.Radius + B.Radius;

            if (distance >= radius)
            {
                manifold.ContactCount = 0;
                return;
            }

            manifold.ContactCount = 1;
            manifold.Contacts     = new Vector2[manifold.ContactCount];

            if (Mathf.Abs(distance) < Mathf.Epsilon)
            {
                manifold.Penetration = A.Radius;
                manifold.Normal      = new Vector2(1.0f, 0.0f);

                manifold.Contacts[0] = a.transform.position;
            }
            else
            {
                manifold.Penetration = radius - distance;
                manifold.Normal      = normal / distance;
                manifold.Contacts[0] = manifold.Normal * A.Radius + (Vector2)a.transform.position;
            }
        }
예제 #2
0
        public static void Remove(Rigidbody.Rigidbody collider)
        {
            Rigidbodies.Remove(collider);

            if (_isRunning && Rigidbodies.Count == 0)
            {
                End();
            }
        }
예제 #3
0
        public static void Add(Rigidbody.Rigidbody collider)
        {
            if (!_isRunning)
            {
                Init();
            }

            Rigidbodies.Add(collider);
        }
예제 #4
0
 public static void Handle(ref Manifold manifold, Rigidbody.Rigidbody a, Rigidbody.Rigidbody b)
 {
     for (int i = 0; i < CollisionHandlers.Length; i++)
     {
         if (CollisionHandlers[i].CanHandle(a.Shape, b.Shape))
         {
             CollisionHandlers[i].Handle(ref manifold, a, b);
             break;
         }
     }
 }
예제 #5
0
        private static void IntegrateForces(Rigidbody.Rigidbody rigidbody, float deltaTime)
        {
            if (Math.Abs(rigidbody.InverseMass) < Mathf.Epsilon)
            {
                return;
            }

            float dts = deltaTime * 0.5f;

            rigidbody.SetVelocity(rigidbody.Velocity + rigidbody.Force * (dts * rigidbody.InverseMass));
            rigidbody.SetVelocity(rigidbody.Velocity + rigidbody.GravityScale * Gravity * dts);
            rigidbody.SetAngularVelocity(rigidbody.AngularVelocity + rigidbody.Torque * rigidbody.InverseMass * dts);
        }
        public Manifold(ref Rigidbody.Rigidbody a, ref Rigidbody.Rigidbody b)
        {
            A = a;
            B = b;

            AverageRestitution = Mathf.Min(A.Restitution, B.Restitution);
            StaticFriction     = Mathf.Sqrt(Mathf.Pow(A.StaticFriction, 2) + Mathf.Pow(B.StaticFriction, 2));
            DynamicFriction    = Mathf.Sqrt(Mathf.Pow(A.DynamicFriction, 2) + Mathf.Pow(B.DynamicFriction, 2));

            Normal       = new Vector2();
            Penetration  = 0f;
            ContactCount = 0;

            Contacts = new Vector2[ContactCount];
        }
예제 #7
0
        private static void IntegrateVelocity(Rigidbody.Rigidbody rigidbody, float deltaTime)
        {
            if (Math.Abs(rigidbody.InverseMass) < Mathf.Epsilon)
            {
                return;
            }

            rigidbody.transform.position += (Vector3)rigidbody.Velocity * deltaTime;

            float orient = rigidbody.transform.eulerAngles.z * Mathf.Deg2Rad + rigidbody.AngularVelocity * deltaTime;

            rigidbody.transform.eulerAngles.WithZ(orient * Mathf.Rad2Deg);
            rigidbody.SetOrient(orient);

            IntegrateForces(rigidbody, deltaTime);
        }
        public void Handle(ref Manifold manifold, Rigidbody.Rigidbody a, Rigidbody.Rigidbody b)
        {
            if (a.Shape.GetType() == typeof(Circle) && b.Shape.GetType() == typeof(Polygon))
            {
                AbsoluteHandler(ref manifold, a, b);
            }
            else if (a.Shape.GetType() == typeof(Polygon) && b.Shape.GetType() == typeof(Circle))
            {
                AbsoluteHandler(ref manifold, b, a);

                if (manifold.ContactCount > 0)
                {
                    manifold.Normal = -manifold.Normal;
                }
            }
        }
예제 #9
0
        private static void Step()
        {
            Contacts.Clear();

            for (int i = 0; i < Rigidbodies.Count; ++i)
            {
                Rigidbody.Rigidbody a = Rigidbodies[i];
                for (int j = i + 1; j < Rigidbodies.Count; ++j)
                {
                    Rigidbody.Rigidbody b = Rigidbodies[j];

                    if (Math.Abs(a.InverseMass) < Mathf.Epsilon && Math.Abs(b.InverseMass) < Mathf.Epsilon)
                    {
                        continue;
                    }

                    Manifold manifold = new Manifold(ref a, ref b);
                    manifold.Solve();

                    if (manifold.ContactCount > 0)
                    {
                        Contacts.Add(manifold);
                    }
                }
            }

            for (int i = 0; i < Rigidbodies.Count; ++i)
            {
                IntegrateForces(Rigidbodies[i], DeltaTime);
            }

            for (int i = 0; i < Contacts.Count; ++i)
            {
                Contacts[i].Initialize();
            }

            for (int j = 0; j < Iterations; ++j)
            {
                for (int i = 0; i < Contacts.Count; ++i)
                {
                    Contacts[i].ApplyImpulse();
                }
            }

            for (int i = 0; i < Rigidbodies.Count; ++i)
            {
                IntegrateVelocity(Rigidbodies[i], DeltaTime);
            }

            for (int i = 0; i < Contacts.Count; ++i)
            {
                Contacts[i].PositionalCorrection();
            }

            for (int i = 0; i < Rigidbodies.Count; ++i)
            {
                Rigidbody.Rigidbody rigidbody = Rigidbodies[i];

                rigidbody.SetForce(Vector2.zero);
                rigidbody.SetTorque(0f);
            }

            for (int i = 0; i < Contacts.Count; i++)
            {
                if (!Array.Exists(_previousFrameContacts, item => item.Equals(Contacts[i])))
                {
                    Contacts[i].A.Shape.OnCollisionEnter?.Invoke(Contacts[i].B.Shape);
                    Contacts[i].B.Shape.OnCollisionEnter?.Invoke(Contacts[i].A.Shape);
                }
            }

            _previousFrameContacts = Contacts.ToArray();
        }
        private void AbsoluteHandler(ref Manifold manifold, Rigidbody.Rigidbody a, Rigidbody.Rigidbody b)
        {
            Circle  A = (Circle)a.Shape;
            Polygon B = (Polygon)b.Shape;

            manifold.ContactCount = 0;

            Vector2 center = B.Orientation.Transpose().Multiply(a.transform.position - b.transform.position);

            float separation = Mathf.NegativeInfinity;
            int   faceNormal = 0;

            for (int i = 0; i < B.VertexCount; ++i)
            {
                float s = Vector2.Dot(B.Normals[i], center - B.Vertices[i]);

                if (s > A.Radius)
                {
                    return;
                }

                if (s > separation)
                {
                    separation = s;
                    faceNormal = i;
                }
            }

            Vector2 v1 = B.Vertices[faceNormal];
            int     i2 = faceNormal + 1 < B.VertexCount? faceNormal + 1 : 0;
            Vector2 v2 = B.Vertices[i2];

            if (separation < Mathf.Epsilon)
            {
                manifold.ContactCount = 1;
                manifold.Normal       = -B.Orientation.Multiply(B.Normals[faceNormal]);
                manifold.Contacts     = new Vector2[manifold.ContactCount];
                manifold.Contacts[0]  = manifold.Normal * A.Radius + (Vector2)a.transform.position;
                manifold.Penetration  = A.Radius;
                return;
            }

            float dot1 = Vector2.Dot(center - v1, v2 - v1);
            float dot2 = Vector2.Dot(center - v2, v1 - v2);

            manifold.Penetration = A.Radius - separation;

            if (dot1 <= 0.0f)
            {
                if (Vector2.Distance(center, v1) > A.Radius)
                {
                    return;
                }

                manifold.ContactCount = 1;
                manifold.Normal       = B.Orientation.Multiply(v1 - center).normalized;
                manifold.Contacts     = new Vector2[manifold.ContactCount];
                manifold.Contacts[0]  = B.Orientation.Multiply(v1) + (Vector2)b.transform.position;
            }
            else if (dot2 <= 0.0f)
            {
                if (Vector2.Distance(center, v2) > A.Radius)
                {
                    return;
                }

                manifold.ContactCount = 1;
                manifold.Normal       = B.Orientation.Multiply(v2 - center).normalized;
                manifold.Contacts     = new Vector2[manifold.ContactCount];
                manifold.Contacts[0]  = B.Orientation.Multiply(v2) + (Vector2)b.transform.position;
            }
            else
            {
                Vector2 n = B.Normals[faceNormal];

                if (Vector2.Dot(center - v1, n) > A.Radius)
                {
                    return;
                }

                manifold.ContactCount = 1;
                manifold.Normal       = -B.Orientation.Multiply(n);
                manifold.Contacts     = new Vector2[manifold.ContactCount];
                manifold.Contacts[0]  = manifold.Normal * A.Radius + (Vector2)a.transform.position;
            }
        }