Extending the Clipping Method to deal with Circles
In the prior post we successfully completed the implementation of the clipping method to generate contact points between two colliding convex polygons.
In this post we look at how to extend the code so that it can also return contact points between a polygon and a circle (we will build on the circle class, polygon class and the SAT class from this post here).
Obtaining the Farthest Feature
Extending the code starts off by identifying whether the collision is a polygon vs polygon, polygon vs circle or circle vs circle.
Let us consider the following situation of a convex polygon (rectangle) colliding against a circle.
To start with the conclusion, in case of polygon vs circle collision, there is only one contact point - and that contact point is deemed to be the farthest point along the collision normal on the circumference of the circle.
In terms of implementation, remember from the previous post that the clipping method starts off by identifying the colliding features. In the case of polygon vs polygon collisions, the colliding features are both edges. We amend the piece of code that looks for the farthest features so that if either of the pair of objects is a circle, we take the returned colliding feature of the circle (ie the farthest point) as the contact point. This simple logic returns a robust contact point.
PointFeature
As the getFarthestFeature method for Polygon class returned an EdgeFeature object, we will create a PointFeature object for a circle, which will be the output of the circle equivalent of the getFarthestFeature method.
class PointFeature {
constructor(v) {
this.point = new Phaser.Math.Vector2(v.x, v.y);
}
}
getFarthestFeature method
getFarthestFeature( v) {
// obtain the farthest point along the given vector
var farthest = this.getFarthestPoint(v);
// for a circle the farthest feature along a vector will always be a vertex
return new PointFeature(farthest);
}
getFarthestPoint( vector) {
// make sure the axis is normalized
var nAxis = vector.clone().normalize();
// get the transformed center
var center = this.position.clone();
// add the radius along the vector to the center to get the farthest point
center.x += this.radius * nAxis.x;
center.y += this.radius * nAxis.y;
// return the new point
return center;
}
ClipingSolver
The only change needed to the ClippingSolver code since the last version is to amend the code identifying the colliding features at the beginning.
getContact(boxA, boxB, manifold) {
// get the penetration normal
var n = manifold.normal;
// get the reference feature for the first convex shape
var e1 = boxA.getFarthestFeature(n);
// check for vertex
if (e1 instanceof PointFeature) {
manifold.contacts.push(e1.point);
manifold.numContacts = manifold.contacts.length;
return true;
}
var ne = n.clone().negate()
// get the reference feature for the second convex shape
var e2 = boxB.getFarthestFeature(ne);
// check for vertex
if (e2 instanceof PointFeature) {
manifold.contacts.push(e2.point);
manifold.numContacts = manifold.contacts.length;
return true;
}
Comments