Part 2: SDL Initialisation
Initialising the basics
Now we have our project setup, let's get down to business. I'm going to talk you through the code, what each bit does and to a certain extent why it's important. Baring in mind this tutorial is mainly about making sure you can get off the ground quickly - teaching to to drive a car before you can dribble so to speak. Because of this premise, the following link takes you to copies of all the files worked on in every tutorial, but I emplore to you work through it with me before resorting to simply copying the file I provide you:
First things first, we're going to need a file from which the entire of our program starts, and that file and that file only will contain our main function. *(The main function is the one which the compiler searches for when running the program)*. So, go ahead and right click on the folder named "Source Files" on the left and go to "Add" and "New Item".
If not already highlighted, click "Visual C++" on the left and single-click "C++ File (.cpp)". Give it a name in the first box of two at the bottom, I highly recommend "Main.cpp" for this file. Then click Add and the file will open automatically for editing with nothing inside it.
[Whenever I ask you to create a ".cpp" file or a ".h" file in the future, refer to this method of creation. However, creation of a "class" is different and I will show you that soon.]
Now we have our empty Main.cpp file the first thing we want to do is "include" some header files to use them in our Main.cpp file. For this tutorial part we're going to be initialising SDL and outputting to the console for testing and debugging purposes. With that in mind we are going to want to include "SDL.h" for SDL, "iostream" for outputting to the console and "string" so we can use string variables (string variables are a collection of characters, like a word or phrase).
First off, there are two ways to "include" a header file. Inbuilt header files such as the ones we are including now can be included like so:
First off, there are two ways to "include" a header file. Inbuilt header files such as the ones we are including now can be included like so:
#include <SDL.h> or #include <iostream>
Later down the line when we start including the header files we have created for our project ourselves we will use the following syntax:
#include "OurHeader.h"
For now let's go ahead and include those three at the top of our Main.cpp (always include first in a .cpp file):
In the screenshot, I stopped halfway through including string because of what you probably noticed pops up.
This is IntelliSense.
IntelliSense is incredibly useful, it predicts what you're going to put when it is able to. It does so for things like includes, but also for functions and properties of classes or objects you're manipulating/using. Incredibly useful tool.
Now we've included those we can continue on with our first function, "main":
This is IntelliSense.
IntelliSense is incredibly useful, it predicts what you're going to put when it is able to. It does so for things like includes, but also for functions and properties of classes or objects you're manipulating/using. Incredibly useful tool.
Now we've included those we can continue on with our first function, "main":
This is a function, and for those of you who don't know, take a gander at -> this page <- for an explanation of functions.
Now, in our function the first thing we need to do is intialise SDL, get a window showing and a renderer to go with so we can draw stuff to the window, not just have an empty window.
Firstly we must create 2 global variables for SDL to use, a window variable and a renderer variable:
Now, in our function the first thing we need to do is intialise SDL, get a window showing and a renderer to go with so we can draw stuff to the window, not just have an empty window.
Firstly we must create 2 global variables for SDL to use, a window variable and a renderer variable:
SDL_Window* window;
SDL_Renderer* renderer; |
We pop these variables after our includes but before our main function. These are pointer variables for a SDL_Window and an SDL_Renderer which we will use for this part of the tutorial to demonstrate setting them up when initialising SDL.
For now on all work will be within the main function.
Firstly we initialise SDL and check whether it was successful all in one line with an if statement like so:
For now on all work will be within the main function.
Firstly we initialise SDL and check whether it was successful all in one line with an if statement like so:
int main(int argc, char* args[])
{ if (SDL_Init(SDL_INIT_EVERYTHING)==0) { std::cout << "SDL initialising successful" << std::endl; } else { std::cout << "SDL initalisation failed" << std::endl; return false; } SDL_Delay(5000); return 0; } |
* [From now on everything new will be bold, and the rest normal text.] *
We initialise SDL within the if statement using the function "SDL_Init" which takes a parameter. Here we use a variable in SDL called SDL_INIT_EVERYTHING because we want all of SDLs functionality open to us. We check if the function returned 0, meaning everything's okay and we can proceed into the if statement where we print to the console to tell us that everything went okay. If not, we add an else to our if statement which prints a different line to the console, should the initialisation fail, and then exit the program immediately. You should have this console pop up if you were successful:
If so, init was successful, if not one of three things has happened: You're code isn't the same as I have told you (in which case check the source code up to line 13). Or you have set up SDL wrong. The last one you will probably encounter first time.
You're going to want to copy a few .dlls into your projects Debug directory.
Navigate to your SDL and SDL Image libraries wherever you stored them (C drive maybe?) and go into the "lib" folder, the into the "x86" folder and copy all the ".dll" files in there (if you don't have file extensions showing, then the "Type" in windows explorer will be "Application Extension"). Paste these files in "Your Base Project folder" -> "Debug" (you should have 3 files in there with the same name as your project, one being a .exe [executable]). Do this for both SDL2 and SDL Image.
If you just performed the actions concerning dll files, try running your program again, it should now be successful.
Once we've successfully initialised SDL as above, we can now create our window which is done quite simply with one line, using the window variable we created above the main function.
You're going to want to copy a few .dlls into your projects Debug directory.
Navigate to your SDL and SDL Image libraries wherever you stored them (C drive maybe?) and go into the "lib" folder, the into the "x86" folder and copy all the ".dll" files in there (if you don't have file extensions showing, then the "Type" in windows explorer will be "Application Extension"). Paste these files in "Your Base Project folder" -> "Debug" (you should have 3 files in there with the same name as your project, one being a .exe [executable]). Do this for both SDL2 and SDL Image.
If you just performed the actions concerning dll files, try running your program again, it should now be successful.
Once we've successfully initialised SDL as above, we can now create our window which is done quite simply with one line, using the window variable we created above the main function.
int main(int argc, char* args[])
{ if (SDL_Init(SDL_INIT_EVERYTHING)==0) { std::cout << "SDL initialising successful" << std::endl; window = SDL_CreateWindow("SDL Practice", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 640, SDL_WINDOW_SHOWN); } else { std::cout << "SDL initalisation failed" << std::endl return false; } SDL_Delay(5000); return 0; } |
As you can see here we create our window by initialising our window variable.
To initialise the window variable we use SDL2's SDL_CreateWindow function which takes the following parameters:
To initialise the window variable we use SDL2's SDL_CreateWindow function which takes the following parameters:
(const char* title, int xPos, int yPos, int width, int height, int flags)
We've not seen the char* variable before, and it is basically an array (collection) of letters, much like a string. The const denotes that it must be a constant value, meaning never changing. The easiest way to ensure this is to input a raw value rather than using a variable which can be edited later. For this in our code we put "SDL Practice" as the title for our window, hence the variable name title.
The next two variables are the x position and y position of our window on screen. SDL has a few inbuilt variables for use with window creation, such as the one we used in the example; SDL_WINDOWPOS_CENTERED. This variable finds the centre of the windows x or y depending on what variable it's assigned to in window creation and what you assign the next two variables. You can manually set a position such as 0, 0 and that is entirely up to you what you choose to do.
The next two variables are the width and height of the window, not including the "decorations" (title bar, edges, etc.) but only the inner window, so any size you declare is the size of window you'll be working with when developing your game. This effects the previous variables of x and y if you chose SDL_WINDOWPOS_CENTERED for either of them as it is used in the calculation.
The final variable is called flags which means any extra features you want to give this window from a list of pre-determined "flags". I chose the SDL flag SDL_WINDOW_SHOWN because it gives you a window with all borders and title bar, allows minimising and closing but isn't resizable or maximisable. That is because for now we don't want to complicate our game by allowing the window to resize and having to adjust ingame elements to adapt to change in window size. If you want to put in the extra effort to do so, go ahead. You can also choose SDL_WINDOW_BORDERLESS to remove all decorations like title bar; this can be used for things like splash screens.
Now that we have created our window we want to check whether it was succesfull, and if it was we want to carry on:
The next two variables are the x position and y position of our window on screen. SDL has a few inbuilt variables for use with window creation, such as the one we used in the example; SDL_WINDOWPOS_CENTERED. This variable finds the centre of the windows x or y depending on what variable it's assigned to in window creation and what you assign the next two variables. You can manually set a position such as 0, 0 and that is entirely up to you what you choose to do.
The next two variables are the width and height of the window, not including the "decorations" (title bar, edges, etc.) but only the inner window, so any size you declare is the size of window you'll be working with when developing your game. This effects the previous variables of x and y if you chose SDL_WINDOWPOS_CENTERED for either of them as it is used in the calculation.
The final variable is called flags which means any extra features you want to give this window from a list of pre-determined "flags". I chose the SDL flag SDL_WINDOW_SHOWN because it gives you a window with all borders and title bar, allows minimising and closing but isn't resizable or maximisable. That is because for now we don't want to complicate our game by allowing the window to resize and having to adjust ingame elements to adapt to change in window size. If you want to put in the extra effort to do so, go ahead. You can also choose SDL_WINDOW_BORDERLESS to remove all decorations like title bar; this can be used for things like splash screens.
Now that we have created our window we want to check whether it was succesfull, and if it was we want to carry on:
int main(int argc, char* args[])
{ if (SDL_Init(SDL_INIT_EVERYTHING)==0) { std::cout << "SDL initialising successful" << std::endl; window = SDL_CreateWindow("SDL Practice", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 640, SDL_WINDOW_SHOWN); if (window != 0) { std::cout << "Window creation succeeded" << std::endl; } else { std::cout << "Window creation failed" << std::endl; return false; } } else { std::cout << "SDL initalisation failed" << std::endl return false; } SDL_Delay(5000); return 0; } |
The line "window != 0" returns true if the window creation succeeded because it means that the variable window isn't equal to nothing. Once again, we add an else to our if statement, just in case it fails, to tell us what went wrong, and then exit. Running the program again should return something a little like this which closes after 5 seconds:
Once we've done that we can now have a go at initialising our renderer, needed for drawing elements to the screen other than the white space you see above. We do this like so:
int main(int argc, char* args[])
{ if (SDL_Init(SDL_INIT_EVERYTHING)==0) { std::cout << "SDL initialising successful" << std::endl; window = SDL_CreateWindow("SDL Practice", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 640, SDL_WINDOW_SHOWN); if (window != 0) { std::cout << "Window creation succeeded" << std::endl; renderer = SDL_CreateRenderer(window, -1, 0); if (renderer != 0) { std::cout << "Renderer creation succeeded" << std::endl; SDL_SetRenderDrawColor(renderer, 0, 0, 100, 255); } else { std::cout << "Renderer creation failed" << std::endl; return false; } } else { std::cout << "Window creation failed" << std::endl; return false; } } else { std::cout << "SDL initalisation failed" << std::endl return false; } SDL_Delay(5000); return 0; } |
Like with the window, once created using the line renderer = SDL_CreateRenderer(window, -1, 0); we want to check whether it was successful, if not return false and exit, if so then carry on. We did so once more with an if statement as shown above, very similar to the way we did with the window.
The odd line out is the SDL_SetRenderDrawColor(renderer, 0, 0, 100, 255);
What this does is set the background colour of our renderer (yes it's spelt "color" in the code, american english...) to the RGBA code (0, 0, 100, 255); These are values from 0 to 255 which represent the following; R = Red, G = Green, B = Blue and A = Alpha Transparency.
Look up how RGB colour codes work, programs like fireworks use RGB colour codes, with alpha transparency also (how see through it is). So the example colour code should give us a totally opaque, dark blue coloured background. However, if you run it you'll find it gives you the same white background. That's because we need to clear the renderer to the render colour, and then present the renderer to the window in order to see it. To do so we add a couple of lines after our initialisation completes.
The odd line out is the SDL_SetRenderDrawColor(renderer, 0, 0, 100, 255);
What this does is set the background colour of our renderer (yes it's spelt "color" in the code, american english...) to the RGBA code (0, 0, 100, 255); These are values from 0 to 255 which represent the following; R = Red, G = Green, B = Blue and A = Alpha Transparency.
Look up how RGB colour codes work, programs like fireworks use RGB colour codes, with alpha transparency also (how see through it is). So the example colour code should give us a totally opaque, dark blue coloured background. However, if you run it you'll find it gives you the same white background. That's because we need to clear the renderer to the render colour, and then present the renderer to the window in order to see it. To do so we add a couple of lines after our initialisation completes.
int main(int argc, char* args[])
{ if (SDL_Init(SDL_INIT_EVERYTHING)==0) { std::cout << "SDL initialising successful" << std::endl; window=SDL_CreateWindow("SDL Practice", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 960, 640, SDL_WINDOW_SHOWN); if (window !=0) { std::cout << "Window creation succeeded" << std::endl; renderer=SDL_CreateRenderer(window, -1, 0); if (renderer !=0) { std::cout << "Renderer creation succeeded" << std::endl; SDL_SetRenderDrawColor(renderer, 0, 0, 100, 255); } else { std::cout << "Renderer creation failed" << std::endl; return false; } } else { std::cout << "Window creation failed" << std::endl; return false; } } else { std::cout << "SDL initalisation failed" << std::endl return false; } SDL_RenderClear(renderer); SDL_RenderPresent(renderer); SDL_Delay(5000); return 0; } |
Both functions, SDL_RenderClear and SDL_RenderPresent take only one parameter, being our renderer. You'll learn later how we draw any and all elements in the lines between these two functions as a basic implementation of something called double buffering, but we'll cover that later.
Once done with that and you have a dark blue (or whatever colour you chose) screen showing you have succesfully initialised SDL. In the next tutorial we'll learn about the Game Loop and we'll also move this initiasation code into a new class "Game" which will encompass our game from there on out.
Once done with that and you have a dark blue (or whatever colour you chose) screen showing you have succesfully initialised SDL. In the next tutorial we'll learn about the Game Loop and we'll also move this initiasation code into a new class "Game" which will encompass our game from there on out.