Exemplo n.º 1
0
    //TODO make multi-path colliders work......
    /// <summary>
    /// Generates the fine details between two known-colliding Collider2D objects.
    /// One collider will be a CircleCollider2D and the other will be a PolygonCollider2D that belongs to a JelloBody.
    /// </summary>
    /// <param name="collA">The CircleCollider2D involved in the collision.</param>
    /// <param name="info">The SupplementartyColliderInfo representing the PolygonCollider2D that belongs to a JelloBody involved in the collision.</param>
    /// <param name="contacts">The JelloContact list to add any generated JelloContact to.</param>
    public void BodyCollide(CircleCollider2D collA, SupplementaryColliderInfo info, ref List<JelloContact> contacts)
    {
        JelloContact contact;
        Vector2 pt;
        Vector2 hitPt;
        Vector2 norm;
        float scalarAB;
        float dist;
        float radius;

        //contact = new JelloContact();
        radius = collA.radius * Mathf.Max(collA.transform.localScale.x, collA.transform.localScale.y);

        pt = (Vector2)collA.transform.TransformPoint(collA.center);

        //for each pointmass in body B
        for (int j = 0; j < info.ColliderVertices.Length - 2; j++)
        {
            //get collision info
            dist = JelloVectorTools.getClosestPointOnSegmentSquared(pt, info.ColliderVertices[j + 1], info.ColliderVertices[j + 2], out hitPt, out norm, out scalarAB); //TODO make this work with fully penetrated circles.
            //fill out collisioninfo
            if(dist < radius * radius)
            {
                contact = new JelloContact();

                contact.bodyA = null;
                contact.colliderA = collA;
                contact.rigidbodyA = collA.rigidbody2D;
                contact.transformA = collA.transform;
                contact.bodyB = info.body;
                contact.colliderB = info.collider;
                contact.rigidbodyB = info.collider.rigidbody2D;
                contact.transformB = info.collider.transform;
                contact.bodyBpmA = j;
                contact.bodyBpmB = j + 1 > info.ColliderVertices.Length - 3 ? 0 : j + 1;
                contact.scalarAB = scalarAB;
                contact.hitPoint = hitPt;
                contact.normal = (hitPt - pt).normalized * (JelloShapeTools.Contains(info.ColliderVertices, pt) ? 1f : -1f);
                contact.mtv = contact.normal;
                contact.penetration = radius - Mathf.Sqrt(dist);
                contact.R = contact.hitPoint - (Vector2)collA.transform.position;
                contact.R2 = contact.hitPoint - (Vector2)info.collider.transform.position;

                contacts.Add(contact);
            }
        }
    }
Exemplo n.º 2
0
    //public void BodyCollide(PolygonCollider2D collA, EdgeCollider2D collB, ref List<JelloContact> contacts){}
    //public void BodyCollide(EdgeCollider2D collA, PolygonCollider2D collB, ref List<JelloContact> contacts){}
    public void BodyCollide(SupplementaryColliderInfo infoA, SupplementaryColliderInfo infoB, ref List<JelloContact> contacts)
    {
        List<JelloContact> closestLineContacts = new List<JelloContact>();

        //find each point of the colliders that are penetrating each other.
        FindPenetratingPoints(infoA, infoB, ref contacts);

        //find each contact that satisfies the parametric contact method
        FindParametricContactDetails(infoA, infoB, ref contacts);

        //decide the detection method for each contact, parametric, closest line, or hybrid
        FinalizeContactTypes(infoA, infoB, ref contacts, ref closestLineContacts);

        //get details (using the closest line method) for each contact that does not satisfy the parametric or hybrid detection methods.
        FindClosestLineContactDetails(infoA, infoB, ref contacts, ref closestLineContacts);
    }
Exemplo n.º 3
0
    private void FindPenetratingPoints(SupplementaryColliderInfo infoA, SupplementaryColliderInfo infoB, ref List<JelloContact> contacts)
    {
        //TODO i have an idea of how to optimise this a bit maybe.
        //have separate lists for each body and iterate better over each of them...

        //loop through both bodies at the same time, identifying penetrating points
        for (int i = 0; i < Mathf.Max ( infoA.ColliderVertices.Length - 2, infoB.ColliderVertices.Length - 2); i++)
        {
            //check for potential collisions in both bodies
            if(i < infoA.ColliderVertices.Length - 2)
            {
                //only consider this point if it is insdie the other body's AABB and inside the other body.
                if(infoB.AABB.contains(infoA.ColliderVertices[i + 1]) && JelloShapeTools.Contains(infoB.ColliderVertices, infoA.ColliderVertices[i + 1]))
                {
                    contacts.Add (new JelloContact());
                    contacts[contacts.Count - 1].penetration = Mathf.Infinity;
                    contacts[contacts.Count - 1].toi = Mathf.Infinity;
                    contacts[contacts.Count - 1].bodyApm = i;
                    contacts[contacts.Count - 1].bodyA = infoA.body;
                    contacts[contacts.Count - 1].colliderA = infoA.collider;
                    contacts[contacts.Count - 1].rigidbodyA = infoA.rigidbody;
                    contacts[contacts.Count - 1].transformA = infoA.transform;
                    contacts[contacts.Count - 1].bodyB = infoB.body;
                    contacts[contacts.Count - 1].colliderB = infoB.collider;
                    contacts[contacts.Count - 1].rigidbodyB = infoB.rigidbody;
                    contacts[contacts.Count - 1].transformB = infoB.transform;
                }
            }
            if(i < infoB.ColliderVertices.Length - 2)
            {
                //only consider this point if it is insdie the other body's AABB and inside the other body.
                if(infoA.AABB.contains(infoB.ColliderVertices[i + 1]) && JelloShapeTools.Contains(infoA.ColliderVertices, infoB.ColliderVertices[i + 1]))
                {
                    contacts.Add (new JelloContact());
                    contacts[contacts.Count - 1].penetration = Mathf.Infinity;
                    contacts[contacts.Count - 1].toi = Mathf.Infinity;
                    contacts[contacts.Count - 1].bodyApm = i;
                    contacts[contacts.Count - 1].bodyA = infoB.body;
                    contacts[contacts.Count - 1].colliderA = infoB.collider;
                    contacts[contacts.Count - 1].rigidbodyA = infoB.rigidbody;
                    contacts[contacts.Count - 1].transformA = infoB.transform;
                    contacts[contacts.Count - 1].bodyB = infoA.body;
                    contacts[contacts.Count - 1].colliderB = infoA.collider;
                    contacts[contacts.Count - 1].rigidbodyB = infoA.rigidbody;
                    contacts[contacts.Count - 1].transformB = infoA.transform;
                }
            }
        }
    }
