Hello again! In this video, we are going to look at sprites.
In the last video, we looked at shapes in SFML.
These are textures, images which have been loaded into the graphics card. Which are enclosed inside a rectangle,
known as a "texture rectangle".
But we can only have a few predefined images, which are provided by the library. With a sprite,
we can do something similar, but we can use any image that we want to.
For example, with this image, which looks rather like the Windows7 background, or one of them,
we could have a sprite which has this image as a texture, and then that is inside the texture rectangle.
So this is all in the graphics card, and it is all displayed very efficiently.
The advantage of this is that we can represents all the pixels which make up this image as a single
graphical entity.
And when this was first thought of, in the 1970's, this was a really powerful idea.
You could have these group of pixels which, if you like, float across the display without interacting
with the display.
So it looks a bit like a ghost.
And that is why it is called a sprite, because "sprite" is an archaic name for "ghost".
To create a spright,
you first need a texture. So you can create a SFML Texture object.
Then you call loadFromfile(), to load the image file into the graphics card. And this can often go wrong.
So it is probably a good idea to check the return value. Which, to be honest, I have not done.
But I should have!
So this can go wrong.
One possibility is that the image file is not valid, in some way.
Perhaps it was corrupted during download.
So it is always worth having a quick look at the image in a viewer, just to make sure it is all there.
The other possibility is that the image file is not where the program expects to find it.
If you are running from the command line, then you can just copy the image file into the folder where
you are running your program.
If you are using an Integrated Development Environment, then you may need to investigate and find out
where the environment thinks the file ought to be.
And of course, you can always provide a full path, saying which directory the file is in.
Once you have your texture, then you can create the sprite object, and then you call setTexture(), and
that will associate this texture with that sprite.
In our game, we are going to create several different sprites, to represent the different entities within
the game.
We are going to use an inheritance hierarchy to organize these.
So we are going to create a base class, entity, which will represent sprites.
This is going to be an abstract base class.
So we need to override methods in the child classes. And the child classes will be concrete sprite classes.
So the actual entities in the game.
So here is our entity class.
We need to include the SFML graphics header.
We have a sprite as a protected data member, so the child classes can see it, which is arguably not ideal
object-oriented design.
But let's leave it! Then we have some virtual functions.
These are pure virtual functions, so they have to be overridden in the child classes, and we cannot
create any objects of this entity class.
We have one member function which will update the entity.
So as we go from one frame to the next, the entity might change its position, or change its colour, or
shape. Or do all sorts of things.
We have a draw() member function, which will cause this entity to be drawn upon the window argument.
And because we are using virtual functions, we need to provide a virtual destructor.
We are going to start off with a very simple entity. This is just going to be the background for the
game.
So we are just going to load in an image file, which just sits there and does nothing.
We inherit from the entity class.
We have a texture member. We make this static.
So there is only one object in memory, regardless of how many objects there are of the class.
We have a constructor which will create an object at a given position on the screen. And then we override
the inherited pure virtual functions.
In the class definition,
we first of all initialize the static data member. In the constructor, we load the texture from file.
Then we set this to be the texture of the Sprite object, which we inherited from entity. And then we
search the initial position of the sprite.
In the update() function,
there is nothing to do, because the background does not need any updating.
And for the draw() member function, we can just delegate to the window.
So we ask the window object to draw the sprite for us.
And then the main() function is very similar to the one we had for the random walk.
Except, instead of having a creature object, we have a background object.
So we create the background object. We create the window, we set the frame limit. We start our
loop, clear the screen, check if we need to terminate the game. Then we update the background, then
we draw the background, and then finally we display the updated version of the screen for this frame.
And there it is. Not very exciting, but it is the first step on the road.
If you are using Visual Studio, then by default it will look for the image file in the project directory.
So this is where the headers and the source file are.
If you remember back to when when we copied the DLL's, those went into the directory where the program
executable is. And that is known as the target directory.
So if you'd rather have your image file there, you can do that. Go into configuration properties,
then debugging, and then set the working directory.
So by default, this is project directory, but if you change it to target, then this will look for
the image in the same directory as the executable and the DLL's, which I think is more logical.
Okay, so that is it for this video.
I will see you next time.
But until then, keep coding!