Before we can draw any graphics, we need to discuss the difference between sprites, textures, and images. In SFML, an image (sf::Image
) is exactly how it sounds; a collection of pixels in a 2D array. They can be easily manipulated on a per-pixel level, but they can’t be drawn to the screen. A texture (sf::Texture
) is an image that can be drawn, and lives in the graphics card instead of in RAM. Textures are not efficiently mutable however, and cannot have their pixels accessed individually. As such they are best created once and drawn repeatedly. They do not have any kind of position however, and so cannot be drawn without the help of another class, the sprite (sf::Sprite
).
Sprites are both drawable and transformable, so they can be drawn to the screen. Thus, to create our background, we’ll need both a texture, and a sprite. We could create both of these in GameStateStart
and maintain them there, however if we want to reuse the background in another game state we would have to load the texture and create the sprite all over again! Instead we will use a texture manager to store our textures, which will be part of the Game
class. Create a texture_manager.hpp
file:
#ifndef TEXTURE_MANAGER_HPP
#define TEXTURE_MANAGER_HPP
#include <SFML/Graphics.hpp>
#include <string>
#include <map>
class TextureManager
{
private:
/* Array of textures used */
std::map<std::string, sf::Texture> textures;
public:
/* Add a texture from a file */
void loadTexture(const std::string& name, const std::string &filename);
/* Translate an id into a reference */
sf::Texture& getRef(const std::string& texture);
/* Constructor */
TextureManager()
{
}
};
#endif /* TEXTURE_MANAGER_HPP */
Our texture manager will work by storing an std::map
that maps strings to textures; when we want a texture we will call the getRef
function with the name of the texture we want and the manager will return a reference to it. This way our textures will not be destroyed unless our manager is, we don’t have to use a bunch of pointers storing each individual texture, and our pointers will have easy to remember names instead of indices in an array. This method is not the best way to handle textures, but it is a simple way of doing it. In larger games (where the VRAM space is actually an issue) you would require ways of unloading textures so that only the required textures were loaded at any one time. For our purposes though, this will do fine. In a texture_manager.cpp
file, place
#include <SFML/Graphics.hpp>
#include <map>
#include <string>
#include "texture_manager.hpp"
void TextureManager::loadTexture(const std::string& name, const std::string& filename)
{
/* Load the texture */
sf::Texture tex;
tex.loadFromFile(filename);
/* Add it to the list of textures */
this->textures[name] = tex;
return;
}
sf::Texture& TextureManager::getRef(const std::string& texture)
{
return this->textures.at(texture);
}
In loadTexture
we take the name to give the texture and the path of the file it’s stored in. We then load the texture from that file and add it to the map with the name given. In getRef
we return a reference to the texture whose name is passed to the function. If you are not familiar, std::map
can be accessed like an array (as we did to add the texture) or by using the at
member function. The at
function provides bounds checking, and will throw an exception (error, in other words) if the specified element does not exist. As such, it’s only useful for reading or writing to existing elements, and not for creating new ones. That’s all for our texture manager! And unlike our state manager, we won’t be going back to it. Speaking of the state manager, it’s time to change game.hpp
and add our new manager!
#include "texture_manager.hpp"
class GameState;
class Game
{
private:
void loadTextures();
public:
std::stack<GameState*> states;
sf::RenderWindow window;
TextureManager texmgr;
sf::Sprite background;
void pushState(GameState* state);
As you can see we’ve added our texture manager, texmgr
, and we’ve declared a new private function called loadTextures
. loadTextures
will fill texmgr
with the textures we need. We’ve also finally created background
! Inside game.cpp
we will define the loadTextures
function
#include "game.hpp"
#include "game_state.hpp"
#include "texture_manager.hpp"
void Game::loadTextures()
{
texmgr.loadTexture("background", "media/background.png");
}
Using the loadTexture
function that we created, we add a new texture called "background"
from the media/background.png
file. Lastly we need to change the Game
constructor to call the loadTextures
function and set the texture of our background
Game::Game()
{
this->loadTextures();
this->window.create(sf::VideoMode(800, 600), "City Builder");
this->window.setFramerateLimit(60);
this->background.setTexture(this->texmgr.getRef("background"));
}
Using the getRef
function we set to the texture of the background
to the "background"
texture we created in loadTextures
. Finally, we can compile the code! If everything has gone well you should have a window with a lovely background, that can be resized and, even better, properly closed!
We now have most of the game engine structure out of the way, there’s just one or two things left. The first of which being the AnimationHandler
class. We’ll use this class to provide animation support to any sprites we create, by including an AnimationHandler
as a member variable in the class that contains the sprite. We could create a new AnimatedSprite
class using inheritance instead, but I prefer this method.
Before we begin, let’s discuss how the handler will work. We’re going to keep this simple, so each sprite will have its own texture file that will contain all the animation stages for its different animations. It would be more efficient (for the computer, not us!) to store multiple sprites in the same file, but that makes the code and asset creation more complex so we won’t do that. Anyway, we’ll split the texture file into a grid, where each frame of the same animation extends to the right, and each animation extends downwards.

The handler will have an update
function that takes a timestep dt
and moves the animation to the next frame if necessary. First let’s create an individual Animation
class, which the handler will store an array of. In animation_handler.hpp
…
#ifndef ANIMATION_HANDLER_HPP
#define ANIMATION_HANDLER_HPP
#include <SFML/Graphics.hpp>
#include <vector>
class Animation
{
public:
unsigned int startFrame;
unsigned int endFrame;
float duration;
Animation(unsigned int startFrame, unsigned int endFrame, float duration)
{
this->startFrame = startFrame;
this->endFrame = endFrame;
this->duration = duration;
}
unsigned int getLength() { return endFrame - startFrame + 1; }
};
#endif /* ANIMATION_HANDLER_HPP */
It’s such a simple class we could have used a struct
if not for the getLength
function. startFrame
and endFrame
are the zero-based indices of the start and stop frame in the grid, and duration
is the amount of time one frame should last for. I find that this is nicer to work with than a frequency or frames-per-second value. And now we create the handler itself (underneath Animation
and before that header guard).
class AnimationHandler
{
private:
/* Array of animations */
std::vector<Animation> animations;
/* Current time since the animation loop started */
float t;
int currentAnim;
public:
/* Add a new animation */
void addAnim(Animation& anim);
/* Update the current frame of animation. dt is the time since
* the update was last called (i.e. the time for one frame to be
* executed) */
void update(const float dt);
/* Change the animation, resetting t in the process */
void changeAnim(unsigned int animNum);
/* Current section of the texture that should be displayed */
sf::IntRect bounds;
/* Pixel dimensions of each individual frame */
sf::IntRect frameSize;
/* Constructor */
AnimationHandler()
{
this->t = 0.0f;
this->currentAnim = -1;
}
AnimationHandler(const sf::IntRect& frameSize)
{
this->frameSize = frameSize;
this->t = 0.0f;
this->currentAnim = -1;
}
};
#endif /* ANIMATION_HANDLER_HPP */
First up we have that std::vector
of Animation
s we mentioned. t
is the elapsed time since the animation started or looped, and is used to determine when the next frame should occur. Every time update
is called we will increase t
by dt
to keep track of the time. currentAnim
is the (vertical) index in the grid or the (horizontal) index in the std::vector
used to keep track of which animation is running. The next three functions are self-explanatory (or are with the comments), but then we have some SFML code.
An sf::IntRect
is a rectangle with integers for its start coordinate, its width, and its height. Since we’re using a single texture for all of the animations, we use an sf::IntRect
to keep track of which section of the texture the sprite should show. Later we’ll tell the sprite to use that section of the texture by using sf::Sprite
‘s setTextureRect
member function. The constructors are rather straightforward, so we’ll move on to writing the algorithms for the handler to use. In animation_handler.cpp
we first create the update
function
#include <SFML/Graphics.hpp>
#include <vector>
#include "animation_handler.hpp"
void AnimationHandler::update(const float dt)
{
if(currentAnim >= this->animations.size() || currentAnim < 0) return;
float duration = this->animations[currentAnim].duration;
/* Check if the animation has progessed to a new frame and if so
* change to the next frame */
if(int((t + dt) / duration) > int(t / duration))
{
/* Calculate the frame number */
int frame = int((t + dt) / duration);
/* Adjust for looping */
frame %= this->animations[currentAnim].getLength();
/* Set the sprite to the new frame */
sf::IntRect rect = this->frameSize;
rect.left = rect.width * frame;
rect.top = rect.height * this->currentAnim;
this->bounds = rect;
}
/* Increment the time elapsed */
this->t += dt;
/* Adjust for looping */
if(this->t > duration * this->animations[currentAnim].getLength())
{
this->t = 0.0f;
}
return;
}
Firstly, we don’t update if the current animation does not exist. The next line just saves us some writing every time we want to know the animation’s duration. If each animation takes duration
seconds, then from t
between 0 and duration
, we’re on frame 0, t
between duration
and 2*duration
we are on frame 1, t
between 2*duration
and 3*duration
we are on frame 2, and so on.
If we divide t
by duration
them frame 0 is between 0 and 1, frame 1 is between 1 and 2, and so on. Thus if we round t / duration
down (i.e. cast it to an integer) we get what frame of the animation is playing. So if the new time t+dt
gives a different answer using that formula to t
we need to advance the animation to the next frame. Can you see when this wouldn’t work? So long as dt < duration
, we’ll only ever advance one frame at a time, but if dt
is too large we should skip a frame of animation! That’s why we calculate the new frame on the next line, instead of just incrementing the frame number.

This brings us to another problem, however. If we have a 4 frame animation (0-3) then when we are on frame 3 we should not go to frame 4 or 5 or higher (depending on dt
), we should loop back to frame 0, 1 or whatever is next! To do this we simply take the modulus of the frame with the number of frames to ensure that the animation loops correctly. This shows a limitation of our animation handler: every animation loops, and nothing happens at the end.
We then compute the rectangle of the texture that the sprite should show using the pattern mentioned before (frames move to the right). Regardless of whether the frame has changed or not we advance the elapsed time by the timestep and then ensure that the elapsed time resets round to 0 if it is greater than the duration of the animation. By setting it to 0 instead of taking the modulus (which is awkward with a floating point value) we may introduce a slight jitter at the end of the animation, but this is only noticeable if multiple frames are being jumped at once. Adding the last two functions,
void AnimationHandler::addAnim(Animation& anim)
{
this->animations.push_back(anim);
return;
}
void AnimationHandler::changeAnim(unsigned int animID)
{
/* Do not change the animation if the animation is currently active or
* the new animation does not exist */
if(this->currentAnim == animID || animID >= this->animations.size() ||
animID < 0) return;
/* Set the current animation */
this->currentAnim = animID;
/* Update the animation bounds */
sf::IntRect rect = this->frameSize;
rect.top = rect.height * animID;
this->bounds = rect;
this->t = 0.0;
return;
}
addAnim
just adds the specified animation to the animation std::vector
, and changeAnim
sets the current animation to the new one (if the new one is valid) before setting the bounds rectangle to the first frame and resetting the elapsed time. And with that our game engine is essentially complete! In part four, we’ll move back and add some more to GameStateEditor
before moving on to the Tile
s.