Publicité pour l'hébergement

Plan du projet

Projet

I - Tutoriel Librairie SDL

"SDL" pour "Simple Directmedia Layer". Il s'agit d'une librairie graphique accessible par tous. Elle permet de créer des applications graphiques comme des jeux 2D ou des émulateurs. Cette bibliothèque est très flexible, simple d'utilisation et portative. Tous ces atouts ont largement contribué à son succès.


1) Installation

Afin de commencer à utiliser la librairie SDL, nous allons procéder à son installation sous le logiciel Code::Blocks v1.0 RC2.

Tout d'abord, il vous faut récupérer les fichiers nécéssaires à l'installation de la librairie.
Pour cela, il vous suffit de cliquer ici :)

Une fois ceci fait, voici la procédure à suivre.
1) Entrez dans le dossier SDL-1.2.12.
2) Dézippez le contenu du dossier lib dans le dossier lib de Code::Blocks :
C:/Program Files/CodeBlocks/lib (par défaut)
3) Dézippez le contenu du dossier bin dans le dossier bin de Code::Blocks :
C:/Program Files/CodeBlocks/bin (par défaut)
3) Ouvrez le dossier include.
4) Dézippez le dossier SDL dans le dossier include de Code::Blocks :
C:/Program Files/CodeBlocks/include (par défaut)
5) Retournez dans le dossier principal et ouvrez le dossier bin.
6) Dézippez le fichier SDL.dll dans le dossier C:/WINDOWS/system32 afin que la librairie SDL soit accessible pour n'importe quel programme à compiler.
7) Lancez Code::Blocks puis créez un projet SDL :
http://zupi.free.fr/PTuto/images/SDL/install1.jpg
8) Ensuite, rendez-vous dans les propriétés du projet : Project -> Properties
9) Cliquez sur l'onglet Targets et veillez à bien décocher la case Pause when execution ends puis validez.
http://zupi.free.fr/PTuto/images/SDL/install2.JPG

La librairie SDL en elle même est maintenant prête.
Cependant, nous aurons aussi besoin d'utiliser SDL_image et SDL_ttf.

Commençons par SDL_image. Cette librairie utilise SDL mais permet de charger n'importe quel type d'image à l'écran et non seulement des BMP comme le permet SDL.

Tout d'abord, il vous faut récupérer les fichiers nécéssaires à l'installation de la librairie.
Pour cela, il vous suffit de cliquer ici (mais non on ne se répète pas ;))

Une fois ceci fait, voici la procédure à suivre :
1) Dézippez tous les fichiers .dll du dossier /lib/ de l'archive dans le dossier /bin/ de votre CodeBlocks : C:/Program Files/CodeBlocks/bin (par défaut).
Profitez en pour faire de même dans le dossier C:/WINDOWS/System32/.
2) Dézippez le fichier .lib du dossier /lib/ de l'archive dans le dossier /lib/ de votre CodeBlocks : C:/Program Files/CodeBlocks/bin (par défaut).
3) Dézippez le fichier .h du dossier /include/ de l'archive dans le dossier /include/SDL/ de votre CodeBlocks : C:/Program Files/CodeBlocks/include/SDL (par défaut).
4) Maintenant, lancez Code::Blocks et rendez-vous dans le menu "Build" puis "Compiler Options".
http://zupi.free.fr/PTuto/images/SDL/install3.jpg
5) Sélectionnez l'onglet "Linker" puis cliquez sur le bouton "Add". Entrez alors "SDL_image" (cf screenshot). Validez le tout.
http://zupi.free.fr/PTuto/images/SDL/install4.jpg

Désormais, vous pourrez utiliser SDL_image en incluant :
#include "SDL/SDL_image.h"

Enfin, mettons un terme à toutes ces installations barbantes vitales :)

SDL_ttf sert à afficher des textes à partir de polices courantes ce qui évite de faire des images pour chaque affichage de texte.

Pour installer SDL_ttf, il vous faut d'abord récupérer les fichiers nécessaires à l'installation en cliquant ici (petit variante :))

Ensuite, reproduisez exactement les mêmes étapes que pour SDL_image, jusqu'à l'étape 5).
En effet, pour SDL_ttf vous ne devrez pas écrire "SDL_image" mais bien ... (suspense) ... "SDL_ttf" !

Enfin, pour utilisez SDL_ttf, il vous suffira d'inclure :
#include "SDL/SDL_ttf.h"


Vous êtes maintenant paré à utiliser la librairie SDL et à débuter ce tutorial sur SDL ! (les choses sérieuses quoi :))


2) Hello World v1.0

