Search icon
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletters
Free Learning
Arrow right icon
Beginning C++ Game Programming. - Second Edition

You're reading from  Beginning C++ Game Programming. - Second Edition

Product type Book
Published in Oct 2019
Publisher Packt
ISBN-13 9781838648572
Pages 746 pages
Edition 2nd Edition
Languages
Author (1):
John Horton John Horton
Profile icon John Horton

Table of Contents (25) Chapters

Preface 1. Chapter 1: C++, SFML, Visual Studio, and Starting the First Game 2. Chapter 2: Variables, Operators, and Decisions – Animating Sprites 3. Chapter 3: C++ Strings and SFML Time – Player Input and HUD 4. Chapter 4: Loops, Arrays, Switches, Enumerations, and Functions – Implementing Game Mechanics 5. Chapter 5: Collisions, Sound, and End Conditions – Making the Game Playable 6. Chapter 6: Object-Oriented Programming – Starting the Pong Game 7. Chapter 7: Dynamic Collision Detection and Physics – Finishing the Pong Game 8. Chapter 8: SFML Views – Starting the Zombie Shooter Game 9. Chapter 9: C++ References, Sprite Sheets, and Vertex Arrays 10. Chapter 10: Pointers, the Standard Template Library, and Texture Management 11. Chapter 11: Collision Detection, Pickups, and Bullets 12. Chapter 12: Layering Views and Implementing the HUD 13. Chapter 13: Sound Effects, File I/O, and Finishing the Game 14. Chapter 14: Abstraction and Code Management – Making Better Use of OOP 15. Chapter 15: Advanced OOP – Inheritance and Polymorphism 16. Chapter 16: Building Playable Levels and Collision Detection 17. Chapter 17: Sound Spatialization and the HUD 18. Chapter 18: Particle Systems and Shaders 19. Chapter 19: Game Programming Design Patterns – Starting the Space Invaders ++ Game 20. Chapter 20: Game Objects and Components 21. Chapter 21: File I/O and the Game Object Factory 22. Chapter 22: Using Game Objects and Building a Game 23. Chapter 23: Before You Go... 24. Other Books You May Enjoy

Chapter 21: File I/O and the Game Object Factory

This chapter handles how a GameObject gets into the m_GameObjects vector that's used in the game. We will look at how we can describe individual objects and an entire level in a text file. We will write code to interpret the text and then load up values into a class that will be a blueprint for a game object. We will also code a class called LevelManager that oversees the whole process, starting from the initial request to load a level sent from an InputHandler via the ScreenManager, right through to the factory pattern class that assembles a game object from components and delivers it to the LevelManager, neatly packed away in the m_GameObjects vector.

The following are the steps we will go through in this chapter:

  • Examine how we will describe game objects and their components in a text file
  • Code the GameObjectBlueprint class where the data from the text file will be temporarily stored
  • Code the ObjectTags class...

The structure of the file I/O and factory classes

Have a look at the following diagram, which gives an overview of the classes we will code in this chapter and how the vector of GameObject instances will be shared with the ScreenManager class that we coded in Chapter 19, Game Programming Design Patterns – Starting the Space Invaders ++ Game:

The preceding diagram shows that there is a vector of GameObject instances that's shared between four classes. This is achieved by passing the vector between the functions of the classes by reference. Each class can then carry out its role with the vector and its contents. The ScreenManager class will trigger the LevelManager class when a new level needs to be loaded into the vector. The individual Screen classes and their InputHandler-derived classes, as we saw in Chapter 19, Game Programming Design Patterns – Starting the Space Invaders ++ Game, have access to ScreenManager via ScreenManagerRemoteControl...

Describing an object in the world

We have already added the level1.txt file in the world folder in Chapter 19, Game Programming Design Patterns – Starting the Space Invaders ++ Game. Let's discuss its uses, future intended uses, and its contents.

