In this tutorial project, we will build a fully working and functional but simple C++ game engine. All that the game engine will do is allow the player to control one object moving left and right on a background, however, once you have completed the project you will be able to use the example game object class, Bob as a blueprint for adding as many other objects as you like. The tutorial won’t cover collision detection as that was discussed in the pong game and once you have read that tutorial it would be trivial to add this feature into the update function that we will be writing. Note that this really is a “simple” engine and future tutorials will expand and evolve this code to add more features. The long-term shortcomings of the engine are discussed at the end. What you do get with this simple game engine is a level of abstraction that will allow you to build a relatively complex game, without ending up in a tangled mess of code.
[widgets_on_pages id=”udemy_advert_cpp_1″][widgets_on_pages id=”udemy_code_details”]

Creating the simple game engine project in Visual Studio

To get started we need to create a new project in Visual Studio, complete with all the required properties to work with SFML. If you haven’t completed the Building your first SFML game project you will need to do that first in order for the next steps to work.

These next steps set up our new SFML C++  game engine project.

  1. Open Visual Studio and from the main menu choose File | New Project. In the left-hand menu click C++. Select the HelloSFML template and name your project Simple Game Engine.
  2. Now click OK.
  3. Right-click the HelloSFML.cpp file under the Source Files heading from the right-hand Solution Explorer window. Choose Rename and rename the file to Main. This is a more appropriate name as this will indeed be the  source file containing the main function.
  4. Open Main.cpp by double-clicking it. Now delete all of its contents as we will be starting with an empty file.
  5. Copy & paste the SFML .dll files from the YOUR_DRIVE:\SFML\bin to YOUR_DRIVE:\Visual Studio Stuff\Projects\Simple Game Engine\Simple Game Engine. Obviously, if you configured your development environment slightly differently then your folder names will vary.

Now we can get coding. All the code is on the page and all the assets you need are made available from this page, but please take a look at the bonus download offer.

[sociallocker id=”14566″]

Thanks for the love! Here is the link to the simple-game-engine-c-bonus-download

Click to download the  bonus!

Click to download the bonus!

 

[/sociallocker]

Also, note that all the bonus downloads for this and every future tutorial is available on an exclusive download area for my Patreon subscribers.

patreon-medium-banner

Planning the simple game engine

One of the problems that we had in the Pong game was how long and unwieldy the code was. If you consider that Pong is perhaps the simplest game it is possible to make then we need to think about improving the structure of our code. Object oriented programming in C++ allows us to break our code up into logical and manageable chunks called classes.

We will make a big improvement to the manageability of the code in this project compared to the Pong game with the introduction of an Engine class. The Engine class will have three
private functions. They are input, update, and draw. This should sound very familiar if you have done the Pong project. Each of these functions will hold a part of the code that was previously all in the main function. Each of these functions will be in a code file of its own, Input.cpp, Update.cpp, and Draw.cpp respectively.

There will also be one public function in the Engine class, which can be called with an instance of Engine which will be declared in Main.cpp. This function is appropriately called start and will be responsible for calling input, update, and draw, once for each frame of the game:

In addition, because we have abstracted the game loop to the Engine class, we can also move virtually all of the variables from main and make them members of Engine. All we need to do to get our game engine revving is create an instance of Engine and call its start function from main. Here is what the super-simple main function will look like when we are done. Don’t code it just yet, though.

int main()
{
	// Declare an instance of Engine
	Engine engine;
	// Start the engine
	engine.start();
	// Quit the game
	return 0;
}

If you want to go way beyond this tutorial, please take a look at these three related books.

[widgets_on_pages id=”bcgp_cfgp_gpp”]

Now we can build the classes that we discussed.

Coding the Bob class

Bob is a simple class that will represent the player’s controllable character. It can only move left and right but when you see the code you will see that it would be trivial to extend this functionality. More significant, however, is that the Bob class can be easily copied and modified to become just about any type of game object you like. Simply apply the appropriate texture in the constructor, behaviour in the  update function then declare, update and draw them in exactly the same way that we will soon see. If you want dozens, hundreds, or more of your new game object then just declare an entire array of them.

Bob.h

First, let’s code the header file of the Bob class.

Right-click Header Files in the Solution Explorer and select Add | New Item…. In the Add New Item window, highlight (by left-clicking) Header File (.h) and then in the Name field, type Bob.h. Finally, click the Add button. We are now ready to code the header file for the Bob class.

#pragma once
#include <SFML/Graphics.hpp>

using namespace sf;

class Bob
{
	// All the private variables can only be accessed internally
private:

