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.
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.
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.
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;
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.
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.
3.142.197.95