Now, let’s add some more code. The code that follows will open a window using SFML that Timber!!! will eventually run in. The window will be 1,920 pixels wide by 1,080 pixels high and will be full screen (no border or title).
Enter the new code that is highlighted here to the existing code and then we will examine it. As you type (or copy and paste), try and work out what is going on:
#include <SFML/Graphics.hpp>
{
RenderWindow window(vm, "Timber!!!", Style::Fullscreen);
return 0;
}
Now we will go through that code a bit at a time to understand it.
Including SFML features
The first thing we will notice in our new code is the #include
directive.
The #include
directive directs Visual Studio to include, or add, the contents of another file before compiling. The effect of this is that some other code, which we have not written ourselves, will be a part of our program when we run it. The process of adding code from other files into our code is called preprocessing and, perhaps unsurprisingly, is performed by something called a preprocessor. The .hpp
file extension means it is a header file.
Therefore, #include <SFML/Graphics.hpp>
tells the preprocessor to include the contents of the Graphics.hpp
file that is contained within the folder named SFML
. It is the same folder that we created while setting up the project.
This line adds code from the file, which gives us access to some of the features of SFML. Exactly how it achieves this will become clearer when we start writing our own separate code files and using #include
to use them.
The most common files that we will be including throughout this book are the SFML header files that give us access to all the cool game-coding features. We will also use #include
to access the C++ Standard Library header files. These header files give us access to core features of the C++ language itself.
What matters for now is that we have a whole bunch of new functionalities that have been provided by SFML available to use if we add that single line of code.
The next new line is using namespace sf;
. We will come back to what this line does soon.
OOP, classes, and objects
We will fully discuss OOP, classes, and objects as we proceed through this book. What follows is a brief introduction so that we can understand what is happening so far.
We already know that OOP stands for object-oriented programming. OOP is a programming paradigm – that is, a way of coding. OOP is generally accepted throughout the world of programming in most languages as the best, if not the only, professional way to write code. Notice I said most; there are exceptions.
OOP introduces a lot of coding concepts, but fundamental to them all are classes and objects. When we write code, whenever possible, we want to write code that is reusable, maintainable, and secure. The way we do this is by structuring our code as a class. We will learn how to do this in Chapter 6, Object-Oriented Programming – Starting the Pong Game.
All we need to know about classes for now is that once we have coded our class, we don’t just execute that code as part of our game; instead, we create usable objects from the class.
For example, if we wanted 100 zombie NPCs (non-player characters), we could carefully design and code a class called Zombie
and then, from that single class, create as many zombie objects as we like. Each and every zombie object would have the same functionality and internal data types, but each and every zombie object would be a separate and distinct entity.
To take the hypothetical zombie example further but without showing any code for the Zombie
class, we might create a new object based on the Zombie
class, like this:
Zombie z1;
The z1
object is now a fully coded and functioning Zombie
object. We could then do this:
Zombie z2; Zombie z3; Zombie z4; Zombie z5;
We now have five separate Zombie
instances, but they are all based on one carefully coded class. Let’s take things one step further before we get back to the code we have just written. Our zombies can contain both behavior (defined by functions) as well as data, which might represent things such as the zombie’s health, speed, location, or direction of travel. As an example, we could code our Zombie
class to enable us to use our Zombie
objects, perhaps like this:
z1.attack(player); z2.growl(); z3.headExplode();
Note again that all this zombie code is hypothetical for the moment. Don’t type this code into Visual Studio – it will just produce a bunch of errors.
We would design our class so that we can use the data and behaviors in the most appropriate manner to suit our game’s objectives. For example, we could design our class so that we can assign values for the data for each zombie object at the time we create it.
Let’s say we need to assign a unique name and speed in meters per second at the time we create each zombie. Careful coding of the Zombie
class could enable us to write code like this:
The point is that classes are almost infinitely flexible, and once we have coded the class, we can go about using them by creating an object/instance of them. It is through classes and the objects that we create from them that we will harness the power of SFML. And yes, we will also write our own classes, including a Zombie
class.
Let’s get back to the real code we just wrote.
Using namespace sf
Before we move on and look more closely at VideoMode
and RenderWindow
, which, as you have probably guessed by now, are classes provided by SFML, we will learn what the using namespace sf;
line of code does.
When we create a class, we do so in a namespace. We do this to distinguish our classes from those that others have written. Consider the VideoMode
class.
It is entirely possible that, in an environment such as Windows, somebody has already written a class called VideoMode
. By using a namespace, we and the SFML programmers can make sure that the names of classes never clash.
The full way of using the VideoMode
class is like this:
sf::VideoMode...
using namespace sf;
enables us to omit the sf::
prefix from everywhere in our code. Without it, there would be over 100 instances of sf::
in this simple game alone. It also makes our code more readable, as well as shorter.
SFML VideoMode and RenderWindow
Inside the main
function, we now have two new comments and two new lines of executable code. The first line of executable code is this:
VideoMode vm(1920, 1080);
This code creates an object called vm
from the class called VideoMode
and sets up two internal values of 1920
and 1080
. These values represent the resolution of the player’s screen.
The next new line of code is as follows:
RenderWindow window(vm, "Timber!!!", Style::Fullscreen);
In the previous line of code, we are creating a new object called window
from the SFML-provided class called RenderWindow
. Furthermore, we are setting up some values inside our window object.
Firstly, the vm
object is used to initialize part of window
. At first, this might seem confusing. Remember, however, that a class can be as varied and flexible as its creator wants to make it. And yes, some classes can contain instances of other classes.
It is not necessary to fully understand how this works at this point if you appreciate the concept. We code a class and then make usable objects from that class – a bit like an architect might draw a blueprint. You certainly can’t move all your furniture, kids, and the dog into the blueprint, but you could build a house (or many houses) from the blueprint. In this analogy, a class is like a blueprint and an object is like a house.
Next, we use the "Timber!!!"
value to give the window a name. Then, we use the predefined Style::FullScreen
value to make our window
object full-screen.
Style::FullScreen
is a value that’s defined in SFML. It is useful because we don’t need to remember the integer number the internal code uses to represent a full screen. The coding term for this type of value is constant
. Constants and their close C++ relatives, variables, are covered in the next chapter.
Let’s look at our window object in action.
Running the game
You can run the game again at this point. You will see a bigger black screen flash on and then disappear. This is the 1920 x 1080 full-screen window that we just coded. Unfortunately, what is still happening is that our program is starting, executing from the first line of main
, creating the cool new game window, then coming to return 0;
and immediately exiting back to the operating system.
Next, we will add some code that will form the basic structure of every game in this book. This is known as the game loop.