Esempio n. 1
0
        public static Collision  ConvexConvexIntersection(ConvexCollider a, ConvexCollider b)
        {
            Vector2 ret   = Vector2.zero;
            int     count = 0;

            for (int i = 0; i < a.len; i++)
            {
                Vector2 w = a.gameObject.transform.LocalToWorldPoint(a.points [i]);
                if (b.IsPointInCollider(w))
                {
                    ret += w;
                    count++;
                }
            }
            for (int i = 0; i < b.len; i++)
            {
                Vector2 w = b.gameObject.transform.LocalToWorldPoint(b.points [i]);
                if (a.IsPointInCollider(w))
                {
                    ret += w;
                    count++;
                }
            }
            if (count > 0)
            {
                Collision s = new Collision();
                s.point  = ret / count;
                s.normal = a.GetNormal(s.point);
                return(s);
            }
            return(null);
        }
Esempio n. 2
0
        public static Collision CircleConvexIntersection(CircleCollider a, ConvexCollider b, bool ImCircle = true)
        {
            Vector2 localPoint      = b.gameObject.transform.WorldToLocalPoint(a.gameObject.transform.position);
            Vector2 ret             = Vector2.zero;
            Vector2 nor             = Vector2.zero;
            int     count           = 0;
            float   area            = 0;
            float   realRadA        = a.gameObject.transform.LocalToWorldLength(a.radius);
            float   radALocalToB    = b.gameObject.transform.WorldToLocalLength(realRadA);
            float   sqrRadALocalToB = radALocalToB * radALocalToB;

            Vector2 a0        = localPoint - b.points [b.len - 1];
            float   proj0     = Vector2.Dot(a0, b.deltas[0]) / b.lengths [0];
            float   rej0      = Math.Abs(Vector2.Cross(a0, b.deltas [0]) / b.lengths [0]);
            float   rejection = 0;

            if (rej0 <= radALocalToB && 0 <= proj0 && proj0 <= b.lengths [0])
            {
                //ret += b.points [b.len - 1] + b.deltas [0] * MyMath.Clamp(proj0 / b.lengths [0], 0, 1);
                Vector2 vrej         = Vector2.Reject(a0, b.deltas [0]);
                float   vrejMag      = vrej.magnitude;
                float   worldVrejMag = b.gameObject.transform.LocalToWorldLength(vrejMag);
                float   darea        = (float)(Math.PI * (realRadA - worldVrejMag) * worldVrejMag * Math.Sqrt(1.0 - worldVrejMag * worldVrejMag / realRadA / realRadA));
                nor      += Vector2.Rotate(b.deltas[0].normalized, MyMath.FloatPIPer2) * darea;
                ret      += (localPoint - vrej) * darea;
                area     += darea;
                rejection = Math.Max(rejection, realRadA - worldVrejMag);
                count++;
            }
            else if (Vector2.SqrDistance(b.points [0], localPoint) <= sqrRadALocalToB)
            {
                count++;
                float y = radALocalToB - Vector2.Distance(b.points [0], localPoint);

                Vector2 delta      = b.points [0] - localPoint;
                Vector2 proji      = Vector2.Project(b.deltas [0], delta);
                Vector2 projiPlus1 = Vector2.Project(b.deltas [1], delta);
                Vector2 reji       = b.deltas [0] - proji;
                Vector2 rejiPlus1  = b.deltas [1] - projiPlus1;

                float darea = 0.5f * y * y * (reji.magnitude / proji.magnitude + rejiPlus1.magnitude / projiPlus1.magnitude);

                rejection = Math.Max(rejection, realRadA - b.gameObject.transform.LocalToWorldLength(delta.magnitude));
                ret      += b.points [1] * darea;
                nor      += (Vector2.Reject(a0, b.deltas [1]) + Vector2.Reject(localPoint - b.points [0], b.deltas [1])).normalized * darea;
                area     += darea;
            }



            for (int i = 1; i < b.len - 1; i++)
            {
                Vector2 ai   = localPoint - b.points [i - 1];
                float   proj = Vector2.Dot(ai, b.deltas [i]) / b.lengths [i];
                float   rej  = Math.Abs(Vector2.Cross(ai, b.deltas [i]) / b.lengths [i]);

                if (rej <= radALocalToB && 0 <= proj && proj <= b.lengths [i])
                {
                    Vector2 vrej         = Vector2.Reject(ai, b.deltas [i]);
                    float   vrejMag      = vrej.magnitude;
                    float   worldVrejMag = b.gameObject.transform.LocalToWorldLength(vrejMag);
                    float   darea        = (float)(Math.PI * (realRadA - worldVrejMag) * worldVrejMag * Math.Sqrt(1.0 - worldVrejMag * worldVrejMag / realRadA / realRadA));
                    nor      += Vector2.Rotate(b.deltas [i].normalized, MyMath.FloatPIPer2) * darea;
                    ret      += (localPoint - vrej) * darea;
                    area     += darea;
                    rejection = Math.Max(rejection, realRadA - worldVrejMag);
                    count++;
                }
                else if (Vector2.SqrDistance(b.points [i], localPoint) <= sqrRadALocalToB)
                {
                    count++;
                    float y = radALocalToB - Vector2.Distance(b.points [i], localPoint);

                    Vector2 delta      = b.points [i] - localPoint;
                    Vector2 proji      = Vector2.Project(b.deltas [i], delta);
                    Vector2 projiPlus1 = Vector2.Project(b.deltas [i + 1], delta);
                    Vector2 reji       = b.deltas [i] - proji;
                    Vector2 rejiPlus1  = b.deltas [i + 1] - projiPlus1;

                    float darea = 0.5f * y * y * (reji.magnitude / proji.magnitude + rejiPlus1.magnitude / projiPlus1.magnitude);

                    rejection = Math.Max(rejection, realRadA - b.gameObject.transform.LocalToWorldLength(delta.magnitude));
                    ret      += b.points [i] * darea;
                    nor      += (Vector2.Reject(ai, b.deltas [i]) + Vector2.Reject(localPoint - b.points [i], b.deltas [i + 1])).normalized * darea;
                    area     += darea;
                }
            }

            int     last  = b.len - 1;
            Vector2 al    = localPoint - b.points [last - 1];
            float   projl = Vector2.Dot(al, b.deltas[last]) / b.lengths [last];
            float   rejl  = Math.Abs(Vector2.Cross(al, b.deltas [last]) / b.lengths [last]);

            if (rejl <= radALocalToB && 0 <= projl && projl <= b.lengths [last])
            {
                Vector2 vrej         = Vector2.Reject(al, b.deltas [last]);
                float   vrejMag      = vrej.magnitude;
                float   worldVrejMag = b.gameObject.transform.LocalToWorldLength(vrejMag);
                float   darea        = (float)(Math.PI * (realRadA - worldVrejMag) * worldVrejMag * Math.Sqrt(1.0 - worldVrejMag * worldVrejMag / realRadA / realRadA));
                nor      += Vector2.Rotate(b.deltas[last].normalized, MyMath.FloatPIPer2) * darea;
                ret      += (localPoint - vrej) * darea;
                area     += darea;
                rejection = Math.Max(rejection, realRadA - worldVrejMag);
                count++;
            }
            else if (Vector2.SqrDistance(b.points [last], localPoint) <= sqrRadALocalToB)
            {
                count++;
                float y = radALocalToB - Vector2.Distance(b.points [last], localPoint);

                Vector2 delta      = b.points [last] - localPoint;
                Vector2 proji      = Vector2.Project(b.deltas [last], delta);
                Vector2 projiPlus1 = Vector2.Project(b.deltas [0], delta);
                Vector2 reji       = b.deltas [last] - proji;
                Vector2 rejiPlus1  = b.deltas [0] - projiPlus1;

                float darea = 0.5f * y * y * (reji.magnitude / proji.magnitude + rejiPlus1.magnitude / projiPlus1.magnitude);


                rejection = Math.Max(rejection, realRadA - b.gameObject.transform.LocalToWorldLength(delta.magnitude));
                ret      += b.points [last] * darea;
                //nor += (Vector2.Reject (al, b.deltas [last]) + Vector2.Reject (localPoint - b.points [last], b.deltas [0])).normalized * darea;
                //nor +=
                area += darea;
            }

            bool inCol = b.IsPointInCollider(a.gameObject.transform.position);

            if (count > 0 || (inCol && b.isTrigger && b.hacked))
            {
                if (inCol)
                {
                    area = a.area - area;
                }


                if (area <= 0)
                {
                    area = MyMath.dFloat;
                }
                Collision s = new Collision();
                s.point  = b.gameObject.transform.LocalToWorldPoint(ret / area);
                s.normal = (ImCircle ? -1 : 1) * a.GetNormal(s.point);
                //s.normal = (ImCircle ? -1 : 1) * b.gameObject.transform.LocalToWorldDirection(nor / area).normalized;

                if (!ImCircle)
                {
                    s.normal *= -1;
                }

                //Console.WriteLine ("normal " + s.normal);
                s.area      = area;
                s.collider  = ImCircle ? (Collider)b : (Collider)a;
                s.rejection = rejection;
                //Console.WriteLine ("Collide " + MainWindow.frameCount);
                //Console.WriteLine ("normal " + s.normal);
                return(s);
            }
            return(null);
        }