예제 #1
0
        public CollisionResult SolveCollision(CollisionBody colA, CollisionBody colB)
        {
            // normalize parameters such that colA is the circle and colB is the box.
            // there are only two possibilities, therefore we only need to swap if colB is the circle.
            if (colB.Shape is Circle)
            {
                CollisionBody tmp = colA;
                colA = colB;
                colB = tmp;
                tmp  = null;
            }

            Circle  circleA    = (Circle)colA.Shape;
            Box     boxB       = (Box)colB.Shape;
            Matrix3 transformB = colB.WorldTransform;

            float   projectedDistance = 0;
            float   minPenetration    = float.MaxValue;
            Vector2 distance          = colA.Position - colB.Position;
            Vector2 mtv = default(Vector2); // the minimum translation vector

            Vector2[] axisToCheck = new Vector2[3];
            boxB.CalculateOrientation(ref transformB, out axisToCheck[0]);
            axisToCheck[1] = Vector2Extensions.PerpendicularLeft(axisToCheck[0]);
            float   minDistance   = float.MaxValue;
            Vector2 closestVertex = default(Vector2);

            for (int i = 0; i < boxB.Vertices.Length; i++)
            {
                float vertexDistance = Vector2.DistanceSquared(colA.Position, boxB.Vertices[i]);
                if (vertexDistance < minDistance)
                {
                    minDistance   = vertexDistance;
                    closestVertex = colB.Position - boxB.Vertices[i];
                }
            }
            axisToCheck[2] = closestVertex;
            Vector2Extensions.SafeNormalize(ref axisToCheck[2]);

            for (int i = 0; i < axisToCheck.Length; i++)
            {
                Vector2 projectionA, projectionB;

                projectedDistance = Math.Abs(Vector2.Dot(distance, axisToCheck[i]));
                circleA.ProjectOnto(ref axisToCheck[i], out projectionA);
                boxB.ProjectOnto(ref transformB, ref axisToCheck[i], out projectionB);

                float aSize       = projectionA.Length(); //Math.Abs(projectionA.X) + Math.Abs(projectionA.Y);
                float bSize       = Math.Abs(projectionB.X) + Math.Abs(projectionB.Y);
                float abSize      = aSize + bSize;
                float penetration = abSize - projectedDistance;

                // a seperating axis found; there is no collision.
                if (penetration <= 0)
                {
                    return(CollisionResult.NoCollision);
                }
                // project the object along the axis with the smalled penetration depth.
                else if (Math.Abs(penetration) < Math.Abs(minPenetration))
                {
                    minPenetration = penetration;
                    mtv            = axisToCheck[i];
                }
            }
            // the distance vector determines the direction of movement. the distance and mtv
            // should always oppose each other to repel collisions.
            if (Vector2.Dot(distance, mtv) < 0f)
            {
                mtv = -mtv;
            }
            // seperating axis could not be found; a collision occurs.
            return(new CollisionResult()
            {
                Us = colA,
                Them = colB,
                CollisionResponse = minPenetration * mtv,
                IsColliding = true
            });
        }
예제 #2
0
파일: Circle.cs 프로젝트: W3SS/delta
 public void CalculateExtents(ref Matrix3 transform, out Vector2 extents)
 {
     extents = new Vector2(Radius, 0);
     transform.TransformVector(ref extents);
 }