Spawning the towers

To spawn a tower, the player must first tap somewhere on the map to select the location where they want the tower placed. Once an area of the map has been tapped, the following tower selection menu will be shown:

Spawning the towers

As you can see in the previous screenshot, the player is shown an arrow for each tower. This indicates the direction in which the player must swipe in order to spawn the tower at the specified location. The player can swipe anywhere on the screen and the respective tower will be spawned at the location.

The class responsible for creating that menu, as well as the tower upgrade menu, is defined in the TowerMenu.h and TowerMenu.cpp files. I will skip discussing this class, since it is quite a straightforward class that I'm sure you will be able to wrap your head around with ease.

Now, the tower selection menu shows up when the player taps on the map. Tap gestures are forwarded to the HandleTap function of the GameWorld class:

void GameWorld::HandleTap(CCPoint position)
{
  // get the touch coordinates with respect to the tile map
  CCPoint touch_point = tiled_map_->convertToNodeSpace(position);
  CCPoint tile_coord = ccp(GET_COL_FOR_X(touch_point.x), 
    GET_ROW_FOR_Y(touch_point.y, MAX_ROWS));
  touch_point = ccpMult(tile_coord, TILE_SIZE);
  touch_point.y = SCREEN_SIZE.height - touch_point.y;
  
  // check if the touched tile is empty
  int tile_GID = tmx_layer_->tileGIDAt(tile_coord);
  // if the touched tile is empty, show the tower placement menu
  if(tile_GID == 0)
  {
    // check to ensure only one menu is visible at a time
    if(tower_menu_->placement_node_->isVisible() == false && 
   tower_menu_->maintenance_node_->isVisible() == false)
    {
      tower_menu_->ShowPlacementMenu(touch_point);
      // show the grid
      grid_node_->setVisible(true);
    }
  }
  // a tower exists on the touched tile
  else if(tile_GID >= TOWER_GID)
  {
    int tower_index = tile_GID - TOWER_GID;
    // first check bounds and then check to ensure only one 
   menu is visible at a time
    if(tower_index >= 0 && tower_index < num_towers_ && 
   tower_menu_->maintenance_node_->isVisible() == false && 
   tower_menu_->placement_node_->isVisible() == false)
    {
      // show the tower's current range
      towers_[tower_index]->ShowRange();
      tower_menu_->ShowMaintenanceMenu(touch_point, tower_index, 
     towers_[tower_index]->GetType(), 
  towers_[tower_index]->GetLevel());
    }
  }

  // hide the tower placement menu if it is visible
  if(tower_menu_->placement_node_->isVisible())
  {
    tower_menu_->HidePlacementMenu();
    grid_node_->setVisible(false);
  }
  // hide the tower maintenance menu if it is visible
  if(tower_menu_->maintenance_node_->isVisible())
  {
    tower_menu_->HideMaintenanceMenu();
  }
}

In the preceding code, we take the location of the touch (that is, screen coordinates), convert into coordinates local to the Tiled map, and store it into the touch_point variable. We then calculate the tile coordinate where the preceding tap occurred. Now we know exactly where we need to place our tower.

With the tile coordinates in hand, we first query the Tiled map to see if the requested tile is free. The requested tile won't be free if there is an enemy path tile or another tower placed at that tile coordinate. Thus, if the GID at the requested tile is 0 we know that the tile is empty, and we show the tower selection/placement menu.

If the GID at the requested tile is not 0, it could mean that an enemy path tile or a tower exists there. To find out if there is a tower placed at the tile, we compare the GID with the TOWER_GID constant that is defined as 100 in GameGlobals.h.

Whenever we place a tower at a certain tile, we save a certain GID at that tile. We shall look into this in more detail when we discuss the PlaceTower function from GameWorld. For now, all we need to know is that the GID will point us to the tower placed at the requested tile.

Once we fetch the index of the tower from within GameWorld class' towers_ vector, we simply show the tower maintenance menu. From the tower maintenance menu, the player can choose to either upgrade or sell the respective tower. Lastly, we hide any menus that might have been enabled in any previous taps on the screen.

Now that we've discussed what happens on a tap gesture, let's take a look at the HandleSwipeUp function that is called when an upward swipe is detected:

void GameWorld::HandleSwipeUp()
{
  // return if the tower placement menu is not active
  if(tower_menu_->placement_node_->isVisible() == false)
  {
    return;
  }

  // place the tower with specified type at specified position
  PlaceTower(1, tower_menu_->placement_node_->getPosition());
  tower_menu_->HidePlacementMenu();
  grid_node_->setVisible(false);
}

The player can only place a tower if the tower selection menu is visible; swipes at other times must simply be ignored. This function internally calls the PlaceTower function, passing in the type of tower that needs to be placed along with the location at which it needs to be placed. Without further ado, let's look at the PlaceTower function from GameWorld.cpp to wrap up our tower spawning section:

void GameWorld::PlaceTower(int type, CCPoint position)
{
  // can the player afford this tower?
  if(cash_ < GameGlobals::tower_data_sets_[type]->tower_data_[0]->cost_)
  {
    return;
  }

  // create a new Tower object & add it into the vector of towers
  Tower* tower = Tower::create(this, type, position);
  addChild(tower, E_LAYER_TOWER);
  ++ num_towers_;
  towers_.push_back(tower);

  // save tower's information into the tile map
  position = tiled_map_->convertToNodeSpace(position);
  CCPoint tile_coord = ccp(GET_COL_FOR_X(position.x), GET_ROW_FOR_Y(position.y, MAX_ROWS));
  tmx_layer_->setTileGID(TOWER_GID + (num_towers_ - 1), tile_coord);

  // debit cash
  UpdateCash(-tower->GetCost());
  UpdateHUD();
  // show the range for this tower
  tower->ShowRange();

  // hide the grid now that the tower has been placed
  grid_node_->setVisible(false);
}

First off, we return from the PlaceTower function if the player cannot afford to place the selected tower. We then create a brand new Tower object, passing in a reference to GameWorld, the type of the tower, and its position. We then add it both to the node graph as well as the GameWorld class' vector by the name towers_.

We then calculate the position of the tower with respect to the Tiled map and then use that quantity to calculate the tile coordinates at that point. With the tile coordinates in place, we save this tower's index into the Tiled map. Since Tiled will save the tileset for this tile layer from 0 -> number of tiles, we offset our tower's index by the constant TOWER_GID. That is why we use the following line in the HandleTap function:

int tower_index = tile_GID - TOWER_GID;

Now that we've saved this tower's index safely into the Tiled map for later, we only need to debit the player's cash and update the HUD. We also show the newly placed tower's range.

With this, we wind up our tower placing logic. By now, we have a functional and enjoyable tower defense game—complete with upgradable towers and levels with configurable paths and limitless waves of enemies. We can add one more neat little feature though—a feature that is not uncommon in tower defense games—the fast-forward feature!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.14.144.216