Category Archives: Tutorial

SDL 2.0 Tutorial-01: The game window

Last week we discussed how to setup a basic game loop. We were missing a few critical components, one being the window! This week we are going to learn how to create a basic window and renderer using SDL. SDL 2.0 works hard to get us the optimal display for the system we are working on. Most often that means OpenGL or DirectX, although, SDL provides a wrapper to a build-in renderer to make drawing easy – so we won’t be considered with what type of renderer we get. If you wish to work on a 3D game (or 2D with shaders/effects) it is possible to do with SDL but you’ll have to write a custom renderer which communicates with OpenGL/DirectX.

First thing we’ll want to do is take last week’s anonymous “Game” structure and add a module for our screen. We’ll only use one screen here so the module will adhere to the same anonymous struct style which we used for “Game”.

struct {
	// define "attributes"
	SDL_bool running;
	struct {
		unsigned int w;
		unsigned int h;
		const char* name;
		SDL_Window* window;
		SDL_Renderer* renderer;
	} screen;

	// define "methods"
	void (*init)(void);
	void (*quit)(void);
} Game = {
	SDL_FALSE,
	{
		SCREEN_SCALE*SCREEN_w,
		SCREEN_SCALE*SCREEN_H,
		SCREEN_NAME,
		NULL,
		NULL
	},
	game_init,
	game_quit
};

So now we have access to Game.screen who’s properties are w the width of the window, h the height of the window, name the string which will appear and the top of our window, window a pointer to our SDL window, and renderer a pointer to our SDL renderer. The width, height, scale, and name are specified as follows in the game header file.

#define SCREEN_w 640
#define SCREEN_H 480
#define SCREEN_SCALE 1
#define SCREEN_NAME "Prototype"

Defining our variables in this way allows for the w, h, scale, and name to be accessed from other points within our code base. Now we need to rewrite void game_init(void); and void game_quit(void); to get our screen to display and to clean up any memory left when we’re finished.

void game_init(void) {
	if(SDL_Init(SDL_INIT_EVERYTHING)!=0) {
		printf("SDL error -> %sn", SDL_GetError());
		exit(1);
	}

	unsigned int w = Game.screen.w;
	unsigned int h = Game.screen.h;
	const char* name = Game.screen.name;

	Game.screen.window = SDL_CreateWindow(
		name,
		SDL_WINDOWPOS_CENTERED,
		SDL_WINDOWPOS_CENTERED,
		w, h, 0
	);
	Game.screen.renderer = SDL_CreateRenderer(
		Game.screen.window, -1,
		SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC
	);

	Game.running = SDL_TRUE;
}

Here we make the necessary library calls to get a window and renderer. The SDL_WINDOWPOS_CENTERED flag will center our window when it pops up for the player. It is possible to setup a fullscreen window however if you are using pixel art this isn’t recommended for reasons that will become obvious once we write code for setting up our sprites. To destroy our renderer and window we’ll code void game_quit(void); the following way.

void game_quit(void) {
	SDL_DestroyRenderer(Game.screen.renderer);
	SDL_DestroyWindow(Game.screen.window);

	Game.screen.window = NULL;
	Game.screen.renderer = NULL;

	SDL_Quit();
}

At this point if you are encountering errors it is recommended to wrap the library function returns with if-statements to print any errors to stdout as we have done in the past. Now we need to modify our main game loop to provide continuous rendering as well as exiting functionality. It’s quite interesting to note that a window not polling for events (i.e. keypresses, mouse movements, etc.) will show as being non-responsive by the operating system. If on the other hand you are polling for events but aren’t listening for when the window is closed (i.e. red X at top right on windows) then the window will remain open and the only way to close it will require Ctrl+Alt+Delete. Let’s write a new game loop which polls for events and listens for when the window is closed.

int main(int argc, char* argv[]) {

	Game.init();

	SDL_Event event;
	while(Game.running) {
		while(SDL_PollEvent(&event)) {
			switch(event.type) {
				case SDL_QUIT: {
					Game.running = SDL_FALSE;
				} break;
			}
		}

		SDL_RenderClear(Game.screen.renderer);
		SDL_RenderPresent(Game.screen.renderer);
	}

	Game.quit();

	return 0;
}

Here we are simply polling for events and clearing/presenting an empty renderer. That’s all for this week! Next week we’ll look at how to read in a single image, split it into an array of sprites and display those sprites based on a gird/map. If you are getting the hang of C development I highly recommend picking up a GCW handheld – think of it as a hobby expense! Take care.

SDL 2.0 Tutorial-00: The Basic Sturcture

Throughout this series of weekly tutorials I’ll be guiding you through SDL 2.0 game development in C. I’m sticking with the C-programming language to keep things simple, and this will no doubt make learning C++ A LOT easier if you ever decide to step things up a bit.

