コード例 #1
0
    void EPAHandle(const Collider &collider_a, const Collider &collider_b,
        const Simplex &simplex, Contacts &contacts)
    {
        std::vector<Simplex::Vert> epa_simplex
            = { simplex.vertices[0], simplex.vertices[1], simplex.vertices[2] };

        // 100 is for security purposes, preventing an infinite loop
        for (int i = 0; i < 100; ++i)
        {
            // find the edge closest to the origin in the simplex
            SimplexEdge edge = EPAFindClosestEdge(epa_simplex);

            // find the furthest minkowski difference point in the direction of the normal
            Vector2 support, support_A, support_B;
            Support(collider_a, collider_b, edge.normal,
                support, support_A, support_B);

            // find the distance between the point and the edge
            float dist = Vector2::Dot(support, edge.normal);

            // if we've hit the border of the minkowski difference
            if (dist - edge.distance < 0.01f)
            {
                contacts.push_back(Contact());
                auto &contact = contacts.back();

                contact.normal = edge.normal;
                contact.pen_depth = dist;

                // For contact points
                // Find the repeating point, if there is no repeating point,
                // project onto the edge, and use the homogenous coords to find the contact point.

                Simplex::Vert &vert_0 = epa_simplex[edge.index_0],
                    &vert_1 = epa_simplex[edge.index_1];

                // if there are no repitions, we project the origin onto the edge
                // to find the contact point
                float t;

                // get the interval from the x coordinates
                if (vert_0.vert.x > 0 && vert_1.vert.x < 0 ||
                    vert_0.vert.x < 0 && vert_1.vert.x > 0)
                {
                    t = (-vert_0.vert.x) / (vert_1.vert.x - vert_0.vert.x);
                }
                // get the interval from the y coordinates
                else
                {
                    t = (-vert_0.vert.y) / (vert_1.vert.y - vert_0.vert.y);
                }

                contact.point = vert_0.parent_p0 + t * (vert_1.parent_p0 - vert_0.parent_p0);

                return;
            }
            else
            {
                // add the point inbetween the points where it was found
                epa_simplex.insert(epa_simplex.begin() + edge.index_1,
                { support_A, support_B, support });
            }
        }
    }
コード例 #2
0
    bool IsColliding(const Collider &collider_a, const Collider &collider_b, Contacts &contacts)
    {
        // quick check with the individual collider AABBs for a quick out
        if (!collider_a.aabb.Overlap(collider_b.aabb))
            return false;

        // our simplex for this collision test
        Simplex simplex;

        // Set initial search direction to the difference of centers
        Vector2 d = Vector2(1, -1);//Vector2(collider_b.root_trans.PositionWC() - collider_a.root_trans.PositionWC());

        // get the first minkowski difference point
        simplex.Add(Support(collider_a, collider_b, d));

        // negate the support point, giving us a vector in the direction of the origin
        d = -simplex.A().vert;

        int count = 0;
        // start looping
        while (count < 100)
        {
            // add a new point to the simplex because we haven't terminated yet
            simplex.Add(Support(collider_a, collider_b, d));

            // see if the simplex is on the correct side of the origin
            if (Vector2::OppositeDirection(simplex.A().vert, d))
            {
                // if the point added last was not past the origin in the direction of d
                // then the Minkowski Sum cannot possibly contain the origin since
                // the last point added is on the edge of the Minkowski Difference
                return false;
            }
            else
            {
                // oterwise we need to determine if the origin is in the current simplex
                // this function will set the next search direction for us if it fails.
                if (simplex.ContainsOrigin(d))
                {
                    // if it does then we know there is a collision

                    // handle the collision with the EPA algorithm
                    EPAHandle(collider_a, collider_b, simplex, contacts);

                    // find the incident edge.
                    if (contacts.size())
                    {
                        auto &it = contacts.back();
                        it.info.e.edge_a = collider_a.FindIndex(it.normal);
                        it.info.e.edge_b = collider_b.FindIndex(-it.normal);
                    }

                    return true;
                }
            }

            ++count;
        }

        return false;
    }