A matter of state

Before we move on to actually rendering 2D items, we need to add a state machine to our game. Just as we did in RoboRacer2D, we need to be able to handle several different game states: displaying the splash screen, loading resources, displaying the main menu, running the game, pausing the game, and game over.

Tip

Don't let the word state confuse you as it is used in several different ways in computer programming. We just finished a section on render state, learning how to push and pop this state from the OpenGL stacks. Now, we are talking about game state, which you can think of as the different modes that our game is in. A framework that handles different game states is known as a state machine.

Adding the state machine

Fortunately, we will be able to take some of the code directly from RoboRacer2D. Open up RoboRacer2D.cpp. You can do this from inside the SpaceRacer3D project by clicking File, then Open, and then browsing to RoboRacer2D.cpp. This will allow you to copy information from RoboRacer2D.cpp and paste it into SpaceRacer3D.

Tip

Opening a file loads it into the current project, but it does not add the file to the current project. However, you want to be careful because if you make changes to the file and save them, the original source file will be modified.

Copy the GameState enum and then paste it at the top of SpaceRacer3D.cpp just after the header files:

enum GameState
{
  GS_Splash,
  GS_Loading,
  GS_Menu,
  GS_Credits,
  GS_Running,
  GS_NextLevel,
  GS_Paused,
  GS_GameOver,
};

We will be copying more code from RoboRacer2D.cpp, so go ahead and leave it open.

Next, we need to create a global game state variable. Add the following definition in the global variables section of SpaceRacer3D.cpp:

GameState gameState;

The gameState variable will store the current game state.

Getting ready for a splash

Just as we did in RoboRacer2D, we are going to start our game with a splash screen. The splash screen will be quickly loaded before any other resources, and it will be displayed for a few seconds before moving on to loading the game assets and starting the game.

Just under the definition for gameState, add the following lines:

float splashDisplayTimer;
float splashDisplayThreshold;

These two variables will handle the splash screen timing. Our splash screen is going to be one of the many 2D assets that we load into the game. Let's go ahead and define some variables for our 2D assets. Add the following lines of code to the global variables section of SpaceRacer3D.cpp:

Sprite* splashScreen;
Sprite* menuScreen;
Sprite* creditsScreen;
Sprite* playButton;
Sprite* creditsButton;
Sprite* exitButton;
Sprite* menuButton;
Sprite* gameOverScreen;
Sprite* replayButton;

You will notice that all of our 2D assets are being handled as Sprites, a class that we borrowed from RoboRacer2D.

While we are here, let's add the following two lines as well:

float uiTimer;
const float UI_THRESHOLD = 0.1f;

These two variables will be used to add a timing buffer to mouse clicks. Now, let's create a function to load the splash screen. Add the following function to SpaceRacer3D.cpp somewhere before the StartGame function:

void LoadSplash()
{
  gameState = GameState::GS_Splash;
  splashScreen = new Sprite(1);
  splashScreen->SetFrameSize(screenWidth, screenHeight);
  splashScreen->SetNumberOfFrames(1);
  splashScreen->AddTexture("resources/splash.png", false);
  splashScreen->IsActive(true);
  splashScreen->IsVisible(true);
  splashScreen->SetPosition(0.0f, 0.0f);
}

This code is exactly the same as the code from RoboRacer2D. In fact, feel free to copy and paste it directly from RoboRacer2D.cpp.

Remember: we set up our 2D orthographic viewport to exactly replicate the settings that we had in RoboRacer2D. This allows us to use the same exact code and positions for our 2D objects. Even better, it allows us to use the Sprite class from RoboRacer2D without changing any of the code.

Tip

The LoadSplash function loads a file from the game resource folder called splash.png. You can download this file and all of the other 2D resources that are used in this chapter, from the book website. You should place all of them in a folder named resources under the same folder as the game source code. You also have to remember to add these resources to the Resource Files folder in the solution by right-clicking on Resource Files, then choosing Add Existing Item, then browsing to the resources folder and adding all of the items in that folder.

Next, we need to modify the StartGame function to load the splash screen. Move to the StartGame function add the following code:

LoadSplash();
uiTimer = 0.0f;
splashDisplayTimer = 0.0f;
splashDisplayThreshold = 5.0f;

The first thing that we do is call the LoadSplash function, which sets the game state to GS_Splash, and then loads the splash page. Next, we have to update and render the splash page. Move to the Update function and modify it so that it looks like this:

void Update(const float p_deltaTime)
{
 switch (gameState)
 {
 case GameState::GS_Splash:
 case GameState::GS_Loading:
 {
  splashScreen->Update(p_deltaTime);
 }
 break;
 case GameState::GS_Running:
 {
  inputManager->Update(p_deltaTime);
  ProcessInput(p_deltaTime);
  ship->Update(p_deltaTime);
  ship->SetVelocity(ship->GetVelocity() + ship->GetVelocity()*p_deltaTime/10.0f);
  speed = ship->GetVelocity() * 1000;
  if (maximumSpeed < speed)
  {
   maximumSpeed = speed;
  }
  missionTime = missionTime + p_deltaTime * 100.0f;
  CheckCollisions();
  if (ship->GetPosition().z > 10.0f)
  {
   gameState = GS_GameOver;
   menuButton->IsActive(true);
   gameOverScreen->IsActive(true);
  }
 }
 break;
 case GameState::GS_GameOver:
 {
  gameOverScreen->Update(p_deltaTime);
  replayButton->IsActive(true);
  replayButton->Update(p_deltaTime);
  exitButton->IsActive(true);
  exitButton->Update(p_deltaTime);
  inputManager->Update(p_deltaTime);
  ProcessInput(p_deltaTime);
  ship->Update(p_deltaTime);
  CheckCollisions();
 }
 break;
 }
}

The only real change is that we implemented part of the state machine. You will notice how we moved all of the code to run the game under the GS_Running game state case. Next, we added an update for the splash screen game state. We will eventually modify the Update function to handle all of the game states, but we have some more work to do yet.

Now, we are ready to render the splash screen. Move to the Render2D function and add the following line of code between the Enable2D and Disable2D calls:

splashScreen->Render();

At this point, if you run the game, you will see a splash screen render. The game will not move beyond the splash screen because we haven't added the code to move on yet.

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

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