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 }); } } }
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; }