So, after hours of Googling and reading, I've found that the basic process of detecting a collision using SAT is:
for each edge of poly A
project A and B onto the normal for this edge
if intervals do not overlap, return false
end for
for each edge of poly B
project A and B onto the normal for this edge
if intervals do not overlap, return false
end for
However, as many ways as I try to implement this in code, I just cannot get it to detect the collision. My current code is as follows:
for (unsigned int i = 0; i < asteroids.size(); i++) {
if (asteroids.valid(i)) {
asteroids[i]->Update();
// Player-Asteroid collision detection
bool collision = true;
SDL_Rect asteroidBox = asteroids[i]->boundingBox;
// Bullet-Asteroid collision detection
for (unsigned int j = 0; j < player.bullets.size(); j++) {
if (player.bullets.valid(j)) {
Bullet b = player.bullets[j];
collision = true;
if (b.x + (b.w / 2.0f) < asteroidBox.x - (asteroidBox.w / 2.0f)) collision = false;
if (b.x - (b.w / 2.0f) > asteroidBox.x + (asteroidBox.w / 2.0f)) collision = false;
if (b.y - (b.h / 2.0f) > asteroidBox.y + (asteroidBox.h / 2.0f)) collision = false;
if (b.y + (b.h / 2.0f) < asteroidBox.y - (asteroidBox.h / 2.0f)) collision = false;
if (collision) {
bool realCollision = false;
float min1, max1, min2, max2;
// Create a list of vertices for the bullet
CrissCross::Data::LList<Vector2D *> bullVerts;
bullVerts.insert(new Vector2D(b.x - b.w / 2.0f, b.y + b.h / 2.0f));
bullVerts.insert(new Vector2D(b.x - b.w / 2.0f, b.y - b.h / 2.0f));
bullVerts.insert(new Vector2D(b.x + b.w / 2.0f, b.y - b.h / 2.0f));
bullVerts.insert(new Vector2D(b.x + b.w / 2.0f, b.y + b.h / 2.0f));
// Create a list of vectors of the edges of the bullet and the asteroid
CrissCross::Data::LList<Vector2D *> bullEdges;
CrissCross::Data::LList<Vector2D *> asteroidEdges;
for (int k = 0; k < 4; k++) {
int n = (k == 3) ? 0 : k + 1;
bullEdges.insert(new Vector2D(bullVerts[k]->x - bullVerts[n]->x,
bullVerts[k]->y - bullVerts[n]->y));
asteroidEdges.insert(new Vector2D(asteroids[i]->vertices[k]->x - asteroids[i]->vertices[n]->x,
asteroids[i]->vertices[k]->y - asteroids[i]->vertices[n]->y));
}
Vector2D *vectOffset = new Vector2D(asteroids[i]->center.x - b.x, asteroids[i]->center.y - b.y);
for (unsigned int k = 0; k < asteroidEdges.size(); k++) {
Vector2D *axis = asteroidEdges[k]->getPerpendicular();
axis->normalize();
min1 = max1 = axis->dotProduct(asteroids[i]->vertices[0]);
for (unsigned int l = 1; l < asteroids[i]->vertices.size(); l++) {
float test = axis->dotProduct(asteroids[i]->vertices[l]);
min1 = (test < min1) ? test : min1;
max1 = (test > max1) ? test : max1;
}
min2 = max2 = axis->dotProduct(bullVerts[0]);
for (unsigned int l = 1; l < bullVerts.size(); l++) {
float test = axis->dotProduct(bullVerts[l]);
min2 = (test < min2) ? test : min2;
max2 = (test > max2) ? test : max2;
}
float offset = axis->dotProduct(vectOffset);
min1 += offset;
max1 += offset;
delete axis; axis = NULL;
float d0 = min1 - max2;
float d1 = min2 - max1;
if ( d0 > 0 || d1 > 0 ) {
realCollision = false;
break;
} else {
realCollision = true;
}
}
if (realCollision) {
for (unsigned int k = 0; k < bullEdges.size(); k++) {
Vector2D *axis = bullEdges[k]->getPerpendicular();
axis->normalize();
min1 = max1 = axis->dotProduct(asteroids[i]->vertices[0]);
for (unsigned int l = 1; l < asteroids[i]->vertices.size(); l++) {
float test = axis->dotProduct(asteroids[i]->vertices[l]);
min1 = (test < min1) ? test : min1;
max1 = (test > max1) ? test : max1;
}
min2 = max2 = axis->dotProduct(bullVerts[0]);
for (unsigned int l = 1; l < bullVerts.size(); l++) {
float test = axis->dotProduct(bullVerts[l]);
min2 = (test < min2) ? test : min2;
max2 = (test > max2) ? test : max2;
}
float offset = axis->dotProduct(vectOffset);
min1 += offset;
max1 += offset;
delete axis; axis = NULL;
float d0 = min1 - max2;
float d1 = min2 - max1;
if ( d0 > 0 || d1 > 0 ) {
realCollision = false;
break;
} else {
realCollision = true;
}
}
}
if (realCollision) {
player.bullets.remove(j);
int numAsteroids;
float newDegree;
srand ( j + asteroidBox.x );
if ( asteroids[i]->degree == 90.0f ) {
if ( rand() % 2 == 1 ) {
numAsteroids = 3;
newDegree = 30.0f;
} else {
numAsteroids = 2;
newDegree = 45.0f;
}
for ( int k = 0; k < numAsteroids; k++)
asteroids.insert(new Asteroid(asteroidBox.x + (10 * k), asteroidBox.y + (10 * k), newDegree));
}
delete asteroids[i];
asteroids.remove(i);
}
while (bullVerts.size()) {
delete bullVerts[0];
bullVerts.remove(0);
}
while (bullEdges.size()) {
delete bullEdges[0];
bullEdges.remove(0);
}
while (asteroidEdges.size()) {
delete asteroidEdges[0];
asteroidEdges.remove(0);
}
delete vectOffset; vectOffset = NULL;
}
}
}
}
}
bullEdges is a list of vectors of the edges of a bullet, asteroidEdges is similar, and bullVerts and asteroids[i].vertices are, obviously, lists of vectors of each vertex for the respective bullet or asteroid.
Honestly, I'm not looking for code corrections, just a fresh set of eyes.
Turns out my mathematical understanding of the theorem was perfectly fine. Instead, the problem lay in the fact that I was not including the center points of the polygons in the vertice vectors.
Thank you everyone for their time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With