Game State Management in C ++

Original author: Antony Lewis
  • Transfer
Hello dear readers!

We are actively dispersing the third additional edition of the extremely successful book “Learning C ++ through Game Programming” . Therefore, today we offer you the translation of an interesting article on one of the narrow topics related to programming games in C ++. We also ask you to participate in the survey.

I first got the impression of the various states of the game many years ago when I watched one demo. It was not a “preview of the upcoming game,” but something old-school, “from scene.org .” One way or another, such demos completely imperceptibly passed from one effect to another. From some two-dimensional vortices, the game could switch immediately to the complex rendering of a three-dimensional scene. I remember, it seemed to me that to implement these effects, several separate programs are required at once.

Multiple states are important not only in demos, but also in any games. Any game starts with a splash screen, then opens a specific menu, after which the gameplay begins. When you are finally defeated, the game goes into a “game over” state, usually followed by a return to the menu. In most games, you can simultaneously be in two or more states. For example, during gameplay you can usually open a menu.

As a rule, multiple states are processed using a series of instructions.if
, switches and loops. The program starts with a splash screen and remains in this state until a key is pressed. Then the menu is displayed, it remains on the screen until you make a choice. Then begins the gameplay, working in the form of a cycle, until the game is over. At any time within the game cycle, the program should check what should be done - draw a menu or just display the next frame. In addition, the part of the program that is busy with event processing should check whether user input affects the state of the menu or the game as such. All this adds up to the main cycle, which is very difficult to track, which means it is difficult to debug and maintain.

What is a condition?

As mentioned above, the state is almost a separate program in the game. In each state, events are processed in their own way, their elements are drawn on the screen. In each state, its own events are processed, the game world is updated, and the next frame is drawn on the screen. So we have identified three methods that should be contained in our state class.

In addition, the game state should be able to load graphics and initialize itself, as well as get rid of unnecessary resources when the task is solved. It happens when we want to pause a state and resume it later. For example, we want to pause the game briefly to display a menu. So far, we have such a class of game state:

classCGameState
{public:
  voidInit();
  voidCleanup();
  voidPause();
  voidResume();
  voidHandleEvents();
  voidUpdate();
  voidDraw();
};


Such a scheme should fully meet all our needs related to the game state. It turns out a beautiful base class from which we can inherit others that correspond to each of the states of the game - splash screen, menu, gameplay, etc.

State Manager

Next, you need to develop a mechanism for managing these states - a state manager. In my code, the state manager is part of the game engine. Another programmer could create a separate class for the state manager, but it seemed to me that it would be easier to add it directly to the engine. Again, you can specifically find out what the game engine should do, and then write a class for it that will implement exactly these functions.

In our simple example, the engine only needs to initialize the SDL and perform the cleanup when everything is done. Since we are going to use the engine in the main cycle, we also need to check whether it continues to work, order it to complete work, process the usual events that occur in the process, update the game world, draw a sequence of frames.

The part of the engine that is associated with the state manager is, in essence, very simple. In order for some states to exist on top of others, you need to arrange them in the form of a stack. I am going to implement such a stack using a vector from STL. In addition, I will need methods for changing states, as well as for moving them up and down the stack.

So, the class of the game engine takes the following form:

classCGameEngine
{public:
  voidInit();
  voidCleanup();
  voidChangeState(CGameState* state);
  voidPushState(CGameState* state);
  voidPopState();
  voidHandleEvents();
  voidUpdate();
  voidDraw();
  boolRunning(){ return m_running; }
  voidQuit(){ m_running = false; }
private:
  // стек состоянийvector<CGameState*> states;
  bool m_running;
};


Writing some of these features will be very simple. , and - all of them will simply call the corresponding function from the state that is at the top of the stack. Since this often requires access to the data of the game engine, I will return to the class of game states and add a pointer to the class of the game engine as a parameter of each of these member functions. The final question is how to switch between states. How does the engine know when to switch from one state to another? No way. Only the current state knows about the need to switch to the next state. So, we will again return to the class of game states and add a function there to transition between them.HandleEvents()
Update()
Draw()




In this case, we will create an abstract base class, and make most of its members pure virtual functions. This ensures that the inherited class will implement them. Given all these changes, the finished class of game states will take the following form:

classCGameState
{public:
  virtualvoidInit()= 0;
  virtualvoidCleanup()= 0;
  virtualvoidPause()= 0;
  virtualvoidResume()= 0;
  virtualvoidHandleEvents(CGameEngine* game)= 0;
  virtualvoidUpdate(CGameEngine* game)= 0;
  virtualvoidDraw(CGameEngine* game)= 0;
  voidChangeState(CGameEngine* game,
                   CGameState* state){
    game->ChangeState(state);
  }
  protected: CGameState() { }
};


Now adding states to our game is extremely simple: we inherit the base class and define seven pure virtual functions. Since in any case, we will need no more than one instance of any particular state, let's implement them in the form of loners. If you are not familiar with the “loner” pattern, I’ll explain: it just allows you to make sure that the object exists exactly in one instance. To do this, the constructor is made protected, and then a function is made that returns a pointer to a static instance of this class.

So that you can imagine how this method can simplify the whole game, pay attention to the following listing, where the whole file is located :main.cpp


#include"gameengine.h"#include"introstate.h"intmain( int argc, char *argv[] ){
  CGameEngine game;
  // инициализация движка
  game.Init( "Engine Test v1.0" );
  // загрузка заставки
  game.ChangeState( CIntroState::Instance() );
  // основной циклwhile ( game.Running() )
  {
    game.HandleEvents();
    game.Update();
    game.Draw();
  }
  // очистка движка
  game.Cleanup();
  return0;
}


Files

This example describes three states: a screen saver that speaks against a black background, gameplay, and the game menu. For the duration of the menu, the gameplay is paused, and after closing the menu, it resumes. Each state corresponds to a simple background image.

stateman.zip - Source code, graphics and project files for Visual C ++
stateman.tar.gz - Source code, graphics and project files for Linux.

The sample code uses SDL. If you are new to SDL, check out my Getting Started with SDL tutorial . If you do not have SDL installed on your computer, then you will not be able to compile and run this example.

Resources

If you are just starting to learn C ++, then you should definitely get acquainted with the book “ Learning C ++ through Game Programming ”. This is a wonderful introduction to the C ++ programming language, as an example, the author uses simple games. For mid-level programmers, I recommend C ++ For Game Programmers . This book will help you deepen your knowledge of C ++. Finally, to learn the patterns properly, read the book Design Patterns, authored by The Gang of Four.

Only registered users can participate in the survey. Please come in.

Do you need a book "C ++ For Game Programmers"


Also popular now: