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.

4 thoughts on “SDL 2.0 Tutorial-01: The game window

  1. southern-dust

    “`
    SDL_Event event;
    while(Game.running) {
    while(SDL_PollEvent(&event)) {
    switch(event.type) {
    case SDL_QUIT: {
    Game.running = SDL_FALSE;
    //I think we should quit there, or there may be blocked at below Other Stuff
    //refrences by https://wiki.libsdl.org/SDL_PollEvent#Code_Examples/
    } break;
    }
    }
    //Other Stuff;
    //Quit maybe blocked here.
    SDL_RenderClear(Game.screen.renderer);
    SDL_RenderPresent(Game.screen.renderer);
    }

    Game.quit();
    “`
    What’s your opinion?

    Like

    Reply
  2. Horst

    Hello,

    i’m new to SDL and c but not to programming.

    I have a problem though: Game.running is always SDL_FALSE, therefore the main loop never get’s executed. I stepped through the code with the debugger (Visual Studio 2017) until it reaches the line “Game.running = SDL_TRUE;” in the init function. It’s strange, because altough it executes this line, Game.running is still SDL_FALSE after this line.

    Do you have any suggestions? The code is exactly like yours.

    Like

    Reply
    1. Stephen Meier Post author

      That’s strange. Sounds like it could be creating a copy of the Game struct and setting running=true in the copy. Looking back at this code I wrote years ago, I think it’s a little confusing to both define and instantiate the game struct at the same time. But I think my reason for doing that was so “Game” would only be created once. Witch compiler are you using? VC++?

      Like

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s