	// Where is Bob
	Vector2f m_Position;

	// Of course we will need a sprite
	Sprite m_Sprite;

	// And a texture
	// Bob has been working out and he is now a bit more muscular than before
	// Furthermore, he fancies himself in lumberjack attire
	Texture m_Texture;

	// Which direction(s) is the player currently moving in
	bool m_LeftPressed;
	bool m_RightPressed;

	// Bob's speed in pixels per second
	float m_Speed;

	// Public functions
public:

	// We will set Bob up in the constructor
	Bob();

	// Send a copy of the sprite to main
	Sprite getSprite();

	// Move Bob in a specific direction
	void moveLeft();

	void moveRight();

	// Stop Bob moving in a specific direction
	void stopLeft();

	void stopRight();

	// We will call this function once every frame
	void update(float elapsedTime);

};

In the previous code, we declare objects of type Texture and Sprite. You will see in the next code how we associate these with each other so that whenever we do anything with the Sprite it will be adorned by this rather handsome Bob character. Notice also the is a Vector2f called m_Position which can be manipulated and will be used to set Bob’s current position on the screen.

bob

Right-click and select Save Image as… to download the previous image.

There are also two Boolean variables which will be set and unset in order to communicate with the update function which way Bob should be moving, if at all. There is also an int called m_Speed which will be assigned a value which determines how fast Bob will move.

The public section of the class has a getSprite function to return a copy of the Sprite object to the draw function where it is required in order to draw Bob to the screen. There are four setter functions moveLeft, moveRight, stopLeft, and stopRight. These functions will be called from the input function and are used to set the values of the two Booleans that control the movement.

The final function in the Bob.h file is the update function. You can see it takes a float variable. This function will be called each and every frame from the update function of the Engine class and will update Bob’s position by the right amount in the appropriate direction each frame.

Bob.cpp

Now we can code the definitions for all the functions we have just seen.

Right-click Source Files in the Solution Explorer and select Add | New Item…. In the Add New Item window, highlight (by left-clicking) C++ File (.cpp) and then in the Name field, type Bob.cpp. Finally, click the Add button. We are now ready to code the .cpp file for the Bob class.

#include "stdafx.h"
#include "bob.h"

Bob::Bob()
{
	// How fast does Bob move?
	m_Speed = 400;

	// Associate a texture with the sprite
	m_Texture.loadFromFile("bob.png");
	m_Sprite.setTexture(m_Texture);		

	// Set the Bob's starting position
	m_Position.x = 500;
	m_Position.y = 800;

}

// Make the private spite available to the draw() function
Sprite Bob::getSprite()
{
	return m_Sprite;
}

void Bob::moveLeft()
{
	m_LeftPressed = true;
}

void Bob::moveRight()
{
	m_RightPressed = true;
}

void Bob::stopLeft()
{
	m_LeftPressed = false;
}

void Bob::stopRight()
{
	m_RightPressed = false;
}

// Move Bob based on the input this frame,
// the time elapsed, and the speed
void Bob::update(float elapsedTime)
{
	if (m_RightPressed)
	{
		m_Position.x += m_Speed * elapsedTime;
	}

	if (m_LeftPressed)
	{
		m_Position.x -= m_Speed * elapsedTime;
	}

	// Now move the sprite to its new position
	m_Sprite.setPosition(m_Position);	

}

In the constructor function, Bob, above we set m_Speed to 400 which means Bob would cross a 1920 pixel screen width in around 5 seconds. We load the bob.png image into the Texture object and we associate it with the Sprite object. We also set the starting horizontal and vertical positions for Bob by initializing m_Position.x and m_Position.y. It is worth noting that depending on the resolution of your monitor you might want to adjust these values.

The getSprite function as expected returns a copy of m_Sprite. The four movement related functions play with our two Booleans. The ...Pressed functions set the appropriate Boolean to true and the stop... functions set the same to false. We can now see how all these ties together in the update function.

The update function starts with two if statements. The first checking whether m_RightPressed is true and the second detecting whether m_LeftPressed is true. Inside each of the if blocks m_Speed multiplied by elapsedTime is added or subtracted from m_Position.x. The elapsedTime variable is calculated and passed in by the start function of the Engine class. We will code that next.

As a final step for this class add bob.png to the Simple Game Engine/Simple Game Engine folder.

Coding the Engine class

The Engine class is what controls everything else. Once it is started in the main function which runs when the app runs it will hold control right up until the player quits the game. Let’s code it now, it is quite straightforward.

Engine.h