Exemplo n.º 4
0
    private void FindParametricContactDetails(SupplementaryColliderInfo infoA, SupplementaryColliderInfo infoB, ref List<JelloContact> contacts)
    {
        Vector2 A, B, prevA, prevB, vA, vB;

        //after looping through each point and checking for potential collisions, loop through one more time and get fine detail collision.
        for (int i = 0; i < Mathf.Max (infoA.ColliderVertices.Length - 2, infoB.ColliderVertices.Length - 2); i++)
        {
            //handle the first collider
            if(i < infoA.ColliderVertices.Length - 2)
            {
                //get the information for the infoa edge
                A = infoA.ColliderVertices[i + 1];
                B = infoA.ColliderVertices[i + 2];
                prevA = infoA.PrevColliderVertices[i + 1];
                prevB = infoA.PrevColliderVertices[i + 2];
                vA = A - prevA;
                vB = B - prevB;

                //test collision for each infoB contact against the infoa edge
                for(int a = 0; a < contacts.Count; a++)
                {
                    if(contacts[a].colliderA == infoA.collider) //this is where it could be beneficial to have separate lists, its not a big check, but it would also save on an iteration...
                        continue;

                    ParametricContactTest
                        (
                            A,
                            B,
                            infoB.ColliderVertices[contacts[a].bodyApm + 1],
                            prevA,
                            prevB,
                            infoB.PrevColliderVertices[contacts[a].bodyApm + 1],
                            vA - (infoB.ColliderVertices[contacts[a].bodyApm + 1] - infoB.PrevColliderVertices[contacts[a].bodyApm + 1]),
                            vB - (infoB.ColliderVertices[contacts[a].bodyApm + 1] - infoB.PrevColliderVertices[contacts[a].bodyApm + 1]),
                            i,
                            contacts[a]
                        );
                }
            }

            //handle the second collider
            if(i < infoB.ColliderVertices.Length - 2)
            {
                A = infoB.ColliderVertices[i + 1];
                B = infoB.ColliderVertices[i + 2];
                prevA = infoB.PrevColliderVertices[i + 1];
                prevB = infoB.PrevColliderVertices[i + 2];
                vA = A - prevA;
                vB = B - prevB;

                for(int a = 0; a < contacts.Count; a++)
                {
                    if(contacts[a].colliderA == infoB.collider)
                        continue;

                    ParametricContactTest
                        (
                            A,
                            B,
                            infoA.ColliderVertices[contacts[a].bodyApm + 1],
                            prevA,
                            prevB,
                            infoA.PrevColliderVertices[contacts[a].bodyApm + 1],
                            vA - (infoA.ColliderVertices[contacts[a].bodyApm + 1] - infoA.PrevColliderVertices[contacts[a].bodyApm + 1]),
                            vB - (infoA.ColliderVertices[contacts[a].bodyApm + 1] - infoA.PrevColliderVertices[contacts[a].bodyApm + 1]),
                            i,
                            contacts[a]
                        );
                }
            }
        }
    }
