
Breaking down the game template
The best way to learn is by practicing. Examples are great, but there's nothing like getting stuck in and working on a real game. The game template provided will allow us to implement the systems that we're going to learn about in a real game as opposed to them being a collection of isolated exercises.
Familiarizing yourself with this template will not only help make the code examples throughout the book clearer, but also make the exercises at the end of each chapter easier. It will also allow you to use what you're learning to implement your own systems in the project once we're done with it.
Download templates
Before you start, download the game template so that you have the source code available as you run through some of the key points. The template is available for download on the official Packt Publishing website at http://www.packtpub.com/support.
We'll set it up shortly, but for now, let's take a quick look at some of its key features.
The class diagram
Included with the project download is an image of the complete class diagram for our solution. If at any point you have any questions about the structure of the template, refer to the diagram.
Class diagrams are a great way of seeing the complete structure of your software. As your game gets bigger and bigger, it will inevitably get more convoluted as inheritance structures grow larger. If you have the tools available to do so, it's a great idea to view a class diagram regularly and keep on top of its structure. It will help you identify where your structure needs work, and where doesn't.
Tip
Creating diagrams in Microsoft Visual Studio is restricted to the Professional edition or higher. However, there are various free tools available, such as Doxygen at at http://argouml.tigris.org/, which create UML diagrams from source code.
The object hierarchy
All objects in the template follow a set inheritance hierarchy. At the base of all classes is the Object
class. This provides a sprite
, a position
, an Update()
virtual function, and a Draw()
virtual function.
All classes extend from this base class, implementing their own behaviors by overriding these virtual functions. In our main
game class we create containers for the main base classes, grouping all items and enemies into single collections that we can iterate over easily:
std::vector<std::unique_ptr<Item>> m_items; std::vector<std::unique_ptr<Enemy>> m_enemies;
A vector of base class pointers allows us to take advantage of polymorphism and store all the classes that inherit from the same parent classes in a single data structure. Don't worry if you're unfamiliar with polymorphism. Towards the end of the chapter we'll take a look at both polymorphism and the object pipeline to add an object to the game.
Tip
We're using the std::unique_ptr
C++11 smart pointer over raw pointers. For more information on smart pointers and their benefits, visit https://msdn.microsoft.com/en-us/library/hh279674.aspx.
Level data
The game template that is provided is a roguelike
template. Given this, the level is described as a grid. The best way to represent a grid in this context is with a 2D array, and to store all the information that we need, we'll use a custom data type named Tile
, as follows:
/** * A struct that defines the data values our tiles need. */ struct Tile { TILE type; // The type of tile this is. int columnIndex; // The column index of the tile. int rowIndex; // The row index of the tile. sf::Sprite sprite; // The tile sprite. int H; // Heuristic / movement cost to goal. int G; // Movement cost. (Total of entire path) int F; // Estimated cost for full path. (G + H) Tile* parentNode; // Node to reach this node. };
This struct
allows us to have a single 2D array of the Tile
type, which can store all the information that each tile needs. This approach is incredibly common when creating a game of this type. The array is found in the Level
class, which is instantiated at the beginning of the game. It encapsulates all the data pertaining to the level.
For now, level data is stored in a simple text file which is parsed during the runtime by performing a simple lookup on an enumerator that defines all the tile types. We will work on an example of this towards the end of the chapter.
The following screenshot shows how the level data is saved:

Collision
Collisions are based on the ID
of the tile that you're currently standing on. Every time a player starts to move, the position that they will be in after a successful move is calculated. This position is then used to calculate the grid tile
that they are placed on. This tile is then used to determine what action should be performed; the action can involve performing a blocking movement, picking up an item, or taking damage.
Note
This type of collision can lead to the bullet through paper problem, but given the game's speed, this isn't an issue in our case. If you're unaware of what this problem is, look it up online; it may catch you out in later projects!
Input
Input is handled through a custom static Input
class. It works much like the Input
class that is provided with SFML, but it combines a number of possible inputs into a single call. For example, when checking whether the left key is pressed, it will check the A key, Left arrow key, left D-Pad, and analog stick. If this was to be done using the standard Input
class, you would have to check all four individually. The Input
class provided streamlines this.
A public enum
of keycodes is defined in input.h
and contains the following values that are used to poll input:
/** * An enum denoting all possible input keys. */ enum class KEY { KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_ATTACK, KEY_ESC };
To check the input, we simply call Inputs IsKeyPressed(KEY keycode)
statically, passing one of the aforementioned valid keycodes.