Right-click Header Files in the Solution Explorer and select Add | New Item…. In the Add New Item window, highlight (by left-clicking) Header File (.h) and then in the Name field, type Engine.h. Finally, click the Add button. We are now ready to code the header file for the Engine class. Add the following code.

#pragma once
#include <SFML/Graphics.hpp>
#include "Bob.h";

using namespace sf;

class Engine
{
private:

	// A regular RenderWindow
	RenderWindow m_Window;	

	// Declare a sprite and a Texture for the background
	Sprite m_BackgroundSprite;
	Texture m_BackgroundTexture;

	// An instance of Bob
	Bob m_Bob;

	// Private functions for internal use only
	void input();
	void update(float dtAsSeconds);
	void draw();

public:
	// The Engine constructor
	Engine();

	// start will call all the private functions
	void start();

};

Let’s talk about the variables first. There is an SFML RenderWIndow which is what we use to display everything. There is a Sprite and a Texture which will be used to draw a pretty background image. We declare an instance of the Bob class that we just finished coding a moment ago. There is also the three private functions, input, update, and draw. They are private because we don’t need or want to call them from outside of the Engine class.

Next, the code declares two public functions. The constructor called Engine will set the instance of the class up ready go and the start function is the function that will continuously call the input, update and draw functions, in that order, every frame.

Engine.cpp

