Part II - Circle Collision Detection
Circle-to-circle collision detection is a fundamental topic in computer graphics, game development, and physics simulations. Unlike the intricate math required for detecting collisions between irregular polygons or complex 3D shapes, circle-to-circle collision detection is refreshingly straightforward. It leverages the inherent symmetry of circles to provide an efficient and easy-to-implement solution.
In essence, if you have two circles, each defined by a center point and a radius, determining whether they collide is a matter of a simple geometric calculation. All you need to do is compare the distance between the two centers to the sum of their radii. If the distance is less than or equal to the sum of their radii, a collision is occurring. This ease of calculation makes circle-to-circle collision detection a popular choice in scenarios where quick and frequent collision checks are required.
\[\text{Collision} = \begin{cases} \text{True}, & \text{if } D := \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2} \leq r_1 + r_2, \\ \text{False}, & \text{otherwise}.\end{cases}\]
where \(\mathbf{c}_1 = \begin{bmatrix}x_1 & y_1 \end{bmatrix}^T\) and \(\mathbf{c}_2 = \begin{bmatrix}x_2 & y_2 \end{bmatrix}^T\) are the coordinates of the centers of each circle.
Upon detecting a collision between two circles, we separate them according to their overlap. To find the overlap distance \(P\) (see image above), subtract the distance between the circle centers from \(r_1 + r_2\). To determine the direction in which to move \(C_2\) away from \(C_1\), multiply \(P\) by the normalized vector \(\vec{C}_{12}\) and divide by 2. Use the other half of \(P\) to move \(C_1\) along \(-\vec{C}_{12}\).
In the following code example, I've implemented a method for detecting collisions between circles. It returns the normalized normal as well as the amount by how big the overlap is.
bool Collision2D::circleCollisionDetection(const Vector2f& center_a, const float radius_a, const Vector2f& center_b, const float radius_b, Vector2f& normal, float& depth)
{
normal = Vector2f::Zero();
depth = 0.f;
float diff_distance = Math2D::distance(center_a, center_b);
float sum_radii = radius_a + radius_b;
if (diff_distance >= sum_radii)
{
return false;
}
normal = center_b - center_a;
normal = Math2D::normalize(normal);
depth = sum_radii - diff_distance;
return true;
}
Circle Collision Detection
The two circles get separated in another method that belongs to the World2D class. This class is used to handle all the object and their physics. It's like the main script for the Physics2D library as the game.cpp file is the main file for the game logic.
void World2D::separateBodies(Rigidbody*& body_a, Rigidbody*& body_b, Vector2f& mtv)
{
if (body_a->is_static)
{
body_b->move(mtv);
} else if (body_b->is_static)
{
body_a->move(-mtv);
} else
{
body_a->move(-mtv / 2.f);
body_b->move(mtv / 2.f);
}
}
Separating Bodies
As you can see, inside this method I've added also two statements that check if one of the two bodies is static. In this case, you don't need to move the static object by the MTV (minimum translation vector, defined as \(\vec{v}_{mtv} = \vec{n} \cdot d_{depth}\)). Important to note, that this method is only responsible for removing the overlap between the two bodies (this method works for all kinds of bodies not only circles). We discuss the impulse calculation later in Part VI.
Conclusion
In today's discussion, we've delved into the mechanisms behind collision detection among circles and the methodologies for their subsequent separation upon collision. Looking ahead to Part III, we will explore the intricacies of the Separating Axis Theorem (SAT) as it pertains to collision detection. Specifically, we will extend the application of this theorem to include interactions between circles and polygons. This upcoming section will offer a comprehensive understanding of how SAT enhances the robustness and versatility of our collision detection system.