Exemplo n.º 5
0
    private void FindClosestLineContactDetails(SupplementaryColliderInfo infoA, SupplementaryColliderInfo infoB, ref List<JelloContact> contacts, ref List<JelloContact> closestLineContacts)
    {
        Vector2 A, B, edgeNormal;

        for (int i = 0; i < Mathf.Max (infoA.ColliderVertices.Length - 2, infoB.ColliderVertices.Length - 2); i++)
        {
            if(i < infoA.ColliderVertices.Length - 2)
            {
                A = infoA.ColliderVertices[i + 1];
                B = infoA.ColliderVertices[i + 2];

                //edge normal
                edgeNormal = infoA.EdgeNormals[i];

                for(int a = 0; a < closestLineContacts.Count; a+=2)
                {
                    if(closestLineContacts[a].colliderA == infoA.collider)
                        continue;

                    ClosestLineContactTest
                        (
                            A,
                            B,
                            infoB.ColliderVertices[closestLineContacts[a].bodyApm + 1],
                            i,
                            edgeNormal,
                            infoB.PointNormals[closestLineContacts[a].bodyApm],
                            infoA.InverseSquaredEdgeLengths[i],
                            closestLineContacts[a],
                            closestLineContacts[a + 1]
                        );
                }
            }

            if(i < infoB.ColliderVertices.Length - 2)
            {
                A = infoB.ColliderVertices[i + 1];
                B = infoB.ColliderVertices[i + 2];

                // normal
                edgeNormal = infoB.EdgeNormals[i];

                for(int a = 0; a < closestLineContacts.Count; a+=2)
                {
                    if(closestLineContacts[a].colliderA == infoB.collider)
                        continue;

                    ClosestLineContactTest
                        (
                            A,
                            B,
                            infoA.ColliderVertices[closestLineContacts[a].bodyApm + 1],
                            i,
                            edgeNormal,
                            infoA.PointNormals[closestLineContacts[a].bodyApm],
                            infoB.InverseSquaredEdgeLengths[i],
                            closestLineContacts[a],
                            closestLineContacts[a + 1]
                        );
                }
            }
        }

        //TODO place the following code into another method?
        for(int i = 0; i < closestLineContacts.Count; i++)
        {
            if (closestLineContacts[i].penetration > PenetrationThreshold && closestLineContacts[i + 1].penetration < closestLineContacts[i].penetration && closestLineContacts[i + 1].penetration != Mathf.Infinity)
            {
                closestLineContacts[i + 1].penetration = Mathf.Sqrt(closestLineContacts[i + 1].penetration);

                float eLength;
                if(closestLineContacts[i + 1].colliderA == infoA.collider)
                {
                    eLength = Vector2.Distance(infoB.ColliderVertices[closestLineContacts[i + 1].bodyBpmA + 1], infoB.ColliderVertices[closestLineContacts[i + 1].bodyBpmB + 1]);

                    if(closestLineContacts[i + 1].bodyBpmB == infoB.ColliderVertices.Length - 2)
                        closestLineContacts[i + 1].bodyBpmB = 0;
                }
                else
                {
                    eLength = Vector2.Distance(infoA.ColliderVertices[closestLineContacts[i + 1].bodyBpmA + 1], infoA.ColliderVertices[closestLineContacts[i + 1].bodyBpmB + 1]);

                    if(closestLineContacts[i + 1].bodyBpmB == infoA.ColliderVertices.Length - 2)
                        closestLineContacts[i + 1].bodyBpmB = 0;
                }

                if(eLength != 0)
                    eLength = 1 / eLength;
                closestLineContacts[i + 1].normal *= eLength;
                closestLineContacts[i + 1].mtv = closestLineContacts[i + 1].normal;

                closestLineContacts[i + 1].R = closestLineContacts[i + 1].hitPoint - (Vector2)closestLineContacts[i + 1].transformA.position;
                closestLineContacts[i + 1].R2 = closestLineContacts[i + 1].hitPoint - (Vector2)closestLineContacts[i + 1].transformB.position;

                closestLineContacts.Remove(closestLineContacts[i]);
            }
            else if(closestLineContacts[i].penetration != Mathf.Infinity)
            {
                closestLineContacts[i].penetration = Mathf.Sqrt(closestLineContacts[i].penetration);

                float eLength;
                if(closestLineContacts[i].colliderA == infoA.collider)
                {
                    eLength = Vector2.Distance(infoB.ColliderVertices[closestLineContacts[i].bodyBpmA + 1], infoB.ColliderVertices[closestLineContacts[i].bodyBpmB + 1]);

                    if(closestLineContacts[i].bodyBpmB >= infoB.ColliderVertices.Length - 2)
                        closestLineContacts[i].bodyBpmB = 0;
                }
                else
                {
                    eLength = Vector2.Distance(infoA.ColliderVertices[closestLineContacts[i].bodyBpmA + 1], infoA.ColliderVertices[closestLineContacts[i].bodyBpmB + 1]);

                    if(closestLineContacts[i].bodyBpmB >= infoA.ColliderVertices.Length - 2)
                        closestLineContacts[i].bodyBpmB = 0;
                }

                if(eLength != 0)
                    eLength = 1 / eLength;
                closestLineContacts[i].normal *= eLength;
                closestLineContacts[i].mtv = closestLineContacts[i].normal;

                closestLineContacts[i].R = closestLineContacts[i].hitPoint - (Vector2)closestLineContacts[i].transformA.position;
                closestLineContacts[i].R2 = closestLineContacts[i].hitPoint - (Vector2)closestLineContacts[i].transformB.position;

                closestLineContacts.Remove(closestLineContacts[i + 1]);
            }
            else
            {
                closestLineContacts.Remove(closestLineContacts[i]);
                closestLineContacts.Remove(closestLineContacts[i]);
                i-=1;
            }
        }

        //now place the closet line contacs back into the original contacts list.
        for(int i = 0; i < closestLineContacts.Count; i++)
        {
            contacts.Add(closestLineContacts[i]);
        }
    }
