Coding a class for pickups

We will code a Pickup class that has a Sprite, member as well as other member data and functions. We will add pickups to our game in just a few steps:

  1. First, we will code the Pickup.h file. This will reveal all the details of the member data and the prototypes for the functions.
  2. Then we will code the Pickup.cpp file which, of course, will contain the definitions for all the functions of the Pickup class. As we step through it, I will explain exactly how an object of type Pickup will work and be controlled.
  3. Finally, we will use the Pickup class in the main function to spawn them, update them and draw them.

Let's get started with step 1.

Coding the Pickup header file

To make the new header file, right-click Header Files in the Solution Explorer and select Add | New Item.... In the Add New Item window, highlight (by left-clicking) Header File ( .h ) and then in the Name field type Pickup.h.

Add and study the following code in the Pickup.h file and then we can go through it:

#pragma once 
#include <SFML/Graphics.hpp> 
 
using namespace sf; 
 
class Pickup 
{ 
private: 
   //Start value for health pickups 
   const int HEALTH_START_VALUE = 50; 
   const int AMMO_START_VALUE = 12; 
   const int START_WAIT_TIME = 10; 
   const int START_SECONDS_TO_LIVE = 5; 
    
   // The sprite that represents this pickup 
   Sprite m_Sprite; 
 
   // The arena it exists in 
   IntRect m_Arena; 
 
   // How much is this pickup worth? 
   int m_Value; 
    
   // What type of pickup is this?  
   // 1 = health, 2 = ammo 
   int m_Type; 
 
   // Handle spawning and disappearing 
   bool m_Spawned; 
   float m_SecondsSinceSpawn; 
   float m_SecondsSinceDeSpawn; 
   float m_SecondsToLive; 
   float m_SecondsToWait;   
 
   // Public prototypes go here 
};

The previous code declares all the private variables of the Pickup class. Although the names should be quite intuitive, it might not be obvious why many of them are needed at all. Let's go through them, starting from the top:

  • const int HEALTH_START_VALUE = 50: This constant variable is used to set the starting value of all health pickups. The value will be used to initialize the m_Value variable, which will need to be manipulated throughout the course of a game.
  • const int AMMO_START_VALUE = 12: This constant variable is used to set the starting value of all ammo pickups. The value will be used to initialize the m_Value variable, which will need to be manipulated throughout the course of a game.
  • const int START_WAIT_TIME = 10: This variable is how long a pickup will wait before it re-spawns after disappearing. It will be used to initialize the m_SecondsToWait variable which can be manipulated throughout the game.
  • const int START_SECONDS_TO_LIVE = 5: This variable determines how long a pickup will last between spawning and being de-spawned. Like the previous three constants, it has a non-constant associated with it that can be manipulated throughout the course of the game. The non-constant it is used to initialize is m_SecondsToLive.
  • Sprite m_Sprite: This is the sprite to visually represent the object.
  • IntRect m_Arena: This will hold the size of the current arena to help the pickup spawn in a sensible position.
  • int m_Value: How much health or ammo is this pickup worth? This value is used when the player levels-up the value of the health or ammo pickup.
  • int m_Type: This will be either zero or one for health or ammo. We could have used an enumeration class but that seemed like overkill for just two options.
  • bool m_Spawned: Is the pickup currently spawned?
  • float m_SecondsSinceSpawn: How long is it since the pickup was spawned?
  • float m_SecondsSinceDeSpawn: How long is it since the pickup was de-spawned (disappeared)?
  • float m_SecondsToLive: How long should this pickup stay spawned before de-spawning?
  • float m_SecondsToWait: How long should this pickup stay de-spawned before re-spawning?

Tip

Note that most of the complexity of this class is due to the variable spawn time and its upgradeable nature. If the pickups just re-spawned when collected and had a fixed value this would be a very simple class. We need our pickups to be upgradeable, so the player is forced to develop a strategy to progress through the waves of zombies.

Next, add the following public function prototypes to the Pickup.h file. Be sure to familiarize yourself with the new code so we can go through it:

// Public prototypes go here 
public:
   Pickup::Pickup(int type);

   // Prepare a new pickup
   void setArena(IntRect arena);
   void spawn();

   // Check the position of a pickup
   FloatRect getPosition();

   // Get the sprite for drawing
   Sprite getSprite();

   // Let the pickup update itself each frame
   void update(float elapsedTime);

   // Is this pickup currently spawned?
   bool isSpawned();

   // Get the goodness from the pickup
   int gotIt();

   // Upgrade the value of each pickup
   void upgrade();
};