In the Engine.cpp file, we will put the constructor ( Engine) and the public start function. All the rest of the functions will go in their own .cpp file, with a name that makes it clear what function goes where. This will not be a problem for the compiler as long as we add the appropriate include directive ( #include "Engine.h") at the top of all the files that contain function definitions from the Engine class.

Let’s get started by coding Engine and start in Engine.cpp. Right-click Source Files in the Solution Explorer and select Add | New Item…. In the Add New Item window, highlight (by left-clicking) C++ File (.cpp) and then in the Name field, type Engine.cpp. Finally, click the Add button. We are now ready to code the .cpp file for the Engine class.

#include "stdafx.h"
#include "Engine.h"

Engine::Engine()
{
	// Get the screen resolution and create an SFML window and View
	Vector2f resolution;
	resolution.x = VideoMode::getDesktopMode().width;
	resolution.y = VideoMode::getDesktopMode().height;

	m_Window.create(VideoMode(resolution.x, resolution.y),
		"Simple Game Engine",
		Style::Fullscreen);

	// Load the background into the texture
	// Be sure to scale this image to your screen size
	m_BackgroundTexture.loadFromFile("background.jpg");

	// Associate the sprite with the texture
	m_BackgroundSprite.setTexture(m_BackgroundTexture);

}

void Engine::start()
{
	// Timing
	Clock clock;

	while (m_Window.isOpen())
	{
		// Restart the clock and save the elapsed time into dt
		Time dt = clock.restart();

		// Make a fraction from the delta time
		float dtAsSeconds = dt.asSeconds();

		input();
		update(dtAsSeconds);
		draw();
	}
}

The constructor function gets the screen resolution and then opens a fullscreen window with m_Window.create. Finally, in the constructor, we load the image into the Texture and associate it with the Sprite.

You need to add an image for the background. Here is a great place to get lots of images with varying sizes.

http://www.spyderonlines.com/wallpapers/game-background-images.html

Use an image editor like GIMP or Photoshop to scale the background to the same resolution as your screen. Rename the image as background.jpg. Add the backgroung.jpg image to the Simple Game Engine/Simple Game Engine folder.

The other function in the code above is the start function. This function contains just a continuous while loop that will only break when the window ( m_Window) is closed. We will give the player the ability to do this in the input function soon.

The start function then calculates how long the previous frame took, stores the answer as a float called dtAsSeconds then calls input, update and draw. Notice that dtAsSeconds get passed to update that will require the value because it will be calling the update function of the Bob instance.

I hope you agree that is extremely simple. It is arguably easier than have to handle the sprawl of code that we did in the Pong game.

Coding the three stages of the game loop

[widgets_on_pages id=”udemy_advert_cpp_2″][widgets_on_pages id=”udemy_code_details”]
The next three functions will be coded in their own individual files but don’t forget that they are part of the Engine class and were declared in the Engine.h file. At the top of each file, we will add the directive #include "Engine.h" so that Visual Studio knows what we are doing.

Handling player input

The first of these functions we will code is input.

Right-click Source Files in the Solution Explorer and select Add | New Item…. In the Add New Item window, highlight (by left-clicking) C++ File (.cpp) and then in the Name field, type Input.cpp. Finally, click the Add button. Here is the code for Input.cpp.

#include "stdafx.h"
#include "Engine.h"

void Engine::input()
{
	// Handle the player quitting
	if (Keyboard::isKeyPressed(Keyboard::Escape))
	{
		m_Window.close();
	}

	// Handle the player moving
	if (Keyboard::isKeyPressed(Keyboard::A))
	{
		m_Bob.moveLeft();
	}
	else
	{
		m_Bob.stopLeft();
	}

	if (Keyboard::isKeyPressed(Keyboard::D))
	{
		m_Bob.moveRight();
	}
	else
	{
		m_Bob.stopRight();
	}						

}

In the input function, we use the SFML Keyboard::isKeyPressed constants to verify which keyboard keys are currently pressed. If the Escape key is pressed m_Window is closed. This has the effect of breaking out of the while loop in the start function. This causes execution to go back to the main function and the game will close.

If the A or D keys are pressed we call the appropriate move... function on our Bob instance. Notice that when the A or D keys are not pressed the two else clauses call the corresponding stop... functions. This is the final piece of the puzzle that enables the player to move Bob left and right.

Updating the game objects

Next, we come to the super-simple update function. Any new objects you create should have their own update functions called from here. You should also add collision detection to the end of this function.

Right-click Source Files in the Solution Explorer and select Add | New Item…. In the Add New Item window, highlight (by left-clicking) C++ File (.cpp) and then in the Name field, type Update.cpp. Finally, click the Add button. Here is the code for Update.cpp.

#include "stdafx.h"
#include "Engine.h"

using namespace sf;

void Engine::update(float dtAsSeconds)
{
	m_Bob.update(dtAsSeconds);
}

As we only have one game object we call m_Bob.update and pass in dtAsSeconds and then we are finished with this function.

Drawing the scene

This is the final function of the Engine class.

Right-click Source Files in the Solution Explorer and select Add | New Item…. In the Add New Item window, highlight (by left-clicking) C++ File (.cpp) and then in the Name field, type Draw.cpp. Finally, click the Add button. Here is the code for Draw.cpp.

#include "stdafx.h"
#include "Engine.h"

void Engine::draw()
{
	// Rub out the last frame
	m_Window.clear(Color::White);

	// Draw the background
	m_Window.draw(m_BackgroundSprite);
	m_Window.draw(m_Bob.getSprite());

	// Show everything we have just drawn
	m_Window.display();
}

In the draw function, there is nothing that we didn’t see in the Pong game. First, we clear the screen with the clear function. Next, we draw the background followed by Bob. The things to note here are that we must draw the background first so Bob is drawn on top and that when we draw Bob we call the getSprite function which gets a copy of the Sprite in the Bob class.

Getting the engine started with Main

This is the shortest main function out of all the C++ tutorials on this site.

Add the code we have already glimpsed at to Main.cpp. Here it is again in its entirety.

#include "stdafx.h"
#include "Engine.h"

int main()
{
	// Declare an instance of Engine
	Engine engine;

	// Start the engine
	engine.start();

	// Quit in the usual way when the engine is stopped
	return 0;
}

First, we declare an instance of Engine, call the start function and execution will move to the Engine class until the player quits by pressing the Escape key.

You can now run the game and move Bob left and right with the A and D keyboard keys.

Use the A and S keys to move

Use the A and D keys to move

Conclusion, flaws & what next?

When you added the background and the player we had to adjust the code to suit your specific resolution. This is obviously not suitable for a game you want to release on Steam. It is quite easy to fix this flaw using the SFML View class. I didn’t add this feature because at some point I had to stop adding features. The View class uses OpenGL to make independent drawing layers and can be used to make some really cool effects like split-screen gameplay, mini maps, and levels that can rotate and zoom. I will publish a whole working game that uses these features soon.

Another obvious flaw that you probably spotted was that the game engine doesn’t handle for different game states like paused, home screen and playing. You can quickly cater for this by creating some Booleans to represent each state. Perhaps isPlaying, isPaused etc. This isn’t the best way of doing it but as I said before I had to draw the line at the features to include in what should be a simple tutorial. We will see a neater and more efficient way to handle states in a forthcoming full-game project, most likely a platformer.

In addition, any game you are going to release to the world will have more features like sound, music, artificial intelligence, saving of high scores and more besides. Most of these features can be bolted onto this engine. It is true, unfortunately, that eventually you will end up with code sprawl again but the purpose of the tutorial is meant to be instructional as well as practical and when we dive into something more complicated this engine should serve as good preparation and starting point.

I hope you had some fun with this simple C++ game engine. Please ask questions and leave comments if you would like to.