Comme le veut la tradition en programmation, tout débutant dans un domaine se doit de passer par le fameux "Hello world !".
Ainsi, nous allons procéder à l'établissement du Hello world v1.0 qui utilisera SDL_image précédemment installé. Autrement dit, nous écrirons "Hello World !" sur une fenêtre avec une imagee (vous verrez à la v2.0 qu'il est possible de faire autrement).

Commençons donc l'écriture du programme.

Tout d'abord, lancez Code::Blocks et créer un nouveau projet "SDL Application", tout en cochant "Do not create any files".

Une fois la page vierge affichée, entrons l'en tête du fichier :

Code C:
//Les fichiers d'entête
#include "SDL/SDL.h"
#include "SDL/SDL_image.h"
#include "SDL/SDL_ttf.h"
#include <string> //Afin de récupérer les noms des fichiers à charger
 
using namespace std;

Ici, on inclut donc une partie ce qu'on a installé avant à savoir SDL_image et SDL tout court :)

Code C:
//Les attributs de l'ecran (640 * 480)
const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;
const int SCREEN_BPP = 32;

On fixe la hauteur de l'écran à 480, la largeur à 640 et le nombre de bits par pixels à 32.

Code C:
//Les surfaces
SDL_Surface *background = NULL;
SDL_Surface *message = NULL;
SDL_Surface *screen = NULL;

Ensuite, on définit les différentes parties de l'écran final. On a donc screen pour l'écran, background pour le fond et message pour notre fameux "Hello world !". Pour l'instant, ces surfaces sont des pointeurs qui ne redirigent vers rien.

Code C:
SDL_Surface *load_image( std::string filename )
{
//L'image qui est chargée
SDL_Surface *loadedImage = NULL;
 
//L'image optimisée que nous utiliserons par la suite
SDL_Surface *optimizedImage = NULL;
 
//Chargement de l'image grâce à SDL_image
loadedImage = IMG_Load( filename.c_str() );
 
//Si l'image est chargée correctement
if( loadedImage != NULL )
{
//creation de l'image optimisée
optimizedImage = SDL_DisplayFormat( loadedImage );
 
//liberation de l'ancienne image
SDL_FreeSurface( loadedImage );
 
}
 
//on retourne l'image optimisé
return optimizedImage;
}

Voici la création de la première fonction. La fonction "load_image" va nous servir à charger dans le tampon une image "optimisée". L'optimisation est fortement conseillée afin d'éviter d'éventuelles pertes de performance dans le cas ou l'image ne serait pas encodée en 32 bits.
A noter que cette fonction retourne un pointeur vers la version optimisée de l'image chargée.

Code C:
void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )
{
SDL_Rect offset;
 
offset.x = x;
offset.y = y;
 
//on blit la surface
SDL_BlitSurface( source, NULL, destination, &offset );
}

La fonction apply_surface va nous permettre d'appliquer (afficher) une image sur l'écran. Pour cela, on lui donne la position (x;y) à laquelle le coin en haut gauche de l'image doit être placé. Ensuite, on crée un rectangle SDL auquel on donne la même position que celle voulue pour l'image. Enfin, on "blit" la surface sur l'écran. (Le terme blitter signifie en quelque sorte "coller")
Pour cela, on fournit à SDL_BlitSurface la source, la destination et le rectangle précédemment crée.

Code C:
bool init()
{
//initialisation de tout les sous-systemes de sdl
if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
{
return false;
}
 
//on met en place l'ecran
screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
 
//Si il y a une erreur lors de la mise en place de l'ecran
if( screen == NULL )
{
return false;
}
 
//on met en place la barre caption de la fenetre
SDL_WM_SetCaption( "Hello World ! v1.0", NULL );
 
//si tout s'est bien passé
return true;
}

La fonction booléenne init va nous permettre d'initialiser l'écran qui va recevoir et afficher ce que l'on veut. C'est l'une des fonctions clés de ce programme. On initialise donc tous les sous système de SDL à savoir les systèmes audio, vidéo, etc ... même si l'on ne se sert pas de tous. Ensuite, on met en place l'écran avec ces différentes caractéristiques.

Code C:
bool load_files()
{
//chargement du fond
background = load_image( "background.png" );
 
//si il y a un probleme au chargement du fond
if( background == NULL )
{
return false;
}
 
message = load_image( "message.jpg" );
 
//si il y a un probleme au chargement du message
if( message == NULL )
{
return false;
}
 
//Si tout s'est bien passé
return true;
}

Le fonction booléenne load_files est simplement une fonction de vérification qui permet de contrôler si le chargement des images c'est bien passé.

Code C:
void clean_up()
{
//Liberation des surfaces
SDL_FreeSurface( background );
SDL_FreeSurface( message );
 
//On quitte SDL
SDL_Quit();
}

La fonction clean_up permet de vider le tampon avant de quitter SDL et donc le programme.

Code C:
int main( int argc, char* args[] )
{
//Initialisation
if( init() == false )
{
return 1;
}
 
//Chargement des fichiers
if( load_files() == false )
{
return 1;
}
 
 
//Application des surfaces(images) sur l'ecran
apply_surface( 0, 0, background, screen );
apply_surface( 220, 150, message, screen );
 
//mise à jour de l'ecran
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
 
//On "met en pause" le programme pendant 3000 millisecondes (3 secondes)
SDL_Delay(3000);
 
//liberation des surface et on quitte sdl
clean_up();
 
return 0;
}

Enfin, la fonction principale du programme.
On initialise l'écran ainsi que les fichiers. Si tout c'est bien passé, on applique les images à l'écran et enfin, on laisse le programme ouvert 3 secondes avant de tout fermer.

Compilez et lancez et admirez votre premier programme fait avec SDL :)

Vous pouvez télécharger la source en cliquant ici


3) Hello world v2.0

Comme vous vous en doutez, nous aurons probablement besoin d'écrire sur notre écran de jeu. Ainsi, faire une image à chaque message à écrire, ça risque de très vite devenir lourd. On va donc reprendre le code précédent et remplacer le message en image pas un message écrit avec une police. Nous prendrons GeekT.ttf pour cette exemple :)

Nous allons donc rajouter à l'en tête du premier programme ceci :

Code C:
//Le Font qu'on va utiliser
TTF_Font *font;
 
//La couleur du Font
SDL_Color textColor = { 255, 255, 255 };

Comme vous le devinez facilement, nous allons donc utiliser SDL_ttf :)

Code C:
	//Initialisation de SDL_TTF 
if( TTF_Init() == -1 ) {
return false;
}
 

A rajouter dans la fonction booléenne init entre le test de mise en place de l'écran et la définition de la barre de caption de la fenêtre, à la place de ce qui concerne message

Code C:
 
//Ouverture du Font
font = TTF_OpenFont( "geekt.ttf", 28 );
 
//S'il y a une erreur dans le chargement du Font
if( font == NULL ) {
return false;
}
 

A rajouter dans la fonction booléenne load_files après le test du chargement correct du background et avant le retour de la fonction

Ici, on assigne une police ainsi que sa taille à la variable font. Nous sommes maintenant prêts à écrire avec :)

Code C:
 
void clean_up() { //Libération des surfaces
SDL_FreeSurface( background );
SDL_FreeSurface( message );
 
//Fermeture des Fonts qu'on a utilisé
TTF_CloseFont( font );
 
//On quitte SDL_ttf
TTF_Quit();
 
//On quitte SDL
SDL_Quit();
}

La fonction clean_up ne change que très peu. On ajoute juste la fermeture des fonts et on quitte SDL_ttf

Code C:
//Mise en place du texte sur la surface message 
message = TTF_RenderText_Solid( font, "Hello World !", textColor );
 
 
//S'il y a une erreur dans la mise en place du texte
if( message == NULL ) {
return 1;
}
 
//Application des images sur l'écran
apply_surface( 0, 0, background, screen );
apply_surface( 200, 175, message, screen );
 

A rajouter dans la fonction main après le chargement des fichiers

Bienvenue dans le monde SDL !

Vous pouvez télécharger la source en cliquant ici


4) Gestion d'évènements

Dans cette partie, nous allons voir comment gérer les évènements. Nous créerons donc un programme qui effectuera une action en fonction des touches directionnelles qui sont pressées, etc ...

Nous allons donc reprendre l'ensemble du programme Hello World v2.0 et le modifier petit à petit.

Commençons donc par gérer la croix qui permet de quitter le programme. (c'est pas le plus joyeux mais bon c'est nécéssaire :))
Ainsi, le programme ne se fermera plus automatiquement au bout de 3 secondes mais lorsque l'utilisateur le souhaitera.

Rajoutons donc dans l'en tête :
Code C:
 
//La structure d'événements qu'on va utiliser
SDL_Event event;
 

Cette nouvelle variable va permettre de gérer les évènements reçus.

Ensuite, remplaçons la fonction main par celle-ci :
Code C:
int main( int argc, char* args[] )
{
//Ce qui va nous permettre de quitter
bool quit = false;
 
//Initialisation
if( init() == false )
{
return 1;
}
 
//Chargement des fichiers
if( load_files() == false )
{
return 1;
}
 
//Mise en place du texte sur la surface message
message = TTF_RenderText_Solid( font, "Hello World !", textColor );
 
 
//S'il y a une erreur dans la mise en place du texte
if( message == NULL ) {
return 1;
}
 
//Application des images sur l'écran
apply_surface( 0, 0, background, screen );
apply_surface( 200, 175, message, screen );
 
//Mise à jour de l'écran
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
 
//Tant que l'utilisateur n'a pas quitté
while( quit == false )
{
//Tant qu'il y a un événement
while( SDL_PollEvent( &event ) )
{
//Si l'utilisateur à cliqué sur le X de la fenêtre
if( event.type == SDL_QUIT )
{
//On quitte le programme
quit = true;
}
}
}

 
//Libèration des surfaces et on quitte sdl
clean_up();
 
return 0;
}
 

La partie qui nous intéresse est celle en gras. On peut donc remarquer une double boucle while qui permet grâce à SDL_PollEvent d'abord de capter l'évènement puis s'il s'agit de l'évènement SDL_QUIT (clic sur la croix de fermeture) d'agir en conséquence.

La source de cette partie est téléchargeable ici

Continuons donc nos découvertes ...
Code C:
SDL_Surface *down = NULL;
SDL_Surface *up = NULL;

A rajouter dans les variables en tête afin de pouvoir afficher un message spécifique si la flèche haut ou bas sont pressées.

Code C:
void clean_up()
{
//Libération des surfaces
SDL_FreeSurface( background );
SDL_FreeSurface( message );
SDL_FreeSurface( up );
SDL_FreeSurface( down );
 
//Fermeture des Fonts qu'on a utilisé
TTF_CloseFont( font );
 
//On quitte SDL_ttf
TTF_Quit();
 
//On quitte SDL
SDL_Quit();
}

Petits rajouts concernant ces deux nouvelles variables, pour plus de propreté.

Code C:
 
int main( int argc, char* args[] )
{
//Ce qui va nous permettre de quitter
bool quit = false;
 
//Initialisation
if( init() == false )
{
return 1;
}
 
//Chargement des fichiers
if( load_files() == false )
{
return 1;
}
 
 
//Génération des surfaces de message
up = TTF_RenderText_Solid( font, "Haut a ete presse.", textColor );
down = TTF_RenderText_Solid( font, "Bas a ete presse.", textColor );
 
if(up==NULL || down==NULL)
{
return 1;
}

 
//Tant que l'utilisateur n'a pas quitté
while( quit == false)
{
//Tant qu'il y a un événement
if ( SDL_PollEvent( &event ) )
{
//Si l'utilisateur à cliqué sur le X de la fenêtre
if( event.type == SDL_QUIT )
{
//On quitte le programme
quit = true;
}
//Si une touche est pressée
else if( event.type == SDL_KEYDOWN )
{
switch(event.key.keysym.sym)
{
case SDLK_UP: message = up;
break;
case SDLK_DOWN: message = down;
break;
}
}
//Si un message a besoin d'être affiché
if( message != NULL )
{
//Application de l'image sur la l'écran
apply_surface( 0, 0, background, screen );
apply_surface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen );
 
//On met à NULL le pointeur vers la surface message
message = NULL;
}
//Mise à jour de l'écran
if( SDL_Flip( screen ) == -1 )
{
return 1;
}
}

}
 
//Libèration des surfaces et on quitte sdl
clean_up();
 
return 0;
 
}

Voici notre nouvelle fonction main.
La première partie en gras concerne la création des messages qui seront affichés en fonction de la touche pressée.
La seconde partie correspond au traitement de la touche pressée.
Ainsi, vous remarquerez que SDL_KEYDOWN permet de détecter l'appui sur une touche mais qu'après il existe un moyen particulier de récupérer quelle touche a été pressée. Il y a donc une hiérarchie afin de remonter à la touche pressée. La voici :
http://zupi.free.fr/PTuto/images/SDL/keysym.jpg
Le event.key.keysym.sym est donc justifié ainsi et retourne la touche qui a été pressée. Il suffit juste de le comparé avec les standards SDL, à savoir SDLK_UP et SDLK_DOWN en ce qui nous concerne. (Il en aurait été de même pour SDLK_LEFT et SDLK_RIGHT)

Zoom sur la ligne suivante :
Code C:
apply_surface( ( SCREEN_WIDTH - message->w ) / 2, ( SCREEN_HEIGHT - message->h ) / 2, message, screen );

Cette ligne permet de placer le nouveau message au centre parfait de l'écran. En effet, message->w récupère la largeur du message et message->h sa hauteur. Si l'on ôte ces deux valeurs de celles correspondantes à l'écran et que l'on divise le tout par 2, on obtient le centre de l'écran.

La source de cette partie est téléchargeable ici

admin

Stats :