WEBVTT

00:00.120 --> 00:03.240
Hello again! In this video, we are going to look at sprites.

00:04.530 --> 00:07.860
In the last video, we looked at shapes in SFML.

00:08.400 --> 00:15.030
These are textures, images which have been loaded into the graphics card. Which are enclosed inside a rectangle,

00:15.360 --> 00:16.920
known as a "texture rectangle".

00:17.520 --> 00:22.590
But we can only have a few predefined images, which are provided by the library. With a sprite,

00:22.590 --> 00:26.040
we can do something similar, but we can use any image that we want to.

00:28.120 --> 00:33.220
For example, with this image, which looks rather like the Windows7 background, or one of them,

00:34.300 --> 00:40.330
we could have a sprite which has this image as a texture, and then that is inside the texture rectangle.

00:41.050 --> 00:44.110
So this is all in the graphics card, and it is all displayed very efficiently.

00:46.090 --> 00:51.640
The advantage of this is that we can represents all the pixels which make up this image as a single

00:51.640 --> 00:52.870
graphical entity.

00:53.350 --> 00:58.330
And when this was first thought of, in the 1970's, this was a really powerful idea.

00:58.870 --> 01:04.240
You could have these group of pixels which, if you like, float across the display without interacting

01:04.240 --> 01:05.140
with the display.

01:05.770 --> 01:07.010
So it looks a bit like a ghost.

01:07.630 --> 01:12.370
And that is why it is called a sprite, because "sprite" is an archaic name for "ghost".

01:15.090 --> 01:16.050
To create a spright,

01:16.050 --> 01:20.790
you first need a texture. So you can create a SFML Texture object.

01:21.390 --> 01:26.820
Then you call loadFromfile(), to load the image file into the graphics card. And this can often go wrong.

01:26.820 --> 01:31.750
So it is probably a good idea to check the return value. Which, to be honest, I have not done.

01:32.160 --> 01:32.820
But I should have!

01:34.500 --> 01:35.400
So this can go wrong.

01:35.610 --> 01:38.970
One possibility is that the image file is not valid, in some way.

01:39.300 --> 01:41.550
Perhaps it was corrupted during download.

01:42.150 --> 01:45.900
So it is always worth having a quick look at the image in a viewer, just to make sure it is all there.

01:47.040 --> 01:51.210
The other possibility is that the image file is not where the program expects to find it.

01:51.960 --> 01:55.980
If you are running from the command line, then you can just copy the image file into the folder where

01:55.980 --> 01:57.150
you are running your program.

01:57.900 --> 02:03.510
If you are using an Integrated Development Environment, then you may need to investigate and find out

02:03.510 --> 02:05.610
where the environment thinks the file ought to be.

02:06.870 --> 02:11.520
And of course, you can always provide a full path, saying which directory the file is in.

02:13.290 --> 02:19.710
Once you have your texture, then you can create the sprite object, and then you call setTexture(), and

02:19.710 --> 02:23.100
that will associate this texture with that sprite.

02:24.210 --> 02:30.240
In our game, we are going to create several different sprites, to represent the different entities within

02:30.240 --> 02:30.630
the game.

02:31.260 --> 02:34.560
We are going to use an inheritance hierarchy to organize these.

02:35.100 --> 02:39.300
So we are going to create a base class, entity, which will represent sprites.

02:39.930 --> 02:41.890
This is going to be an abstract base class.

02:41.910 --> 02:49.290
So we need to override methods in the child classes. And the child classes will be concrete sprite classes.

02:49.530 --> 02:51.060
So the actual entities in the game.

02:52.590 --> 02:54.300
So here is our entity class.

02:54.780 --> 02:58.050
We need to include the SFML graphics header.

02:59.240 --> 03:05.840
We have a sprite as a protected data member, so the child classes can see it, which is arguably not ideal

03:05.840 --> 03:07.130
object-oriented design.

03:07.130 --> 03:11.120
But let's leave it! Then we have some virtual functions.

03:11.450 --> 03:16.400
These are pure virtual functions, so they have to be overridden in the child classes, and we cannot

03:16.460 --> 03:18.440
create any objects of this entity class.

03:20.030 --> 03:23.470
We have one member function which will update the entity.

03:23.540 --> 03:28.550
So as we go from one frame to the next, the entity might change its position, or change its colour, or

03:28.550 --> 03:31.130
shape. Or do all sorts of things.

03:32.330 --> 03:38.900
We have a draw() member function, which will cause this entity to be drawn upon the window argument.

03:40.370 --> 03:45.440
And because we are using virtual functions, we need to provide a virtual destructor.

03:49.110 --> 03:52.950
We are going to start off with a very simple entity. This is just going to be the background for the

03:52.950 --> 03:53.250
game.

03:53.610 --> 03:57.420
So we are just going to load in an image file, which just sits there and does nothing.

03:58.800 --> 04:00.390
We inherit from the entity class.

04:01.020 --> 04:05.130
We have a texture member. We make this static.

04:05.640 --> 04:10.110
So there is only one object in memory, regardless of how many objects there are of the class.

04:12.320 --> 04:17.720
We have a constructor which will create an object at a given position on the screen. And then we override

04:17.840 --> 04:20.060
the inherited pure virtual functions.

04:24.060 --> 04:25.740
In the class definition,

04:26.160 --> 04:33.510
we first of all initialize the static data member. In the constructor, we load the texture from file.

04:34.650 --> 04:41.550
Then we set this to be the texture of the Sprite object, which we inherited from entity. And then we

04:41.550 --> 04:43.290
search the initial position of the sprite.

04:45.800 --> 04:47.060
In the update() function,

04:47.060 --> 04:50.900
there is nothing to do, because the background does not need any updating.

04:52.040 --> 04:55.370
And for the draw() member function, we can just delegate to the window.

04:55.610 --> 04:58.850
So we ask the window object to draw the sprite for us.

05:03.630 --> 05:07.800
And then the main() function is very similar to the one we had for the random walk.

05:08.310 --> 05:11.520
Except, instead of having a creature object, we have a background object.

05:11.970 --> 05:19.140
So we create the background object. We create the window, we set the frame limit. We start our

05:19.140 --> 05:26.820
loop, clear the screen, check if we need to terminate the game. Then we update the background, then

05:26.820 --> 05:33.510
we draw the background, and then finally we display the updated version of the screen for this frame.

05:36.270 --> 05:39.660
And there it is. Not very exciting, but it is the first step on the road.

05:42.550 --> 05:48.940
If you are using Visual Studio, then by default it will look for the image file in the project directory.

05:49.150 --> 05:51.710
So this is where the headers and the source file are.

05:53.380 --> 05:58.810
If you remember back to when when we copied the DLL's, those went into the directory where the program

05:58.810 --> 06:01.900
executable is. And that is known as the target directory.

06:02.410 --> 06:08.470
So if you'd rather have your image file there, you can do that. Go into configuration properties,

06:08.470 --> 06:12.190
then debugging, and then set the working directory.

06:13.180 --> 06:19.540
So by default, this is project directory, but if you change it to target, then this will look for

06:19.540 --> 06:24.970
the image in the same directory as the executable and the DLL's, which I think is more logical.

06:25.840 --> 06:27.340
Okay, so that is it for this video.

06:27.760 --> 06:28.570
I will see you next time.

06:28.570 --> 06:30.790
But until then, keep coding!