Let's talk briefly about each of the function definitions:

  • The first function is the constructor, named after the class. Note that it takes a single int parameter. This will be used to initialize the type of pickup it will be (health or ammo).
  • The setArena function receives an IntRect. This function will be called for each Pickup instance at the start of each wave. The Pickup objects will then know the areas into which they can spawn.
  • The spawn function will, of course, handle spawning the pickup.
  • The getPosition function, just like in the Player, Zombie, and Bullet classes will return a FloatRect that represents the current location of the object in the game world.
  • The getSprite function returns a Sprite object that enables the pickup to be drawn, once each frame.
  • The update function receives the time the previous frame took. It uses this value to update its private variables and make decisions about when to spawn and de-spawn.
  • The isSpawned function returns a Boolean that will let the calling code know whether or nor the pickup is currently spawned.
  • The gotIt function will be called when a collision is detected with the player. The Pickup class code can then prepare itself for re-spawning at the appropriate time. Note that it returns an int so that the calling code knows how much the pickup is worth in either health or ammo.
  • The upgrade function will be called when the player chooses to levelup the properties of a pickup during the levelingup phase of the game.

Now we have gone through the member variables and function prototypes, it should be quite easy to follow along as we code the function definitions.

Coding the Pickup class function definitions

Now we can create a new .cpp file that will contain the function definitions. Right-click Source Files in the Solution Explorer and select Add | New Item.... In the Add New Item window, highlight (by left-clicking) C++ File ( .cpp ) and then in the Name field type Pickup.cpp. Finally, click the Add button. We are now ready to code the class.

Add the code shown here to the Pickup.cpp file. Be sure to review the code so we can discuss it:

#include "stdafx.h" 
#include "Pickup.h" 
#include "TextureHolder.h" 
 
Pickup::Pickup(int type) 
{ 
   // Store the type of this pickup 
   m_Type = type; 
 
   // Associate the texture with the sprite 
   if (m_Type == 1) 
   { 
      m_Sprite = Sprite(TextureHolder::GetTexture( 
         "graphics/health_pickup.png")); 
 
      // How much is pickup worth 
      m_Value = HEALTH_START_VALUE; 
 
   } 
   else 
   { 
      m_Sprite = Sprite(TextureHolder::GetTexture( 
         "graphics/ammo_pickup.png")); 
 
      // How much is pickup worth 
      m_Value = AMMO_START_VALUE; 
   } 
 
   m_Sprite.setOrigin(25, 25); 
 
   m_SecondsToLive = START_SECONDS_TO_LIVE; 
   m_SecondsToWait = START_WAIT_TIME; 
}

In the previous code, we added the familiar include directives. Then we added the Pickup constructor. We know it is the constructor because it has the same name as the class.

The constructor receives an int called type and the first thing the code does is assign the value received from type to m_Type. After this, there is an if…else block that checks whether m_Type is equal to 1. If it is, m_Sprite is associated with the health pickup texture and m_Value is set to HEALTH_START_VALUE.

If m_Type is not equal to 1, the else block associates the ammo pickup texture with m_Sprite and assigns the value of AMMO_START_VALUE to m_Value.

After the if…else block, the code sets the origin of m_Sprite to the center using the setOrigin function and assigns START_SECONDS_TO_LIVE and START_WAIT_TIME to m_SecondsToLive and m_SecondsToWait, respectively.

The constructor has successfully prepared a Pickup object that is ready for use.

Next we will add the setArena function. Examine the code as you add it:

void Pickup::setArena(IntRect arena) 
{ 
 
   // Copy the details of the arena to the pickup's m_Arena 
   m_Arena.left = arena.left + 50; 
   m_Arena.width = arena.width - 50; 
   m_Arena.top = arena.top + 50; 
   m_Arena.height = arena.height - 50; 
 
   spawn(); 
}

The setArena function that we just coded simply copies the values from the passed in arena, object but varies the values by plus fifty on the left and top and minus fifty on the right and bottom. The Pickup object is now aware of the area in which it can spawn. The setArena function then calls its own spawn function to make the final preparations for being drawn and updated each frame.

The spawn function is next. Add the following code after the setArena function:

void Pickup::spawn() 
{ 
   // Spawn at a random location 
   srand((int)time(0) / m_Type); 
   int x = (rand() % m_Arena.width); 
   srand((int)time(0) * m_Type); 
   int y = (rand() % m_Arena.height); 
 
   m_SecondsSinceSpawn = 0; 
   m_Spawned = true; 
 
   m_Sprite.setPosition(x, y); 
}