First, I would like to point out that a shooter game is not the best way to demonstrate how to describe a game world in a text file like this. The reason for this is that there are only a few types of game object and the most common one, invaders, are all lined up uniformly like soldiers on parade. They would actually be more efficiently described programmatically, perhaps in a nested for loop. However, the intention of this project was to show the ideas, rather than learn how to make a Space Invaders clone.

Take a look at the following text, which is a sample from the level1.txt file in the world folder:

[START OBJECT]
[NAME]invader[-NAME]
[COMPONENT]Standard Graphics[-COMPONENT]
[COMPONENT]Invader Update[-COMPONENT]...

Coding the GameObjectBlueprint class

Create a new header file in the Header Files/FileIO filter called GameObjectBlueprint.h and add the following code:

#pragma once
#include<vector>
#include<string>
#include<map>
using namespace std;
class GameObjectBlueprint {
private:
    string m_Name = "";
    vector<string> m_ComponentList;
    string m_BitmapName = "";
    float m_Width;
    float m_Height;
    float m_LocationX;
    float m_LocationY;
    float m_Speed;
    bool m_EncompassingRectCollider = false;
    string m_EncompassingRectColliderLabel = "";    
public:
    float getWidth();
    void setWidth(float width);
    float getHeight();
   ...

Coding the ObjectTags class

The way in which we describe the game objects in the level1.txt file needs to be precise because the BlueprintObjectParser class we will code after this class will be reading the text from the file and looking for matches. For example, the [START OBJECT] tag will trigger the start of a new object. If that tag is misspelled as, say, [START OBJECR], then the whole system falls apart and there will be all kinds of bugs, and even crashes when we run the game. To avoid this happening, we will define constant (programmatically unchangeable) string variables for all the tags we need to describe the game objects. We can use these string variables instead of typing something such as [START OBJECT] and have much less chance of making a mistake.

Create a new header file in the Header Files/FileIO filter called ObjectTags.h and add the following code:

#pragma once
#include <string>
using namespace std;
static class ObjectTags {
public:
   ...

Coding the BlueprintObjectParser class

This class will have the code that actually reads the text from the level1.txt file we have discussed. It will parse one object at a time, as identified by the start and end tags we saw previously.

Create a new header file in the Header Files/FileIO filter called BlueprintObjectParser.h and add the following code:

#pragma once
#include "GameObjectBlueprint.h"
#include <string>
using namespace std;
class BlueprintObjectParser {
private:
    string extractStringBetweenTags(
        string stringToSearch, string startTag, string endTag);
public:
    void parseNextObjectForBlueprint(
        ifstream& reader, GameObjectBlueprint& bp);
};

The extractStringBetweenTags private function will capture the content between two tags. The parameters are three string instances. The first string is a full line...

Coding the PlayModeObjectLoader class

This is the class that will pass GameObjectBlueprint instances to BlueprintObjectParser. When it gets the completed blueprint back, it will pass them to the GameObjectFactoryPlayMode class, which will construct the GameObject instance and pack it away in the vector instance. Once all the GameObject instances have been built and stored, responsibility will be handed to the LevelManager class, which will control access to the vector for other parts of the game engine. This is a very small class with just one function, but it links many other classes together. Refer to the diagram at the start of this chapter for clarification.

Create a new header file in the Header Files/FileIO filter called PlayModeObjectLoader.h and add the following code:

#pragma once
#include <vector>
#include <string>
#include "GameObject.h"
#include "BlueprintObjectParser.h"
#include "GameObjectFactoryPlayMode.h"
using namespace...

Coding the GameObjectFactoryPlayMode class

Now, we will code our factory, which will construct working game objects from the GameObject class and all the component related classes that we coded in the previous chapter. We will make extensive use of smart pointers, so we don't have to worry about deleting memory when we have finished with it.

Create a new header file in the Header Files/FileIO filter called GameObjectFactoryPlayMode.h and add the following code:

#pragma once
#include "GameObjectBlueprint.h"
#include "GameObject.h"
#include <vector>
class GameObjectFactoryPlayMode {
public:
    void buildGameObject(GameObjectBlueprint& bp, 
        std::vector <GameObject>& gameObjects);
};

The factory class has just one function, buildGameObject. We have already seen the code that calls this function in the previous code we wrote for the PlayModeObjectLoader class. The function...

Coding the GameObjectSharer class

This class will have two pure virtual functions that share GameObject instances with other classes.

Create a new header file in the Header Files/FileIO filter called GameObjectSharer.h and add the following code:

#pragma once
#include<vector>
#include<string>
class GameObject;
class GameObjectSharer {
public:
    virtual std::vector<GameObject>& getGameObjectsWithGOS() = 0;
    virtual GameObject& findFirstObjectWithTag(
             std::string tag) = 0;
};

The getGameObjectsWithGOS function returns a reference to the entire vector of GameObject instances. The findFirstObjectWithTag function returns just a single GameObject reference. We will see how we implement these functions when we inherit from GameObjectSharer when we code the LevelManager class next.

Briefly, before the LevelManager class, create a new...

Coding the LevelManager class

The LevelManager class is the connection between what we coded in Chapter 19, Game Programming Design Patterns – Starting the Space Invaders ++ Game, and everything we coded in this chapter. The ScreenManager class will have an instance of the LevelManager class, and the LevelManager class will instigate loading levels (using all the classes we have just coded) and share GameObject instances with any classes that need them.

Create a new header file in the Header Files/Engine filter called LevelManager.h and add the following code:

#pragma once
#include "GameObject.h"
#include <vector>
#include <string>
#include "GameObjectSharer.h"
using namespace std;
class LevelManager : public GameObjectSharer {
private:
    vector<GameObject> m_GameObjects;
    const std::string WORLD_FOLDER = "world";
    const std::string SLASH = "/"...

Updating the ScreenManager and ScreenManagerRemoteControl classes

Open the ScreenManagerRemoteControl.h file and uncomment everything so that the code is the same as the following. I have highlighted the lines that have been uncommented:

#pragma once
#include <string>
#include <vector>
#include "GameObject.h"
#include "GameObjectSharer.h"
using namespace std;
class ScreenManagerRemoteControl
{
public:
    virtual void SwitchScreens(string screenToSwitchTo) = 0;
    virtual void loadLevelInPlayMode(string screenToLoad) = 0;
    virtual vector<GameObject>& getGameObjects() = 0;
    virtual GameObjectSharer& shareGameObjectSharer() = 0;
};

Next, open ScreenManager.h, which implements this interface and uncomments all the commented-out code. The code in question is abbreviated and highlighted as follows:

...
#include "SelectScreen.h"
//#include...

Where are we now?

At this point, all the errors in our GameObject class, as well as all component-related classes, are gone. We are making good progress.

Furthermore, we can revisit the ScreenManager.h file and uncomment all the commented-out code.

Open ScreenManager.h and uncomment the #include directive, as follows:

//#include "LevelManager.h"

Change it to this:

#include "LevelManager.h"

Do the same for the functions from the ScreenManagerRemoteControl interface that are implemented in ScreenManager.h. They look like the following:

void ScreenManagerRemoteControl::
        loadLevelInPlayMode(string screenToLoad)
    {
        //m_LevelManager.getGameObjects().clear();
        //m_LevelManager.
            //loadGameObjectsForPlayMode(screenToLoad...

Summary

In this chapter, we have put in place a way to describe a level in a game and a system to interpret the description and build usable GameObject instances. The Factory pattern is used in many types of programming, not just game development. The implementation we have used is the simplest possible implementation and I encourage you to put the Factory pattern on your list of patterns to research and develop further. The implementation we have used should serve you well if you wish to build some deep and interesting games, however.

In the next chapter, we will finally make the game come to life by adding collision detection, bullet spawning, and the logic of the game itself.

lock icon The rest of the chapter is locked
You have been reading a chapter from
Beginning C++ Game Programming. - Second Edition
Published in: Oct 2019 Publisher: Packt ISBN-13: 9781838648572
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime}