Programmation en C/SDL2

Initiation à la SDL

Introduction

La SDL est une bibliothèque destinée à créer des jeux vidéos. Elle met à disposition du programmeur des fonctions permettant de gérer l'affichage en 2D et 3D (en la combinant avec OpenGL). D'autres fonctions sont également disponibles afin de gérer le son et les manettes de jeux.

Notions abordées

Description du programme

Une simple fenêtre SDL, n'affichant aucun contenu.

win_quit.c

#include <stdio.h>
#include <SDL2/SDL.h>

int main(int argc, char *argv[]) {
	/* SDL_Window est une variable pointant vers une fonction
	 * permettant de creer une fenetre -> voir SDL_CreateWindow() plus bas*/
	SDL_Window *window;
	
	/* SDL_Event est une variable regroupant différents types struct.
	 * Ces types struct permettent de gerer des evenements comme :
	 * - les entrees claviers,
	 * - les boutons et les mouvements de la souris
	 * - les boutons ou le joystick d'une manette de jeux */
	SDL_Event event;
	
	/* On cree une variable de type int qui permettra de sortir d'une boucle infinie.
	 * - Si la variable est a 0 la boucle continue
	 * - Si la variable est a 1 on sort de la boucle et le jeux s'arrete */
	int quit=0;
	
	/* On passe en argument de SDL_VideoInit() le type de driver.
	 * On utilise NULL pour utiliser celui par defaut.
	 * La fonction renvoie 0 en cas de succes et un nombre negatif en cas d'echec. */
	if (SDL_VideoInit(NULL) < 0) { 
		/* La fonction SDL_LogError permet d'afficher des erreurs SDL */
        SDL_LogError(
			SDL_LOG_CATEGORY_APPLICATION, /* Flag par defaut pour des logs de type Application */
			"Couldn't initialize SDL video: %s\n",
			/* La fonction SDL_GetError() renvoi une chaine de caractere
			 * contenant la derniere erreur SDL enregistree */
            SDL_GetError()	
         ); /* Fin de SDL_LogError */
        exit(1);
    }// Fin du if de SDL_VideoInit()

	window = SDL_CreateWindow("Fenetre",
				SDL_WINDOWPOS_UNDEFINED,	/* Position de la fenetre selon x */
				SDL_WINDOWPOS_UNDEFINED,	/* Position de la fenetre selon y */
	      640,	/* Taille de la fenetre en pixel */
	      480,	/* Hauteur de la fenetre en pixel */
	      /* En utilisant le flag SDL_WINDOW_SHOWN, la fenetre ne peut-être ni
				 *	maximise, ni minimise et n'est pas redimensionnable */
	      SDL_WINDOW_SHOWN
	      ); /* Fin de SDL_CreateWindow */

	while ( !quit ) {
		/* SDL_PollEvent est une fonction renvoyant le nombre 1
		 * tant qu'il y a des evenements en attente */
		if ( SDL_PollEvent(&event) ) {
			switch (event.type) {
				case SDL_QUIT: /* SDL_QUIT correspond au bouton de fermeture de la fenetre */
					quit=1;
					break;
			}//end switch event.type
		}//end if PollEvent
	}//end while quit
	
	SDL_DestroyWindow(window);
	SDL_Quit();

	exit(0);
}//end main


Ci-dessous le même programme mais sans les commentaires :

#include <stdio.h>
#include <SDL2/SDL.h>

int main(int argc, char *argv[]) {
	SDL_Window *window;
	SDL_Event event;
	int quit=0;
	
	if (SDL_VideoInit(NULL) < 0) { 
        SDL_LogError(
						SDL_LOG_CATEGORY_APPLICATION,
						"Couldn't initialize SDL video: %s\n",
							SDL_GetError()
         );
        exit(1);
    }

	window = SDL_CreateWindow("Fenetre",
				SDL_WINDOWPOS_UNDEFINED,
				SDL_WINDOWPOS_UNDEFINED,
	      640,
	      480,
	      SDL_WINDOW_SHOWN
	      );

	while ( !quit ) {
		if ( SDL_PollEvent(&event) ) {
			switch (event.type) {
				case SDL_QUIT:
					quit=1;
					break;
			}//end switch event.type
		}//end if PollEvent
	}//end while quit
	
	SDL_DestroyWindow(window);
	SDL_Quit();

	exit(0);
}//end main


Pour compiler le programme, on tape dans le terminal

gcc win_quit.c -o win_quit -lSDL2

En tapant la commande ls, vous devriez voir un exécutable appelé win_quit. Pour l'exécuter on tape:

./win_quit

Première utilisation d'un sprite

Les sprites sont des éléments graphiques qui servent à afficher des décors et des personnages animés. Pour manipuler les sprites la SDL utilise le type SDL_Surface.

On affiche pas les sprites directement sur l'écran. Pour cela on utilise un moteur de rendu. Le moteur de rendu est un pointeur vers une structure du type SDL_Renderer. On dessine d'abord dans le moteur de rendu et une fois que l'on a dessiné tous les éléments dans le moteur de rendu on affiche celui-ci à l'écran. Cette technique évite les scintillements et donne une impression de fluidité.

De même, on ne dessine pas directement les sprites dans le moteur de rendu mais on passe par une texture avec le type SDL_Texture. On pourra par exemple charger nos décors dans une texture qui lui est propre et nos personnages dans d'autres textures. Une fois celle-ci chargée, on les couplent au moteur de rendu.

Le fait de séparer nos éléments graphiques en texture permet d'améliorer la gestion de la mémoire et donc la rapidité d'affichage de nos éléments graphiques. On peut par exemple décider de créer une texture de type "décors" une fois pour toute, en ne la chargeant qu'une seul fois durant tout le niveau d'un jeux. On alternerera ensuite l'affichage des différentes textures décors/personnages durant l'animation de nos personnages.

Le code suivant va se contenter de créer un sprite et de charger une image dans celui-ci.

Vous aurez donc besoin de l'image suivante pour faire fonctionner le programme (sol.bmp):

(clique droit de la souris et choisir "Enregistrer l'image sous ..."). Il faut enregistrer l'image dans le même répertoire que le fichier source ci-dessous (sprite.c).

sprite.c

#include <stdio.h>
#include <SDL2/SDL.h>

int main(int argc, char *argv[]) {
	SDL_Window *window;
	SDL_Renderer *renderer;
	SDL_Surface *sprite;
	SDL_Texture *texture;
	SDL_Event event;
	int quit=0; 

	if (SDL_VideoInit(NULL) < 0) {
		SDL_LogError(
		SDL_LOG_CATEGORY_APPLICATION,
		"Couldn't initialize SDL video: %s\n",
		SDL_GetError());
		exit(1);
	}

	window = SDL_CreateWindow("Fenetre",
			SDL_WINDOWPOS_UNDEFINED,
			SDL_WINDOWPOS_UNDEFINED,
	    640, 480, SDL_WINDOW_SHOWN);
	
	/*
	 * On cree notre moteur de rendu avec la fonction SDL_CreateRenderer()
	 * On passe en argument la fenetre d'affichage cree precedemment (window)
	 * Le -1 signifie que l'on initialise le pilote de rendu par defaut
	 * SDL_RENDERER_ACCELERATED demande a ce que le moteur de rendu
	 * utilise l'acceleration materielle
	 */
	renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
    
	// on charge l'image dans le sprite
	sprite = SDL_LoadBMP("sol.bmp");
	
	/*
	 * On cree une texture qui sera utilise par le moteur de rendu
	 * et on associe cette texture au sprite cree precedemment
	 */
	texture = SDL_CreateTextureFromSurface(renderer, sprite);	
    
  /*
   * On copie la texture (et donc le sprite) dans le moteur de rendu
   * Pour l'instant on met les deux derniers arguments a NULL
   * et on verra dans un autre chapitre ce que cela signifie
   */
  SDL_RenderCopy(renderer, texture, NULL, NULL);
    
	//On affiche le tout
	SDL_RenderPresent(renderer);

	while ( !quit ) {
		if ( SDL_PollEvent(&event) ) {
			switch (event.type) {
				case SDL_QUIT:
					quit=1;
					break;
			}//end switch event.type
		}//end if PollEvent
	}//end while quit
	
	SDL_DestroyTexture(texture);
	SDL_FreeSurface(sprite);
	SDL_DestroyRenderer(renderer);
	SDL_DestroyWindow(window);
	SDL_Quit();
	exit(0);
}//end main

Pour compiler le programme, on tape dans le terminal:

gcc sprite.c -o sprite -lSDL2

Pour l'exécuter:

./sprite

Il va alors s'afficher la fenêtre ci-contre :