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 important libraries here
#include <SFML/Graphics.hpp>
// Make code easier to type with “using namespace”
using namespace sf;
// This is where our game starts from
int main()
{
// Create a video mode object
VideoMode vm(1920, 1080);
// Create and open a window for the game
RenderWindow window(vm, “Timber!!!”, Style::Fullscreen);
return 0;
}
#including SFML features
The first thing we will notice in our new code is the #include
directive.
The #include
directive tells 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 aforementioned 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 main 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.
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 almost every language, as the best, if not the only, professional way to write code.
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();
Important note
Note again that all this zombie code is hypothetical for the moment. Don’t type this code into to 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:
// Dave was a 100 metre Olympic champion before infection
// He moves at 10 metres per second
Zombie z1(“Dave”, 10);
// Gill had both of her legs eaten before she was infected
// She drags along at .01 metres per second
Zombie z2(“Gill”, .01);
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 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 actual code. The first line of actual 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 other instances of other classes.
Tip
It is not necessary to fully understand how this works at this point, as long as you appreciate the concept. We code a class and then make useable objects from that class – a bit like an architect might draw a blueprint. You certainly can’t move all your furniture, kids, and 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 fullscreen.
Tip
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 take a 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 1,920 x 1,080 fullscreen 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.