Our first step is to setup a basic game structure. We need a chunk of memory where we can store all the components that will persist over the entire existence of our program. This is a reasonable thing to do since components like the game window will run for as long as the game runs.

First let’s include some fundamental header files. These files are part of the C standard library and provide some basic functions like printing statements to a standard output stream.

#include <stdio.h>
#include <stdlib.h>

For a detailed description of the C standard library and how to use it check out this reference.

Now we have some bare-bones functionality. Next we need to include the SDL 2.0 function and variable definitions so that we can use the SDL library.

#define SDL_MAIN_HANDLED
#include "SDL2/SDL.h"

This first line here tells SDL that we won’t be needing any special entry point for our program. We’ll be handling the entry and library initiation ourselves within int main(int argc, char* argv[]); .

The second line provides references to all the SDL functions and variables we will be using. It is worth noting that #define SDL_MAIN_HANDLED should be before #include “SDL2/SDL.h” so that when the SDL library is being preprocessed the custom entry points aren’t included.

The next part varies a bit based on personal preference but I have found it to be a nice and simple way of defining, what is essentially, a Singleton within C.

void game_init(void);
void game_quit(void);

static struct {
	// define "attributes"
	SDL_bool running;

	// define "methods"
	void (*init)(void);
	void (*quit)(void);
} Game = {
	SDL_FALSE,
	game_init,
	game_quit
};

This provides us with a globally defined game object which will be used to house all persistent game information. Doing things this way will help cut down on function parameters, which can easily get out-of-hand if not kept in check.

Now it is time to actually implement the void game_init(void); and void game_quit(void); functions.

void game_init(void) {
	printf("game_init()n");
	SDL_Init(SDL_INIT_EVERYTHING);
	Game.running = SDL_TRUE;
}

void game_quit(void) {
	printf("game_quit()n");
	SDL_Quit();
	Game.running = SDL_FALSE;
}

What we are doing here in the initialization step is printing the function name to the standard out stream, initializing the SDL library, and setting the game to a “running” state. During the SDL initialization the library will build and allocate all the objects and variables needed to make a game window, provide game audio, timers, events, joystick controls, etc.

Depending on how you are setting up your program it is possible that you might run into errors at this point due to SDL not being able to initialize correctly. In that case you will need to wrap your code in the following way so that SDL will tell you what the issue may be.

void game_init(void) {
	printf("game_init()n");

	if(SDL_Init(SDL_INIT_EVERYTHING)!=0) {
		printf("SDL error -> %sn", SDL_GetError());
		exit(1);
	}

	Game.running = SDL_TRUE;
}

Once all the issues are resolved, we are ready to actually make a little magic happen. The following is a simple game loop which initializes and quits the game in one iteration. Not a fun game but it does provide the structure we’ll need for next week’s project when we actually get a window up and running!

int main(int argc, char* argv[]) {

	Game.init();

	printf("running = %dn", Game.running);

	while(Game.running) {
		Game.quit();
	}

	printf("running = %dn", Game.running);

	return 0;
}

Here our main function takes two parameters. int argc stands for “argument count” and provides us with the number of command line arguments passed to our function during execution. char* argv[] stands for “argument vector” and provides us with the actual string arguments which where passed to our function. Once the game has successfully executed our code we return 0; to tell the operating system that we achieved everything we set out to do.

All together we get the following piece of code!

/* Stephen's Tutorials (https://stephenmeier.net/)
gcc main.c -o game.exe -I./include -L./lib -lSDL2main -lSDL2
running on gcc 4.8.1, SDL 2.0.1
*/

//----------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>

//----------------------------------------------------------------------
#define SDL_MAIN_HANDLED
#include "SDL2/SDL.h"

//----------------------------------------------------------------------
void game_init(void);
void game_quit(void);

static struct {
	// define "attributes"
	SDL_bool running;

	// define "methods"
	void (*init)(void);
	void (*quit)(void);
} Game = {
	SDL_FALSE,
	game_init,
	game_quit
};

//----------------------------------------------------------------------
void game_init(void) {
	printf("game_init()n");

	if(SDL_Init(SDL_INIT_EVERYTHING)!=0) {
		printf("SDL error -> %sn", SDL_GetError());
		exit(1);
	}

	Game.running = SDL_TRUE;
}

//----------------------------------------------------------------------
void game_quit(void) {
	printf("game_quit()n");
	SDL_Quit();
	Game.running = SDL_FALSE;
}

//----------------------------------------------------------------------
int main(int argc, char* argv[]) {

	Game.init();

	printf("running = %dn", Game.running);

	while(Game.running) {
		Game.quit();
	}

	printf("running = %dn", Game.running);

	return 0;
}

Till next week, take care!