The spawn function does everything necessary to prepare the pickup. First it seeds the random number generator and gets a random number for both the horizontal and vertical position of the object. Notice that it uses m_Arena.width and m_Arena.height as the ranges for the possible horizontal and vertical positions.

The m_SecondsSinceSpawn is set to zero so the length of time allowed before it is de-spawned is reset. The m_Spawned variable is set to true so that when we call isSpawned, from main, we will get a positive response. Finally, m_Sprite is moved into position with setPosition, ready for drawing to the screen.

In the following block of code, we have three simple getter functions. The getPosition function returns a FloatRect of the current position of m_Sprite, getSprite returns a copy of m_Sprite itself, and isSpawned returns true or false depending upon whether the object is currently spawned.

Add and examine the code we have just discussed:

FloatRect Pickup::getPosition() 
{ 
   return m_Sprite.getGlobalBounds(); 
} 
 
Sprite Pickup::getSprite() 
{ 
   return m_Sprite; 
} 
 
bool Pickup::isSpawned() 
{ 
   return m_Spawned; 
} 
 

Next we will code the gotIt function. This function will be called from main when the player touches/collides with (gets) the pickup. Add the gotIt function after the isSpawned function:

 
int Pickup::gotIt() 
{ 
   m_Spawned = false; 
   m_SecondsSinceDeSpawn = 0; 
   return m_Value; 
}

The gotIt function sets m_Spawned to false so we know not to draw and check for collisions at the moment. The m_SecondsSinceDespawn is set to zero so the countdown to spawning begins again from the start and m_Value is returned to the calling code so the calling code can handle adding extra ammunition or health, as appropriate.

Next we have the update function, which ties together many of the variables and functions we have seen so far. Add and familiarize yourself with the update function and then we can talk about it:

void Pickup::update(float elapsedTime) 
{ 
   if (m_Spawned) 
   { 
      m_SecondsSinceSpawn += elapsedTime; 
   } 
   else 
   { 
      m_SecondsSinceDeSpawn += elapsedTime; 
   } 
 
 
   // Do we need to hide a pickup? 
   if (m_SecondsSinceSpawn > m_SecondsToLive && m_Spawned) 
   { 
      // Remove the pickup and put it somewhere else 
      m_Spawned = false; 
      m_SecondsSinceDeSpawn = 0; 
   } 
 
   // Do we need to spawn a pickup 
   if (m_SecondsSinceDeSpawn > m_SecondsToWait && !m_Spawned) 
   { 
      // spawn the pickup and reset the timer 
      spawn(); 
   } 
 
}

The update function is divided into four blocks that are considered for execution each frame:

  • An if block that executes if m_Spawned is true—if (m_Spawned). This block of code adds the time of this frame to m_SecondsSinceSpawned, which keeps track of how long the pickup has been spawned.
  • A corresponding else block that executes if m_Spawned is false. This block adds the time this frame took to m_SecondsSinceDeSpawn, which keeps track of how long the pickup has waited since it was last de-spawned (hidden).
  • Another if block that executes when the pickup has been spawned for longer than it should have been—if (m_SecondsSinceSpawn > m_SecondsToLive && m_Spawned). This block sets m_Spawned to false and resets m_SecondsSinceDeSpawn to zero. Now block 2 will execute until it is time to spawn again.
  • A final if block that executes when the time to wait since de-spawning has exceeded the necessary wait time, and the pickup is not currently spawned—if (m_SecondsSinceDeSpawn > m_SecondsToWait && !m_Spawned). When this block is executed, it is time to spawn again and the spawn function is called.

These four tests and code are what controls the hiding and showing of a pickup.

Finally, add the definition for the upgrade function:

void Pickup::upgrade() 
{ 
   if (m_Type == 1) 
   { 
      m_Value += (HEALTH_START_VALUE * .5); 
   } 
   else 
   { 
      m_Value += (AMMO_START_VALUE * .5); 
   } 
 
   // Make them more frequent and last longer 
   m_SecondsToLive += (START_SECONDS_TO_LIVE / 10); 
   m_SecondsToWait -= (START_WAIT_TIME / 10); 
}

The upgrade function tests for the type of pickup, either health or ammo, and then adds 50 percent of the (appropriate) starting value on to m_Value. The next two lines after the if…else blocks increase the amount of time the pickup will remain spawned and decrease the amount of time the player has to wait between spawns.

This function is called when the player chooses to levelup the pickups during the LEVELING_UP state. Our Pickup class is ready for use.

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

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