The basic characteristics of a tower can be summarized as follows:
Based on these characteristics, we shall define the following properties for a tower in our game:
These properties are varied enough to build a simple yet interesting game. With the help of a skilled level designer, you can even make the player enjoy hours of satisfying gameplay.
Let's quickly take a look at the XML structure that is defined to accommodate the data for the towers in this game:
<TowerDataSetList> <TowerDataSet bullet_name="TD_bullet01.png" is_lightning="false" is_rotating="true"> <TowerData sprite_name="TD_t01gun01.png" range="1.5" physical_damage="10" magical_damage="0" speed_damage="1.0" speed_damage_duration="0" fire_rate="1.5" cost="100" /> <TowerData sprite_name="TD_t01gun02.png" range="2" physical_damage="25" magical_damage="0" speed_damage="1.0" speed_damage_duration="0" fire_rate="1.0" cost="175" /> <TowerData sprite_name="TD_t01gun03.png" range="3" physical_damage="30" magical_damage="0" speed_damage="1.0" speed_damage_duration="0" fire_rate="0.5" cost="250" /> </TowerDataSet> . . . </TowerDataSetList>
The root element of this XML document is titled TowerDataSetList
, which defines a list of TowerDataSet
tags. A TowerDataSet
tag represents nothing but the various levels or upgrades that a given tower can possess. For this game, I have defined that each tower will possess three levels or upgrades, each defined within a TowerData
tag. The various attributes from the XML file are summarized in the following table:
For Pumpkin Defense, I used this architecture to create just three towers (with three upgrades each): one that does physical damage, one that does magical damage, and one that slows down the enemy for a given period of time. This information is stored in the tower_data.xml
file inside the source bundle for this chapter. Incidentally, I gave the magical tower a cool ability of casting a lightning bolt at enemies.
All these properties are parsed and stored inside structs TowerDataSet
and TowerData
inside our global data class GameGlobals
. Let's take a quick look at the declaration of these structures, starting with TowerDataSet
in the GameGlobals.h
file:
struct TowerDataSet { char bullet_name_[256]; bool is_lightning_; bool is_rotating_; vector<TowerData*> tower_data_; TowerDataSet() : is_lightning_(false), is_rotating_(false) { sprintf(bullet_name_, "%s", ""); tower_data_.clear(); } ~TowerDataSet() { for(int i = 0; i < NUM_TOWER_UPGRADES; ++i) { delete tower_data_[i]; } tower_data_.clear(); } };
As you'd expect, the TowerDataSet
structure mirrors the TowerDataSet
tag. It contains a char
array to store the bullet name and two flags to represent if this tower will rotate towards an enemy or if this tower will shoot bolts of lightning instead of bullets.
Finally, you will see a vector holding pointers to the TowerData
objects. Let's glance at the TowerData
structure from GameGlobals.h
:
struct TowerData { char sprite_name_[256]; float range_; float physical_damage_; float magical_damage_; float speed_damage_; float speed_damage_duration_; float fire_rate_; int cost_; TowerData() : range_(0.0f), physical_damage_(0.0f), magical_damage_(0.0f), speed_damage_(0.0f), speed_damage_duration_(0.0f), fire_rate_(0.0f), cost_(0) { sprintf(sprite_name_, "%s", ""); } };
Once again, the TowerData
structure is a mirror image of the TowerData
tag. Its members are identical to the attributes of the TowerData
tag detailed in the preceding code and hence we will skip discussing them.
What is important to note is that our static class GameGlobals
maintains a vector named tower_data_sets_
containing pointers to TowerDataSet
objects. When the game is launched, the LoadData
function from GameGlobals
is called and the tower_data.xml
file is parsed to fill up the tower_data_sets_
vector with the relevant information. Whenever the player creates a new tower, that tower reads all its properties from one of the objects within this vector.
In a similar way, let's define the properties of the enemy.
18.217.147.193