-
Book Overview & Buying
-
Table Of Contents
SDL Game Development
By :
So, now that we have an idea of what makes up a game, we can separate the functions into their own class by following these steps:
Go ahead and create a new file in the project called Game.h:
#ifndef __Game__
#define __Game__
class Game
{
};
#endif /* defined(__Game__) */Next, we can move our functions from the main.cpp file into the Game.h header file:
class Game
{
public:
Game() {}
~Game() {}
// simply set the running variable to true
void init() { m_bRunning = true; }
void render(){}
void update(){}
void handleEvents(){}
void clean(){}
// a function to access the private running variable
bool running() { return m_bRunning; }
private:
bool m_bRunning;
};Now, we can alter the main.cpp file to use this new Game class:
#include "Game.h"
// our Game object
Game* g_game = 0;
int main(int argc, char* argv[])
{
g_game = new Game();
g_game->init("Chapter 1", 100, 100, 640, 480, 0);
while(g_game->running())
{
g_game->handleEvents();
g_game->update();
g_game->render();
}
g_game->clean();
return 0;
}Our main.cpp file now does not declare or define any of these functions; it simply creates an instance of Game and calls the needed methods.
Now that we have this skeleton code, we can go ahead and tie SDL into it to create a window; we will also add a small event handler so that we can exit the application rather than having to force it to quit. We will slightly alter our Game.h file to allow us to add some SDL specifics and to also allow us to use an implementation file instead of defining functions in the header:
#include "SDL.h"
class Game
{
public:
Game();
~Game();
void init();
void render();
void update();
void handleEvents();
void clean();
bool running() { return m_bRunning; }
private:
SDL_Window* m_pWindow;
SDL_Renderer* m_pRenderer;
bool m_bRunning;
};Looking back at the first part of this chapter (where we created an SDL window), we know that we need a pointer to an SDL_Window object that is set when calling SDL_CreateWindow, and a pointer to an SDL_Renderer object that is created by passing our window into SDL_CreateRenderer. The init function can be extended to use the same parameters as in the initial sample as well. This function will now return a Boolean value so that we can check whether SDL is initialized correctly:
bool init(const char* title, int xpos, int ypos, int width, int height, int flags);
We can now create a new implementation Game.cpp file in the project so that we can create the definitions for these functions. We can take the code from the Hello SDL section and add it to the functions in our new Game class.
Open up Game.cpp and we can begin adding some functionality:
First, we must include our Game.h header file:
#include "Game.h"
Next, we can define our init function; it is essentially the same as the init function we have previously written in our main.cpp file:
bool Game::init(const char* title, int xpos, int ypos, int width, int height, int flags)
{
// attempt to initialize SDL
if(SDL_Init(SDL_INIT_EVERYTHING) == 0)
{
std::cout << "SDL init success\n";
// init the window
m_pWindow = SDL_CreateWindow(title, xpos, ypos,
width, height, flags);
if(m_pWindow != 0) // window init success
{
std::cout << "window creation success\n";
m_pRenderer = SDL_CreateRenderer(m_pWindow, -1, 0);
if(m_pRenderer != 0) // renderer init success
{
std::cout << "renderer creation success\n";
SDL_SetRenderDrawColor(m_pRenderer,
255,255,255,255);
}
else
{
std::cout << "renderer init fail\n";
return false; // renderer init fail
}
}
else
{
std::cout << "window init fail\n";
return false; // window init fail
}
}
else
{
std::cout << "SDL init fail\n";
return false; // SDL init fail
}
std::cout << "init success\n";
m_bRunning = true; // everything inited successfully,
start the main loop
return true;
}We will also define the render function. It clears the renderer and then renders again with the clear color:
void Game::render()
{
SDL_RenderClear(m_pRenderer); // clear the renderer to
the draw color
SDL_RenderPresent(m_pRenderer); // draw to the screen
}Finally, we can clean up. We destroy both the window and the renderer and also call the SDL_Quit function to close all the subsystems:
{
std::cout << "cleaning game\n";
SDL_DestroyWindow(m_pWindow);
SDL_DestroyRenderer(m_pRenderer);
SDL_Quit();
}So we have moved the Hello SDL 2.0 code from the main.cpp file into a class called Game. We have freed up the main.cpp file to handle only the Game class; it knows nothing about SDL or how the Game class is implemented. Let's add one more thing to the class to allow us to close the application the regular way:
void Game::handleEvents()
{
SDL_Event event;
if(SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_QUIT:
m_bRunning = false;
break;
default:
break;
}
}
}We will cover event handling in more detail in a forthcoming chapter. What this function now does is check if there is an event to handle, and if so, check if it is an SDL_QUIT event (by clicking on the cross to close a window). If the event is SDL_QUIT, we set the Game class' m_bRunning member variable to false. The act of setting this variable to false makes the main loop stop and the application move onto cleaning up and then exiting:
void Game::clean()
{
std::cout << "cleaning game\n";
SDL_DestroyWindow(m_pWindow);
SDL_DestroyRenderer(m_pRenderer);
SDL_Quit();
}The clean() function destroys the window and renderer and then calls the SDL_Quit() function, closing all the initialized SDL subsystems.
To enable us to view our std::cout messages, we must first include Windows.h and then call AllocConsole(); andfreopen("CON", "w", stdout);. You can do this in the main.cpp file. Just remember to remove it when sharing your game.
SDL_CreateWindow takes an enumeration value of type SDL_WindowFlags. These values set how the window will behave. We created an init function in our Game class:
bool init(const char* title, int xpos, int ypos, int width, int height, int flags);
The final parameter is an SDL_WindowFlags value, which is then passed into the SDL_CreateWindow function when initializing:
// init the window m_pWindow = SDL_CreateWindow(title, xpos, ypos, width, height, flags);
Here is a table of the
SDL_WindowFlags function:
|
Flag |
Purpose |
|---|---|
|
|
Make the window fullscreen |
|
|
Window can be used with as an OpenGL context |
|
|
The window is visible |
|
|
Hide the window |
|
|
No border on the window |
|
|
Enable resizing of the window |
|
|
Minimize the window |
|
|
Maximize the window |
|
|
Window has grabbed input focus |
|
|
Window has input focus |
|
|
Window has mouse focus |
|
|
The window was not created using SDL |
Let's pass in SDL_WINDOW_FULLSCREEN to the init function and test out some fullscreen SDL. Open up the main.cpp file and add this flag:
g_game->init("Chapter 1", 100, 100, 640, 580, SDL_WINDOW_FULLSCREEN))Build the application again and you should see that the window is fullscreen. To exit the application, it will have to be forced to quit (Alt + F4 on Windows); we will be able to use the keyboard to quit the application in forthcoming chapters, but for now, we won't need fullscreen. One problem we have here is that we have now added something SDL specific to the main.cpp file. While we will not use any other frameworks in this book, in future we may want to use another. We can remove this SDL-specific flag and replace it with a Boolean value for whether we want fullscreen or not.
Replace the
int flags parameter in our Game init function with a boolfullscreen parameter:
The code snippet for Game.h:
bool init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen);
The code snippet for Game.cpp:
bool Game::init(const char* title, int xpos, int ypos, int width, int height, bool fullscreen)
{
int flags = 0;
if(fullscreen)
{
flags = SDL_WINDOW_FULLSCREEN;
}
}We create an int flags variable to pass into the
SDL_CreateWindow function; if we have set fullscreen to true, then this value will be set to the
SDL_WINDOW_FULLSCREEN flag, otherwise it will remain as 0 to signify that no flags are being used. Let's test this now in our main.cpp file:
if(g_game->init("Chapter 1", 100, 100, 640, 480, true))This will again set our window to fullscreen, but we aren't using the SDL-specific flag to do it. Set it to false again as we will not need fullscreen for a while. Feel free to try out a few of the other flags to see what effects they have.
Change the font size
Change margin width
Change background colour