Updating the game engine to use Thomas and Bob

In order to be able to run the game and see our new characters, we have to declare instances of them, call their spawn functions, update them each frame, and draw them each frame. Let's do that now.

Updating Engine.h to add an instance of Bob and Thomas

Open up the Engine.h file and add the highlighted lines of code, as shown in the following:

#pragma once 
#include <SFML/Graphics.hpp> 
#include "TextureHolder.h" 
#include "Thomas.h"
#include "Bob.h" 
 
using namespace sf; 
 
class Engine 
{ 
private: 
   // The texture holder 
   TextureHolder th; 
 
   // Thomas and his friend, Bob
   Thomas m_Thomas;
   Bob m_Bob; 
 
   const int TILE_SIZE = 50; 
   const int VERTS_IN_QUAD = 4; 
   ... 
   ... 

Now we have an instance of both Thomas and Bob, which are derived from PlayableCharacter.

Updating the input function to control Thomas and Bob

Now we will add the ability to control the two characters. This code will go in the input part of the code. Of course, for this project, we have a dedicated input function. Open up Input.cpp and add this highlighted code:

void Engine::input() 
{ 
   Event event; 
   while (m_Window.pollEvent(event)) 
   { 
      if (event.type == Event::KeyPressed) 
      { 
         // Handle the player quitting 
         if (Keyboard::isKeyPressed(Keyboard::Escape)) 
         { 
            m_Window.close(); 
         } 
 
         // Handle the player starting the game 
         if (Keyboard::isKeyPressed(Keyboard::Return)) 
         { 
            m_Playing = true; 
         } 
 
         // Switch between Thomas and Bob 
         if (Keyboard::isKeyPressed(Keyboard::Q)) 
         { 
            m_Character1 = !m_Character1; 
         } 
 
         // Switch between full and split-screen 
         if (Keyboard::isKeyPressed(Keyboard::E)) 
         { 
            m_SplitScreen = !m_SplitScreen; 
         } 
      } 
   } 
 
   // Handle input specific to Thomas
   if(m_Thomas.handleInput())
   {
     // Play a jump sound
   }

   // Handle input specific to Bob
   if(m_Bob.handleInput())
   {
     // Play a jump sound
   } 
} 

Note how simple the previous code is, as all the functionality is contained within the Thomas and Bob classes. All the code has to do is add an include directive for each of the Thomas and Bob classes. Then, within the input function, the code just calls the pure virtual handleInput functions on m_Thomas and m_Bob. The reason we wrap each of the calls in an if statement is because they return true or false based upon whether a new jump has just been successfully initiated. We will handle playing the jump sound effects in Chapter 15, Sound Spacialization and HUD.

Updating the update function to spawn and update the PlayableCharacter instances

This is broken down into two parts. First, we need to spawn Bob and Thomas at the start of a new level, and second, we need to update (by calling their update functions) each frame.

Spawning Thomas and Bob

We need to call the spawn functions of our Thomas and Bob objects in a few different places as the project progresses. Most obviously, we need to spawn the two characters when a new level begins. In the following chapter, as the number of tasks we need to perform at the beginning of a level increases, we will write a loadLevel function. For now, lets just call spawn on m_Thomas and m_Bob in the update function, as shown in the following highlighted code. Add the code, but keep in mind that this code will eventually be deleted and replaced:

void Engine::update(float dtAsSeconds) 
{ 
   if (m_NewLevelRequired)
   {
     // These calls to spawn will be moved to a new
     // loadLevel() function soon
     // Spawn Thomas and Bob
     m_Thomas.spawn(Vector2f(0,0), GRAVITY);
     m_Bob.spawn(Vector2f(100, 0), GRAVITY); 

     // Make sure spawn is called only once
     m_TimeRemaining = 10;
     m_NewLevelRequired = false;
   } 
 
   if (m_Playing) 
   { 
      // Count down the time the player has left 
      m_TimeRemaining -= dtAsSeconds; 
 
      // Have Thomas and Bob run out of time? 
      if (m_TimeRemaining <= 0) 
      { 
         m_NewLevelRequired = true; 
      } 
 
   }// End if playing 
       
} 

The previous code simply calls spawn and passes in a location in the game world, along with the gravity. The code is wrapped in an if statement that checks whether a new level is required. The actual spawning code will be moved to a dedicated loadLevel function, but the if condition will be part of the finished project. Also, m_TimeRemaining is set to a somewhat arbitrary 10 seconds.

Updating Thomas and Bob each frame

Next, we will update Thomas and Bob. All we need to do is call their update functions and pass in the time this frame has taken.

Add the following highlighted code:

void Engine::update(float dtAsSeconds) 
{ 
   if (m_NewLevelRequired) 
   { 
      // These calls to spawn will be moved to a new 
      // LoadLevel function soon 
      // Spawn Thomas and Bob 
      m_Thomas.spawn(Vector2f(0,0), GRAVITY); 
      m_Bob.spawn(Vector2f(100, 0), GRAVITY); 
 
      // Make sure spawn is called only once 
      m_NewLevelRequired = false; 
   } 
 
   if (m_Playing) 
   { 
      // Update Thomas
      m_Thomas.update(dtAsSeconds);

      // Update Bob
      m_Bob.update(dtAsSeconds); 
 
      // Count down the time the player has left 
      m_TimeRemaining -= dtAsSeconds; 
 
      // Have Thomas and Bob run out of time? 
      if (m_TimeRemaining <= 0) 
      { 
         m_NewLevelRequired = true; 
      } 
 
   }// End if playing 
       
} 

Now that the characters can move, we need to update the appropriate View objects to center around the characters and make them the center of attention. Of course, until we have some objects in our game world, the sensation of actual movement will not be achieved.

Add the highlighted code, as shown in the following snippet:

void Engine::update(float dtAsSeconds) 
{ 
   if (m_NewLevelRequired) 
   { 
      // These calls to spawn will be moved to a new 
      // LoadLevel function soon 
      // Spawn Thomas and Bob 
      m_Thomas.spawn(Vector2f(0,0), GRAVITY); 
      m_Bob.spawn(Vector2f(100, 0), GRAVITY); 
 
      // Make sure spawn is called only once 
      m_NewLevelRequired = false; 
   } 
 
   if (m_Playing) 
   { 
      // Update Thomas 
      m_Thomas.update(dtAsSeconds); 
 
      // Update Bob 
      m_Bob.update(dtAsSeconds); 
 
      // Count down the time the player has left 
      m_TimeRemaining -= dtAsSeconds; 
 
      // Have Thomas and Bob run out of time? 
      if (m_TimeRemaining <= 0) 
      { 
         m_NewLevelRequired = true; 
      } 
 
   }// End if playing 
       
   // Set the appropriate view around the appropriate character
   if (m_SplitScreen)
   {
     m_LeftView.setCenter(m_Thomas.getCenter());
     m_RightView.setCenter(m_Bob.getCenter());
   }
   else
   {
     // Centre full screen around appropriate character
     if (m_Character1)
     {
        m_MainView.setCenter(m_Thomas.getCenter());
     }
     else
     {
        m_MainView.setCenter(m_Bob.getCenter());
     }
   } 
} 

The previous code handles the two possible situations. First, the if(mSplitScreen) condition positions the left-hand view around m_Thomas and the right-hand view around m_Bob. The else clause that executes when the game is in fullscreen mode tests to see if m_Character1 is true. If it is, then the fullscreen view (m_MainView) is centered around Thomas, otherwise it is centered around Bob. You probably remember that the player can use the E key to toggle split screen mode and the Q key to toggle between Bob and Thomas, in fullscreen mode. We coded this in the input function of the Engine class, back in Chapter 12Abstraction and Code Management - Making Better Use of OOP.

Drawing Bob and Thomas

Make sure the Draw.cpp file is open and add the highlighted code, as shown in the following snippet:

void Engine::draw() 
{ 
   // Rub out the last frame 
   m_Window.clear(Color::White); 
 
   if (!m_SplitScreen) 
   { 
      // Switch to background view 
      m_Window.setView(m_BGMainView); 
      // Draw the background 
      m_Window.draw(m_BackgroundSprite); 
      // Switch to m_MainView 
      m_Window.setView(m_MainView);     
 
     // Draw thomas
     m_Window.draw(m_Thomas.getSprite());

     // Draw bob
     m_Window.draw(m_Bob.getSprite()); 
   } 
   else 
   { 
      // Split-screen view is active 
 
      // First draw Thomas' side of the screen 
 
      // Switch to background view 
      m_Window.setView(m_BGLeftView); 
      // Draw the background 
      m_Window.draw(m_BackgroundSprite); 
      // Switch to m_LeftView 
      m_Window.setView(m_LeftView); 
 
     // Draw bob
     m_Window.draw(m_Bob.getSprite());

     // Draw thomas
     m_Window.draw(m_Thomas.getSprite()); 
       
      // Now draw Bob's side of the screen 
 
      // Switch to background view 
      m_Window.setView(m_BGRightView); 
      // Draw the background 
      m_Window.draw(m_BackgroundSprite); 
      // Switch to m_RightView 
      m_Window.setView(m_RightView); 
 
     // Draw thomas
     m_Window.draw(m_Thomas.getSprite());

     // Draw bob
     m_Window.draw(m_Bob.getSprite()); 
             
   } 
 
   // Draw the HUD 
   // Switch to m_HudView 
   m_Window.setView(m_HudView); 
    
    
   // Show everything we have just drawn 
   m_Window.display(); 
} 

Notice that we draw both Thomas and Bob for the full screen, the left, and the right. Also note the very subtle difference in the way that we draw the characters in split screen mode. When drawing the left side of the screen, we switch the order the characters are drawn and draw Thomas after Bob. So, Thomas will always be on top on the left, and Bob on the right. This is because the player controlling Thomas is catered for on the left and Bob the right.

You can run the game and see Thomas and Bob in the center of the screen:

Drawing Bob and Thomas

If you press the Q key to switch focus from Thomas to Bob, you will see the View make the slight adjustment. If you move either of the characters left or right (Thomas with A and D, Bob with the arrow keys) you will see them move relative to each other.

Try pressing the E key to toggle between fullscreen and split-screen. Then try moving both characters again to see the effect. In the following screenshot, you can see that Thomas is always centered in the left-hand window and Bob is always centered in the right-hand window:

Drawing Bob and Thomas

If you leave the game running long enough, the characters will re-spawn in their original positions every ten seconds. This is the beginnings of the functionality we will need for the finished game. This behavior is caused by m_TimeRemaining going below zero and then setting the m_NewLevelRequired variable to true.

Also note that we can't see the full effect of movement until we draw the details of the level. In fact, although it can't be seen, both characters are continuously falling at 300 pixels per second. As the camera is centering around them every frame and there are no other objects in the game-world, we cannot see this downward movement.

If you want to demonstrate this to yourself, just change the call to m_Bob.spawn, as shown in the following code:

m_Bob.spawn(Vector2f(0,0), 0); 

Now that Bob has no gravitational effect, Thomas will visibly fall away from him. This is shown in the following screenshot:

Drawing Bob and Thomas

We will add some playable levels to interact with in the following chapter.

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

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