예제 #1
0
 public override void CalculateWSCollisionBody()
 {
     CollisionBodyWS = new FCollSphere()
     {
         Radius = CollisionBody.Radius, Center = CollisionBody.Center + (Vector2)transform.position
     };
 }
예제 #2
0
        protected override void UpdateCollisionBody_internal()
        {
            float radMod = Mathf.Max(transform.localScale.x, transform.localScale.y);

            CollisionBody = new FCollSphere()
            {
                Center = Offset, Radius = Radius * radMod
            };
        }
        public static bool IsCollidingSphere(FCollSphere a, FCollSphere b, out CollisionContact manifold)
        {
            bool flipRef = b.Center.x < a.Center.x || b.Center.y < a.Center.y;

            Vector2 rel = flipRef ? a.Center - b.Center : b.Center - a.Center;

            float dist = rel.sqrMagnitude;
            float rSum = a.Radius + b.Radius;

            if (dist > (rSum * rSum))
            {
                manifold = null;
                return(false);
            }

            float delta = rel.magnitude;

            manifold = new CollisionContact();

            if (delta == 0.0f)
            {
                manifold.Penetration   = a.Radius;
                manifold.Normal        = Vector2.up;
                manifold.ContactPoints = new Vector2[] { a.Center };
            }
            else
            {
                manifold.Penetration   = rSum - delta;
                manifold.Normal        = rel / delta;
                manifold.ContactPoints = new Vector2[] { flipRef?manifold.Normal *b.Radius + b.Center : manifold.Normal * a.Radius + a.Center };
            }

            manifold.BodyAInc = flipRef;

            if (flipRef)
            {
                manifold.EdgeNormalA = -manifold.Normal;
                manifold.EdgeNormalB = manifold.Normal;
            }
            else
            {
                manifold.EdgeNormalA = manifold.Normal;
                manifold.EdgeNormalB = -manifold.Normal;
            }

            return(true);
        }
        private static bool SphereSAT(FCollPoly p1, FCollSphere p2, out CollisionContact manifold)
        {
            FSATAxis[] axisPoly      = GetAxis_sat(ref p1.Vertices);
            FSATAxis   circleAxis    = GetCircleAxis_sat(p2.Center, ref p1.Vertices);
            FSATAxis   collisionAxis = axisPoly[0];
            float      penetration   = 100000f;

            manifold = null;

            for (int i = 0; i < axisPoly.Length; i++)
            {
                Vector2 proj1        = ProjOntoAxis_sat(axisPoly[i], ref p1.Vertices);
                float   circleCenter = Vector2.Dot(p2.Center, axisPoly[i].Axis);
                Vector2 proj2        = new Vector2(circleCenter - p2.Radius, circleCenter + p2.Radius);

                float overlap = 0f;

                if (!GetOverlapFromProjection_sat(proj1, proj2, out axisPoly[i].BodyA, out overlap))
                {
                    return(false);
                }
                else
                {
                    if (ContainsOtherProjection_sat(proj1, proj2) || ContainsOtherProjection_sat(proj2, proj1))
                    {
                        float mins = Mathf.Abs(proj1.x - proj2.x);
                        float maxs = Mathf.Abs(proj1.y - proj2.y);

                        if (mins < maxs)
                        {
                            overlap += mins;
                        }
                        else
                        {
                            overlap += maxs;
                        }
                    }

                    if (overlap < penetration)
                    {
                        collisionAxis = axisPoly[i];
                        penetration   = overlap;
                    }
                }
            }


            //Circle axis
            {
                Vector2 proj1        = ProjOntoAxis_sat(circleAxis, ref p1.Vertices);
                float   circleCenter = Vector2.Dot(p2.Center, circleAxis.Axis);
                Vector2 proj2        = new Vector2(circleCenter - p2.Radius, circleCenter + p2.Radius);

                float overlap = 0f;

                if (!GetOverlapFromProjection_sat(proj1, proj2, out circleAxis.BodyA, out overlap))
                {
                    return(false);
                }
                else
                {
                    if (ContainsOtherProjection_sat(proj1, proj2) || ContainsOtherProjection_sat(proj2, proj1))
                    {
                        float mins = Mathf.Abs(proj1.x - proj2.x);
                        float maxs = Mathf.Abs(proj1.y - proj2.y);

                        if (mins < maxs)
                        {
                            overlap += mins;
                        }
                        else
                        {
                            overlap += maxs;
                        }
                    }

                    if (overlap < penetration)
                    {
                        collisionAxis = circleAxis;
                        penetration   = overlap;
                    }
                }
            }

            //Debug.Log("Collision axis: " + collisionAxis.Axis);
            //Debug.Log("Penetration: " + penetration);

            manifold = new CollisionContact();

            FEdge eRef;

            if (!collisionAxis.BodyA)
            {
                collisionAxis.Axis *= -1.0f;
            }

            eRef = GetBestEdge_sat(ref p1.Vertices, collisionAxis.Axis);

            eRef.Normal = MeshUtils.CalcNormal(eRef.AV, eRef.BV);

            Vector2 vLeft     = p1.Vertices[CollMeshUtils.LeftIndex(eRef.AI, p1.Vertices.Length)];
            Vector2 vRight    = p1.Vertices[CollMeshUtils.RightIndex(eRef.BI, p1.Vertices.Length)];
            Vector2 normLeft  = MeshUtils.CalcNormalRaw(vLeft, eRef.AV);
            Vector2 normRight = MeshUtils.CalcNormalRaw(eRef.BV, vRight);
            Vector2 leftRel   = p2.Center - eRef.AV;
            Vector2 rightRel  = p2.Center - eRef.BV;

            if (Vector2.Dot(normLeft, leftRel) > 0f && Vector2.Dot(eRef.Normal, leftRel) > 0f)
            {
                manifold.Penetration   = penetration;
                manifold.Normal        = collisionAxis.Axis;
                manifold.ContactPoints = new Vector2[] { p2.Center - leftRel.normalized * p2.Radius };
            }
            else if (Vector2.Dot(normRight, rightRel) > 0f && Vector2.Dot(eRef.Normal, rightRel) > 0f)
            {
                manifold.Penetration   = penetration;
                manifold.Normal        = collisionAxis.Axis;
                manifold.ContactPoints = new Vector2[] { p2.Center - rightRel.normalized * p2.Radius };
            }
            else
            {
                manifold.Penetration   = penetration;
                manifold.Normal        = collisionAxis.Axis;
                manifold.ContactPoints = new Vector2[] { p2.Center - eRef.Normal * p2.Radius };
            }

            manifold.BodyAInc    = false;
            manifold.EdgeNormalA = eRef.Normal;
            manifold.EdgeNormalB = (p2.Center - manifold.ContactPoints[0]).normalized;

            return(true);
        }
 public static bool IsCollidingPoly(FCollPoly a, FCollSphere b, out CollisionContact manifold)
 {
     return(SphereSAT(a, b, out manifold));
 }