Changing the main.cpp file

After updating our star.cpp file, we need to change the main.cpp file to incorporate our elastic collisions. We need to make all of these changes to the collisions() function. Here is the new version of collisions in its entirety:

void collisions() {
Asteroid* asteroid;
std::vector<Asteroid*>::iterator ita;
if( player->m_CurrentFrame == 0 && player->CompoundHitTest( star ) ) {
player->m_CurrentFrame = 1;
player->m_NextFrameTime = ms_per_frame;
player->m_Explode->Run();
large_explosion_snd->Play();
}
if( enemy->m_CurrentFrame == 0 && enemy->CompoundHitTest( star ) ) {
enemy->m_CurrentFrame = 1;
enemy->m_NextFrameTime = ms_per_frame;
enemy->m_Explode->Run();
large_explosion_snd->Play();
}
Projectile* projectile;
std::vector<Projectile*>::iterator it;
for(it=projectile_pool->m_ProjectileList.begin();
it!=projectile_pool->m_ProjectileList.end();
it++) {
projectile = *it;
if( projectile->m_CurrentFrame == 0 && projectile->m_Active ) {
for( ita = asteroid_list.begin(); ita != asteroid_list.end();
ita++
) {
asteroid = *ita;
if( asteroid->m_Active ) {
if( asteroid->HitTest( projectile ) ) {
asteroid->ElasticCollision( projectile );
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
small_explosion_snd->Play();
}
}
}
if( projectile->HitTest( star ) ){
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
small_explosion_snd->Play();
}
else if( player->m_CurrentFrame == 0 && ( projectile->HitTest(
player ) ||
player->CompoundHitTest( projectile ) ) ) {
if( player->m_Shield->m_Active == false ) {
player->m_CurrentFrame = 1;
player->m_NextFrameTime = ms_per_frame;
player->m_Explode->Run();
large_explosion_snd->Play();
}
else {
hit_snd->Play();
player->ElasticCollision( projectile );
}
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
}
else if( enemy->m_CurrentFrame == 0 && ( projectile-
>HitTest( enemy ) || enemy->CompoundHitTest( projectile ) )
) {
if( enemy->m_Shield->m_Active == false ) {
enemy->m_CurrentFrame = 1;
enemy->m_NextFrameTime = ms_per_frame;
enemy->m_Explode->Run();
large_explosion_snd->Play();
}
else {
enemy->ElasticCollision( projectile );
hit_snd->Play();
}
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
}
}
}
for( ita = asteroid_list.begin(); ita != asteroid_list.end(); ita++ ) {
asteroid = *ita;
if( asteroid->m_Active ) {
if( asteroid->HitTest( star ) ) {
asteroid->Explode();
small_explosion_snd->Play();
}
}
else { continue; }
if( player->m_CurrentFrame == 0 && asteroid->m_Active &&
( asteroid->HitTest( player ) || player->CompoundHitTest(
asteroid ) ) ) {
if( player->m_Shield->m_Active == false ) {
player->m_CurrentFrame = 1;
player->m_NextFrameTime = ms_per_frame;
player->m_Explode->Run();
large_explosion_snd->Play();
}
else {
player->ElasticCollision( asteroid );
small_explosion_snd->Play();
}
}
if( enemy->m_CurrentFrame == 0 && asteroid->m_Active &&
( asteroid->HitTest( enemy ) || enemy->CompoundHitTest(
asteroid ) ) ) {
if( enemy->m_Shield->m_Active == false ) {
enemy->m_CurrentFrame = 1;
enemy->m_NextFrameTime = ms_per_frame;
enemy->m_Explode->Run();
large_explosion_snd->Play();
}
else {
enemy->ElasticCollision( asteroid );
small_explosion_snd->Play();
}
}
}
Asteroid* asteroid_1;
Asteroid* asteroid_2;
std::vector<Asteroid*>::iterator ita_1;
std::vector<Asteroid*>::iterator ita_2;
for( ita_1 = asteroid_list.begin(); ita_1 != asteroid_list.end();
ita_1++ ) {
asteroid_1 = *ita_1;
if( !asteroid_1->m_Active ) { continue; }
for( ita_2 = ita_1+1; ita_2 != asteroid_list.end(); ita_2++ ) {
asteroid_2 = *ita_2;
if( !asteroid_2->m_Active ) { continue; }
if( asteroid_1->HitTest( asteroid_2 ) ) {
asteroid_1->ElasticCollision( asteroid_2 );
}
}
}
}

In the first part of this function, we loop over the projectiles and check to see whether they hit an asteroid or a ship. If the projectile hits an asteroid or a ship when that ship has its shields up, we want to create an elastic collision with the projectile. The projectile will still be destroyed, but the ship or asteroid will have a modified velocity based on the collision. Here is the code for the projectile loop:

for( it = projectile_pool->m_ProjectileList.begin(); it != projectile_pool->m_ProjectileList.end(); it++ ) {
projectile = *it;
if( projectile->m_CurrentFrame == 0 && projectile->m_Active ) {
for( ita = asteroid_list.begin(); ita != asteroid_list.end();
ita++ ) {
asteroid = *ita;
if( asteroid->m_Active ) {
if( asteroid->HitTest( projectile ) ) {
asteroid->ElasticCollision( projectile );
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
small_explosion_snd->Play();
}
}
}
if( projectile->HitTest( star ) ){
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
small_explosion_snd->Play();
}
else if( player->m_CurrentFrame == 0 &&
( projectile->HitTest( player ) ||
player->CompoundHitTest( projectile ) ) ) {
if( player->m_Shield->m_Active == false ) {
player->m_CurrentFrame = 1;
player->m_NextFrameTime = ms_per_frame;

player->m_Explode->Run();
large_explosion_snd->Play();
}
else {
hit_snd->Play();
player->ElasticCollision( projectile );
}
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
}
else if( enemy->m_CurrentFrame == 0 &&
( projectile->HitTest( enemy ) ||
enemy->CompoundHitTest( projectile ) ) ) {
if( enemy->m_Shield->m_Active == false ) {
enemy->m_CurrentFrame = 1;
enemy->m_NextFrameTime = ms_per_frame;
enemy->m_Explode->Run();
large_explosion_snd->Play();
}
else {
enemy->ElasticCollision( projectile );
hit_snd->Play();
}
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
}
}
}

The first series of checks this loop performs is against every asteroid. It looks for an active asteroid with which it currently collides. If those conditions are true, the first thing it does is call the ElasticCollision function on the asteroid, passing in the projectile:

for( ita = asteroid_list.begin(); ita != asteroid_list.end(); ita++ ) {
asteroid = *ita;
if( asteroid->m_Active ) {
if( asteroid->HitTest( projectile ) ) {
asteroid->ElasticCollision( projectile );
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
small_explosion_snd->Play();
}
}

This code is the same as the earlier version, but with the addition of this call to ElasticCollision:

asteroid->ElasticCollision( projectile );

Later in our loop through each active projectile, we will add a call to the ElasticCollision function if a projectile strikes your player's spaceship while its shields are up:

else if( player->m_CurrentFrame == 0 &&
( projectile->HitTest( player ) ||
player->CompoundHitTest( projectile ) ) ) {
if( player->m_Shield->m_Active == false ) {
player->m_CurrentFrame = 1;
player->m_NextFrameTime = ms_per_frame;
player->m_Explode->Run();
large_explosion_snd->Play();
}
else {
hit_snd->Play();
player->ElasticCollision( projectile );
}
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
}

We will do the same for an enemy spaceship struck by a projectile while its shields are up:

    else if( enemy->m_CurrentFrame == 0 &&
( projectile->HitTest( enemy ) ||
enemy->CompoundHitTest( projectile ) ) ) {
if( enemy->m_Shield->m_Active == false ) {
enemy->m_CurrentFrame = 1;
enemy->m_NextFrameTime = ms_per_frame;
enemy->m_Explode->Run();
large_explosion_snd->Play();
}
else {
enemy->ElasticCollision( projectile );
hit_snd->Play();
}
projectile->m_CurrentFrame = 1;
projectile->m_NextFrameTime = ms_per_frame;
}
}

After looping over all of the active projectiles, the collisions function loops over all of the asteroids looking for a collision between an asteroid and one of the ships. If the ship does not have its shields activated, the ship is destroyed. We do not make any modifications to this part of the code. In previous versions of our code, if the ship did have its shields up, we destroyed the asteroid. Now, we will have an elastic collision, which will cause the spaceship and the asteroid to bounce off one another. This is what this asteroid loop looks like:

for( ita = asteroid_list.begin(); ita != asteroid_list.end(); ita++ ) {
asteroid = *ita;
if( asteroid->m_Active ) {
if( asteroid->HitTest( star ) ) {
asteroid->Explode();
small_explosion_snd->Play();
}
}
else {
continue;
}

if( player->m_CurrentFrame == 0 &&
asteroid->m_Active &&
( asteroid->HitTest( player ) ||
player->CompoundHitTest( asteroid ) ) ) {
if( player->m_Shield->m_Active == false ) {
player->m_CurrentFrame = 1;
player->m_NextFrameTime = ms_per_frame;

player->m_Explode->Run();
large_explosion_snd->Play();
}
else {
player->ElasticCollision( asteroid );
small_explosion_snd->Play();
}
}
if( enemy->m_CurrentFrame == 0 &&
asteroid->m_Active &&
( asteroid->HitTest( enemy ) ||
enemy->CompoundHitTest( asteroid ) ) ) {
if( enemy->m_Shield->m_Active == false ) {
enemy->m_CurrentFrame = 1;
enemy->m_NextFrameTime = ms_per_frame;

enemy->m_Explode->Run();
large_explosion_snd->Play();
}
else {
enemy->ElasticCollision( asteroid );
small_explosion_snd->Play();
}
}
}

There are now two calls to ElasticCollision. One of the calls occurs when the player ship collides with an asteroid and the player ship has its shields up. The other occurs when the enemy ship collides with an asteroid, and the enemy ship has its shields up.

The last change we must make to our collisions() function is the addition of a new double asteroid loop that will loop through all our asteroids looking for collisions between two of them. That creates a fun effect where asteroids bounce off one another like billiard balls. If there is a collision detected between two of the asteroids, we call ElasticCollision:

Asteroid* asteroid_1;
Asteroid* asteroid_2;

std::vector<Asteroid*>::iterator ita_1;
std::vector<Asteroid*>::iterator ita_2;

for( ita_1 = asteroid_list.begin(); ita_1 != asteroid_list.end(); ita_1++ ) {
asteroid_1 = *ita_1;
if( !asteroid_1->m_Active ) {
continue;
}

for( ita_2 = ita_1+1; ita_2 != asteroid_list.end(); ita_2++ ) {
asteroid_2 = *ita_2;
if( !asteroid_2->m_Active ) {
continue;
}

if( asteroid_1->HitTest( asteroid_2 ) ) {
asteroid_1->ElasticCollision( asteroid_2 );
}
}
}