Exemplo n.º 6
0
    private void FinalizeContactTypes(SupplementaryColliderInfo infoA, SupplementaryColliderInfo infoB, ref List<JelloContact> contacts, ref List<JelloContact> closestLineContacts)
    {
        //loop through each contact and fill out the rest of the details.
        for(int i = contacts.Count - 1; i >= 0; i--)
        {
            //if the time of impact is infinity then this contact point fialed the parametric contact tests and the closest line method will need to be used instead.
            if(contacts[i].toi == Mathf.Infinity)
            {
                //add two copies of this conact to the closest line contact list.

                //representative of closestSame
                closestLineContacts.Add (contacts[i]);
                closestLineContacts[closestLineContacts.Count - 1].penetration = Mathf.Infinity;

                //representative of closestAway
                closestLineContacts.Add(new JelloContact());
                closestLineContacts[closestLineContacts.Count - 1].penetration = Mathf.Infinity;
                closestLineContacts[closestLineContacts.Count - 1].bodyA = contacts[i].bodyA;
                closestLineContacts[closestLineContacts.Count - 1].bodyB = contacts[i].bodyB;
                closestLineContacts[closestLineContacts.Count - 1].bodyApm = contacts[i].bodyApm;
                closestLineContacts[closestLineContacts.Count - 1].colliderA = contacts[i].colliderA;
                closestLineContacts[closestLineContacts.Count - 1].colliderB = contacts[i].colliderB;
                closestLineContacts[closestLineContacts.Count - 1].rigidbodyA = contacts[i].rigidbodyA;
                closestLineContacts[closestLineContacts.Count - 1].rigidbodyB = contacts[i].rigidbodyB;
                closestLineContacts[closestLineContacts.Count - 1].transformA = contacts[i].transformA;
                closestLineContacts[closestLineContacts.Count - 1].transformB = contacts[i].transformB;

                //remove this contact from the contacts list.
                //one of the two above will be returned to this list later at the end of this.
                contacts.RemoveAt(i);
                continue;
            }

            if(contacts[i].colliderA == infoA.collider)
            {

                //assign the normal
                contacts[i].normal = infoB.EdgeNormals[contacts[i].bodyBpmA];

                //test hybrid
                HybridContactTest
                    (
                        infoB.ColliderVertices[contacts[i].bodyBpmA + 1],
                        infoB.ColliderVertices[contacts[i].bodyBpmB + 1],
                        infoA.ColliderVertices[contacts[i].bodyApm + 1],
                        infoB.InverseSquaredEdgeLengths[contacts[i].bodyBpmA],
                        contacts[i]
                    );

                if(contacts[i].bodyBpmB >= infoB.ColliderVertices.Length - 2)
                    contacts[i].bodyBpmB = 0;
            }
            else
            {

                //assign the normal
                contacts[i].normal = infoA.EdgeNormals[contacts[i].bodyBpmA];

                //test hybrid
                HybridContactTest
                    (
                        infoA.ColliderVertices[contacts[i].bodyBpmA + 1],
                        infoA.ColliderVertices[contacts[i].bodyBpmB + 1],
                        infoB.ColliderVertices[contacts[i].bodyApm + 1],
                        infoA.InverseSquaredEdgeLengths[contacts[i].bodyBpmA],
                        contacts[i]
                    );

                if(contacts[i].bodyBpmB >= infoA.ColliderVertices.Length - 2)
                    contacts[i].bodyBpmB = 0;
            }

            contacts[i].R = contacts[i].hitPoint - (Vector2)contacts[i].transformA.position;
            contacts[i].R2 = contacts[i].hitPoint - (Vector2)contacts[i].transformB.position;
        }
    }
Exemplo n.º 7
0
    /// <summary>
    /// Start tracking the Collider2D.
    /// Adds it to the JelloWorld.trackedColliders list and JelloWorld.TrackedColliderDictionary.
    /// </summary>
    /// <param name="collider">The Collider2D to start tracking.</param>
    /// <param name="colliderInfo">The SupplementaryColliderInfo that describes the now tracked Collider2D.</param>
    /// <param name="jelloBody">The JelloBody, if any, the Collider2D belongs to.</param>
    /// <returns>Whether the collider is already being tracked. True if already being tracked, false if not.</returns>
    public bool StartTrackingCollider(Collider2D collider, out SupplementaryColliderInfo colliderInfo, JelloBody jelloBody = null)
    {
        if(trackedColliders.Contains(collider))
        {
            colliderInfo = World.TrackedColliderDictionary[collider.GetInstanceID()];
            return true;
        }

        trackedColliders.Add (collider);
        colliderInfo = new SupplementaryColliderInfo(collider, jelloBody);
        TrackedColliderDictionary.Add (collider.GetInstanceID(), colliderInfo);
        return false;
    }