Reputation:
I'm recreating the classic game Asteroids and I'm having some problems with getting the collision detection working correctly. Currently, the below code works well, but for some reason it will only detect collisions on the last missile that has been fired. What I mean is if I fire 3 missiles in a straight line at a stationary asteroid, the first two will pass through the asteroid whilst only the last one will collide with it and act as intended. I'm not quite sure why this is happening but I think it has something to do with iterating through the list of missiles.
Here's the partially working function that is used to detect collisions:
void checkMissileAsteroidCollision(struct particle *ast, struct particle *mis)
{
float missileX = 0;
float missileY = 0;
float asteroidX = 0;
float asteroidY = 0;
float asteroidSize = 0;
for( ; mis ; mis = mis->next )
{
missileX = mis->x;
missileY = mis->y;
for( ; ast ; ast = ast->next)
{
asteroidX = ast->x;
asteroidY = ast->y;
asteroidSize = ast->size;
if(missileX < asteroidX + asteroidSize &&
missileX > asteroidX &&
missileY < asteroidY + asteroidSize &&
missileY > asteroidY && mis->draw == 1 && ast->draw == 1)
{
collisionCounter++;
ast->draw = 0;
mis->draw = 0;
}
}
}
}
The particle struct;
typedef struct particle{
float x;
float y;
float vx;
float vy;
float heading;
float dur;
int size;
int draw;
struct particle *next;
} node_t;
I've included two links below that link to the whole source file and its header where this code comes from, in case any other information is needed to figure out why this is happening.
gamestate.cpp: https://gist.github.com/Jakemangan/d286ef1f9159e6682778ec2e0daf516c
gamestate.h: https://gist.github.com/Jakemangan/6c3788a46825a86cd0e2642864fcad68
Upvotes: 1
Views: 350
Reputation: 39390
This is how a more modern C++ version could look like:
// drop the pointer from the struct
void checkMissileAsteroidCollision(std::vector<particle>& asteroids, std::vector<particle>& missiles)
{
for(auto & mis : missiles)
{
for(auto & ast : asteroids)
{
const auto missileX = mis.x;
const auto missileY = mis.y;
const auto asteroidX = ast.x;
const auto asteroidY = ast.y;
const auto asteroidSize = ast.size;
if(missileX < asteroidX + asteroidSize &&
missileX > asteroidX &&
missileY < asteroidY + asteroidSize &&
missileY > asteroidY && mis.draw == 1 && ast.draw == 1)
{
collisionCounter++;
ast.draw = false;
mis.draw = false;
}
}
}
}
Then example creation and use:
std::vector<particle> asteroids { { 0, 0, 0, 0, 0, 0, 10, true } };
std::vector<particle> missiles { { 5, 5, 0, 0, 0, 0, 10, true } };
checkMissileAsteroidCollision(asteroids, missiles);
std::cout << std::boolalpha << asteroids[0].draw;
There are more improvements to be made here (encapsulation in a class, not taking parameters to mutate, not using draw
as collision flag), but I believe those belong to Code Review and I encourage you to post your solution there once you get it to work.
Upvotes: 1
Reputation: 169291
for( ; ast ; ast = ast->next)
This line is the problem. After this loop terminates, ast
is null but it is not reset for the next iteration of the outer mis
loop. This means that only the first iteration of the mis
loop actually sees any asteroids.
To correct this, declare a new variable for this loop:
for(struct particle *ast2 = ast ; ast2 ; ast2 = ast2->next)
(Or choose a better name than ast2
.) Then, obviously, replace ast
with ast2
in the loop body.
Upvotes: 5