Sunday 28 February 2010

Tower Defence ideas and a bit of code

Recently in my tower defence game I decided it would be cool to allow opposing players to place bombs over one another's towers in order to destroy them for a certain amount of resources. My thinking was that this would introduce an extra element to the gameplay where by a player has to balance their resources to afford new towers to fend off the enemies, as well as also trying to destroy their friends towers to make life harder for them.

I wanted to implement the bombs so you could have as many as you wanted at a time, so as I have done with my enemies and my towers I created a good old c++ vector (a smart array, or simply a form of container for my data) that could then be iterated through to update them.

I ran into a bit of a problem when I wanted to remove a tower and a bomb after the bomb had blown up the tower. I needed to know if the bomb I was on as I cycled through the list matched the tower, and therefore knew which tower and bomb to remove.

Here is the code I am using, you probably won't understand it, and it probably isn't the most elegant way of doing it, but by joe it works!


void CGameController::Update_Bombs( CTimer* timer )
{
for( unsigned int i = 0; i < _bombs.size(); ++i )
{
_bombs.at(i)->Update( timer );

if(_bombs.at(i)->get_exploded())
{
         for( int j = 0; j < _towers.size(); ++j )
{
if( _bombs.at(i)->get_i() ==
                            _towers.at(j)->get_index_i() &&
    _bombs.at(i)->get_j() ==
                            _towers.at(j)->get_index_j() )
{
_grid->set_occupied( _towers.at(j)->get_index_i(),
                                 _towers.at(j)->get_index_j(), false);

         _towers.at(j) = _towers.back();
_towers.pop_back();

_bombs.at(i) = _bombs.back();
_bombs.pop_back();

break;

}
}
}
}
}

Basically what I am doing is iterating through all my bombs, I update each one in turn, and check if it has exploded. If it has indeed exploded, I then cycle through all my towers, and then do a comparison with the grid square of the tower and the bomb, to make sure they match, and then I remove both of them. It works perfectly, but only with the help of my friend 'break;'.

Without that helpful command, if the first bomb in the bomb list was matched with a tower halfway through the tower list, and the bomb was then removed, the tower list would keep iterating through, and would try and compare itself with a bomb that no longer existed! Not good! I got a horrible run time error, and panicked quite a lot, but then remembered I was missing a 'break;' and then suddenly all was lovely again.

If you can think or a far cleverer way of accomplishing what I am trying to do I would love to hear it, no doubt I am sure there is, but I am just glad it works, well mostly.

2 comments:

Anonymous said...

Maybe too late to be helpful now, but what about using _grid? I'm not sure what else it contains, but set_occupied() looks like it sets a bool indexed by coordinates. If you got it to store pointers to towers instead, you could just grab the tower directly from the bomb's coordinates.

e.g. if your Grid looked like this:

class Grid
{
...
vector < Tower* > locations;
...

bool checkOccupied(int x, int y)
{
return _locations[y * _gridWidth + x] == NULL;
}

void setTower(int x, int y, Tower* t)
{
_locations[y * _gridWidth + x] = t;
}

Tower* getTower(int x, int y)
{
return _locations[y * _gridWidth + x];
}
}

(A 2D array or map or somesuch might also work nicely there.)

Then in Update_Bombs():

...
if (_bombs[i]->get_exploded())
{
Tower* t = _grid->getTower(_bombs[i]->get_i(), _bombs[i]->get_j());
if (t)
{
_grid->setTower(_bombs[i]->get_i(), _bombs[i]->get_j(), NULL);
t->setDestroyed(true);
}
_bombs[i] = _bombs.back();
_bombs.pop_back();
}

Then when you do your normal cycle through the towers vector (e.g. in Update_Towers()?), you can check the destroyed flag and remove it there instead.

I like the way you're deleting items from the vectors though - very neat, and simpler than using iterators! :)

tomhhh said...

That looks really interesting, thank you very much for your input. I will definitely have a re-think about how I remove my towers and bombs! Thanks for the help :)