|
Tutoriaux
- Introduction à SDL |
SDL (pour Simple
Direct Media Layer) est une librairie multimédia gratuite fonctionnant
sur plusieurs plateformes (Windows, Linux, MacOSX, BeOS, …). Elle
fournit toute une panoplie de fonctions permettant de jouer des sons,
gérer le clavier, la 2D, la 3D, … La programmation de jeux
multi plateformes s’en trouve donc facilitée.
Afin de pouvoir l’utiliser sous Delphi, nous allons utiliser Jedi-SDL
.
Le tutorial a été réalisé avec Delphi
6 Personal Edition mais il devrait certainement fonctionner sur d’autres
versions de Delphi.
Télécharger
la dernière version de Jedi-SDL.
Cette archive ZIP contient un fichier ZIP nommé "Jedi-sdl.zip".
Décompresser ce dernier dans "c:\".
Vous devez donc
obtenir l’arborescence suivante :
Aller dans le
répertoire "RunTimes\Win32" et décompresser
les fichiers :
- SDL-1.2.4-win32
- SDL_image-1.2.2-win32
- SDL_mixer-1.2.4-win32
- SDL_net-1.2.4-win32
- SDL_ttf-2.0.5-win32
- Smpeg
Copier les DLL obtenues dans le répertoire system32 ("c:\windows\system32").Suivant
ce qu’utilise votre programme, vous devrez les distribuer en partie
ou en totalité avec votre application.
Il faut ensuite paramètrer Delphi pour
que celui-ci retrouve les unités Jedi-SDL.
Dans le menu "Outils" puis "Options
d’environnement", onglet "Bibliothèques",
ajouter les chemins de bibliothéque :
- C:\JEDI-SDL\SDL\Pas
- C:\JEDI-SDL\SDL_Image\Pas
- C:\JEDI-SDL\SDL_Mixer\Pas
- C:\JEDI-SDL\SDL_Net\Pas
- C:\JEDI-SDL\SDL_Sound\Pas
- C:\JEDI-SDL\SDL_ttf\Pas
- C:\JEDI-SDL\SDLMonoFonts\Pas
- C:\JEDI-SDL\SDLSpriteEngine\Pas
- C:\JEDI-SDL\SFont\Pas
- C:\JEDI-SDL\smpeg\Pas
Dans le menu
"Fichier" de Delphi, choisir "Nouveau" puis
"Autre …" et choisir "Application console".
Le premier programme
ne fera qu’initialiser une fenêtre SDL.
program
tut01;
uses SDL;
Var screen: PSDL_surface;
Begin
if ((SDL_Init(SDL_INIT_VIDEO)=-1))
then //Initialisation
SDL
begin
exit;
end;
SDL_WM_SetCaption('Premier Programme',nil);
//Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,16,SDL_HWSURFACE);
//Attributs de la fenetres
SDL_ShowCursor(0); //Cache la
souris
SDL_Delay(5000); //On attend 5s
SDL_ShowCursor(1); //Affichage
souris
SDL_Quit; //On quitte
end. |
|
La ligne "SDL_Init(SDL_INIT_VIDEO)"
permet d’initialiser la librairie en fonction de ce que nous allons
utiliser.
Les autres valeurs usuelles sont :
Paramètre
|
Description
|
SDL_INIT_AUDIO |
Pour la gestion sonore. |
SDL_INIT_VIDEO |
Pour la gestion graphique. |
SDL_INIT_CDROM |
Pour l’accès au cdrom. |
SDL_INIT_TIMER |
Pour utiliser des timers. |
SDL_INIT_EVERYTHING |
Pour tout initialiser. |
Ces fonctions
sont à combiner avec des "or".
Par exemple, si nous voulons des fonctions sonores et des fonctions
graphiques, nous aurons la fonction "SDL_Init(SDL_INIT_VIDEO
or SDL_INIT_AUDIO)". La fonction retourne "-1" s’il
y a un problème d’initialisation.
La ligne "SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE) permet
de définir le mode vidéo à utiliser. Le premier
paramètre défini la largeur de la fenêtre, le
second la hauteur. Le troisieme concerne le nombre de bits/pixel.
Si il est égal à 0, alors c’est la valeur courante qui
est utilisée. Le dernier paramètre correspond à
diverses options que l’on peut combiner avec des "or".
Paramètre
|
Description
|
SDL_SWSURFACE |
Crée la surface en mémoire centrale. |
SDL_HWSURFACE |
Crée la surface en mémoire vidéo. |
SDL_HWPALETTE |
Donne à SDL un accès exclusif à la palette
de couleurs. |
SDL_FULLSCREEN |
Passe en mode plein ecran. |
SDL_OPENGL |
Crée une surface utilisable pour OpenGL. |
SDL_RESIZABLE |
Crée
une fenêtre redimensionnable. |
SDL_NOFRAME |
Crée
une fenêtre sans barre de titre. |
Ainsi pour ne
pas être en mode fenêtré mais plein écran,
la ligne serait :
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE
or SDL_FULLSCREEN); |
|
|
Sous
SDL, les sprites, les images et l’écran sont gérés
à l’aide de surfaces dont les variables sont de type
"PSDL_Surface". |
Par défaut, l’unité SDL ne permet de charger que des
fichiers BMP via la fonction "SDL_LOADBMP".
Nous allons donc utiliser l’unité SDL_Image permettant de chargé
d’autre type de fichier (PCX, JPG, GIF, PNG, …).
program
tut02;
uses SDL,SDL_Image;
Var screen,image: PSDL_surface;
Begin
if ((SDL_Init(SDL_INIT_VIDEO )=-1))
then //Initialisation
SDL
begin
exit;
end;
SDL_WM_SetCaption('Second Programme',nil);
//Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE);
//Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge
un JPG dans une surface
SDL_BlitSurface(image,nil,screen,nil);
//Copie image sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
SDL_ShowCursor(0); //Cache la
souris
SDL_Delay(5000); //On attend 5s
SDL_ShowCursor(1); //Affichage
souris
SDL_Quit; //On quitte
end. |
|
Pour charger le fichier
JPG, on passé par une surface nommé image. Ensuite
on effectue une copie de la surface image vers la surface screen
(et donc vers l’écran) à l’aide de la fonction "SDL_BlitSurface".
"SDL_BlitSurface" permet de faire des copies rapides d’une
surface vers une autre.
La syntaxe de cette fonction est la suivante :
SDL_BlitSurface(source,rect_source,destination,rect_destination) ; |
|
"Source" et
"destination" sont des surfaces de type "PSDL_surface".
"rect_source" et "rect_destination" sont des
variables de type "TSDL_Rect" qui permettent de définir
la zone rectangulaire à copier.
Si ces valeurs sont égales à "nil", la surface
toute entière est copiée.
Pour optimiser la fonction "BlitSurface", nous pourrions
utiliser la fonction "SDL_DisplayFormat" sur la surface
après le chargement de celle-ci.
Une variable de type "TSDL_Rect" se décompose comme
ceci :
Paramètre
|
Description
|
TSDL_Rect.X |
Position X du coin supérieur gauche. |
TSDL_Rect.Y |
Position Y du coin supérieur gauche. |
TSDL_Rect.H |
Hauteur du bloc à copier. |
TSDL_Rect.W |
Largeur du bloc à copier. |
Dans la zone de destination,
seules les valeurs .X et .Y sont utilisées
Ainsi, si nous voulons uniquement copier un bloc de 300 pixels sur
50, le programme serait le suivant :
program
tut02;
uses SDL,SDL_Image;
Var screen,image: PSDL_surface;
rect1,rect2 : TSDL_rect;
Begin
if ((SDL_Init(SDL_INIT_VIDEO)=-1))
then //Initialisation
SDL
begin
exit;
end;
SDL_WM_SetCaption('Second Programme',nil);
//Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,DL_HWSURFACE); //Attributs
de la fenetres
image:=IMG_Load(PCHAR('test.jpg'));
//Charge un JPG dans une surface
rect1.x:=0; //X coin superieur
gauche
rect1.y:=0; //Y coin superieur
gauche
rect1.w:=640; //Largeur
rect1.h:=480; //Hauteur
rect2.x:=0; //X coin superieur
gauche
rect2.y:=0; //Y coin superieur
gauche
SDL_BlitSurface(image,@rect1,screen,@rect2); //Copie
image sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
SDL_ShowCursor(0); //Cache la
souris
SDL_Delay(5000); //On attend 5s
SDL_ShowCursor(1); //Affichage
souris
SDL_Quit; //On quitte
end. |
|
Sous SDL, les sprites
sont gérés aussi par de surfaces.
program
tut03;
uses SDL,SDL_Image;
Var screen,image,sprite: PSDL_surface;
rect1 : TSDL_rect; begin
if ((SDL_Init(SDL_INIT_VIDEO)=-1))
then //Initialisation
SDL
begin
exit;
end;
SDL_WM_SetCaption('Troisieme Programme',nil);
//Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE);
//Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge
un JPG dans une surface
sprite:=IMG_Load(PCHAR('avion.bmp')); //Charge
le sprite dans une surface
sprite:=SDL_DisplayFormat(sprite);
SDL_BlitSurface(image,nil,screen,nil);
//Copie image sur ecran
rect1.x:=300;
rect1.y:=240;
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR
SDL_RLEACCEL,SDL_MapRGB(sprite.format,255,255,255));
SDL_BlitSurface(sprite,nil,screen,@rect1);
//Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
SDL_ShowCursor(0); //Cache la
souris
SDL_Delay(5000); //On attend 5s
SDL_ShowCursor(1); //Affichage
souris
SDL_Quit; //On quitte
end. |
|
Nous remarquons que ceci
ressemble fortement à tout ce que nous avons pu faire jusqu’ici.
Seule petite nouveauté, la ligne suivante :
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY
OR SDL_RLEACCEL, SDL_MapRGB(sprite.format,255,255,55)); |
|
Elle permet de définir
la transparence du sprite. En effet, l’arrière-plan du sprite
est blanc (valeur RGB : 255,255,255) et cette ligne permet
de définir cette couleur comme couleur de transparence.
Pour plus de renseignements sur cette fonction, consultez la documentation
officielle de l’API de SDL.
Dans cet exemple, nous
allons faire bouger notre petit avion lorsque l’on se sert des flèches
du clavier.
Volontairement, cet exemple n’est pas optimisé afin de bien
comprendre le fonctionnement.
program
tut04;
uses SDL,SDL_Image;
Var screen,image,sprite: PSDL_surface;
rect1 : TSDL_rect;
event: TSDL_Event;
keys: PKeyStateArr;
begin
if ((SDL_Init(SDL_INIT_VIDEO)=-1)) then
//Initialisation SDL
begin
exit;
end;
SDL_WM_SetCaption('Quatrieme Programme',nil);
//Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE); //Attributs
de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge
un JPG dans une surface
sprite:=IMG_Load(PCHAR('avion.bmp')); //Charge
le sprite dans une surface
sprite:=SDL_DisplayFormat(sprite);
SDL_BlitSurface(image,nil,screen, nil);
//Copie image sur ecran
rect1.x:=300;
rect1.y:=240;
rect1.w:=150;
rect1.h:=95;
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR
SDL_RLEACCEL,SDL_MapRGB(sprite.format,255,255,255));
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie
sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0);
//Actualise l'ecran
SDL_ShowCursor(0); //Cache la souris
Repeat
while (SDL_PollEvent(@Event) > 0)
do
begin
case Event.type_ of
SDL_QuitEv:
begin
Exit;
end;
end;
end;
keys:=PKeyStateArr(SDL_GetKeyState(nil));
if (keys[SDLK_UP]=SDL_PRESSED) and
(rect1.y>0) then //si
fleche haut
begin
SDL_BlitSurface(image,@rect1,screen,@rect1); //efface
le sprite
dec(rect1.y);
SDL_BlitSurface(sprite,nil,screen,@rect1);
//Copie sprite sur ecran
SDL_UpdateRect( screen,0,0,0,0); //Actualise
l'ecran
end;
if (keys[SDLK_DOWN]=SDL_PRESSED) and
(rect1.y<385) then //si
fleche bas
begin
SDL_BlitSurface(image,@rect1,screen,@rect1); //Efface
le sprite
inc(rect1.y);
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie
sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
end;
if (keys[SDLK_LEFT]=SDL_PRESSED) and
(rect1.x>0) then //Si
fleche gauche
begin
SDL_BlitSurface(image,@rect1,screen, @rect1);
//Efface le sprite
dec(rect1.x);
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie
sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
end;
if (keys[SDLK_RIGHT]=SDL_PRESSED) and
(rect1.x<490) then //Si
fleche droite
begin
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface
le sprite
inc(rect1.x);
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie
sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
end;
Until (keys[SDLK_SPACE]=SDL_PRESSED);
//Si appui sur espace
SDL_ShowCursor(1); //Affichage souris
SDL_Quit; //On quitte
end. |
|
La boucle WHILE permet
d’intercepter les événements. Ensuite, on récupère
l’état du clavier et en fonction des touches pressées
(SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT) , on bouge l’avion en
conséquence.
SDL permet de jouer des
modules (.mod, .xm, .s3m) en musique de fond.
Pour cet exemple, il vous faudra un fichier .mod (vous pouvez
en trouver pas mal sur le web, http://dir.yahoo.com/Entertainment/Music/Computer_Generated/MOD/).
program
tut05;
uses SDL, SDL_Image, SDL_Mixer, smpeg;
Var screen,image,sprite: PSDL_surface;
rect1 : TSDL_rect;
event: TSDL_Event;
keys: PKeyStateArr;
music: PMix_Music;
begin
if ((SDL_Init(SDL_INIT_VIDEO OR SDL_INIT_AUDIO)=-1))
then //Initialisation
SDL
begin
exit;
end;
if (Mix_OpenAudio(22040, AUDIO_U8,
1, 512) < 0) then //
initialise le systeme sonore a 22kb/8bits
begin
exit;
end;
SDL_WM_SetCaption('Cinquieme Programme',nil);
//Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE);
//Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge
un JPG dans une surface
sprite:=IMG_Load(PCHAR('avion.bmp')); //Charge
le sprite dans une surface
sprite:=SDL_DisplayFormat(sprite);
SDL_BlitSurface(image,nil,screen, nil); //Copie
image sur ecran
rect1.x:=300;
rect1.y:=240;
rect1.w:=150;
rect1.h:=95;
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR SDL_RLEACCEL,SDL_MapRGB(sprite.format,255,255,255));
SDL_BlitSurface(sprite,nil,screen,@rect1);
//Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0);
//Actualise l'ecran
SDL_ShowCursor(0); //Cache la
souris
music := Mix_LoadMUS( PChar( 'mamusique.mod' ) ); //Charge
le module .mod
Repeat
while (SDL_PollEvent(@Event) > 0)
do
begin
case Event.type_ of
SDL_QuitEv:
begin
Exit;
end;
end;
end;
keys:=PKeyStateArr(SDL_GetKeyState(nil));
if (keys[SDLK_UP]=SDL_PRESSED) and
(rect1.y>0) then //Si
fleche haut
begin
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface
le sprite
dec(rect1.y);
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie
sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
end;
if (keys[SDLK_DOWN]=SDL_PRESSED) and
(rect1.y<385) then //Si
fleche bas
begin
SDL_BlitSurface(image,@rect1,screen,@rect1); //Efface
le sprite
inc(rect1.y);
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie
sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
end;
if (keys[SDLK_LEFT]=SDL_PRESSED) and
(rect1.x>0) then //Si
fleche gauche
begin
SDL_BlitSurface(image,@rect1,screen,@rect1); //Efface
le sprite
dec(rect1.x);
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie
sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
end;
if (keys[SDLK_RIGHT]=SDL_PRESSED) and
(rect1.x<490) then //si
fleche droite
begin
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface
le sprite
inc(rect1.x);
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie
sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
end;
if (not (Mix_PlayingMusic=1))
then //Si la
musique est arretée, on la joue (permet de la
jouer en boucle)
begin
Mix_PlayMusic(music,0);
end;
Until (keys[SDLK_SPACE]=SDL_PRESSED); //Si
appui sur espace
Mix_CloseAudio();
SDL_ShowCursor(1); //Affichage
souris
SDL_Quit; //On quitte
end. |
|
|
Remarquez
que la clause "USES" a changée par rapport
à l’exemple précédent. |
Le code source est suffisamment
commenté pour ne pas avoir à détailler le fonctionnement.
Pour jouer le module, on initialise le système sonore, on
charge le fichier musical et on le joue en boucle.
SDL permet de gérer
le temps ainsi que des timers.
Ces timers permettent de faire des appels répétitifs
à des fonctions. Dans cet exemple nous allons gérer
l’animation du sprite grâce à des timers.
program
tut06;
uses SDL, SDL_Image, SDL_Mixer, smpeg;
Var screen,image,sprite,tux: PSDL_surface;
rect1 : TSDL_rect;
event: TSDL_Event;
keys: PKeyStateArr;
music: PMix_Music;
sens: boolean;
bouge : function (timer:Uint32; param:pointer) : Uint32;
time : Uint32;
timer : PSDL_TimerID;
function affichespr(interval : UInt32; param
: Pointer) : Uint32; //Fontion qui
gere le deplacement du sprite
begin // interval
et param sont des parametres definis par SDL
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface
le sprite
if sens=false then
begin
inc(rect1.y,10); // pas de deplacement
if rect1.y>=374 then
sens:=not(sens); //Hauteur fenetre(480)-(hauteur
du sprite(95)+ pas de deplacement(10))
end
else
begin
dec(rect1.y,10);
if rect1.y<=10 then
sens:=not(sens);
end;
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie
sprite sur ecran
SDL_UpdateRect( screen,0,0,0,0); //Actualise
l'ecran
affichespr:=interval; //LIGNE IMPORTANTE
SINON LE TIMER NE FONCTIONNE PAS
end; begin
if ((SDL_Init(SDL_INIT_VIDEO OR SDL_INIT_AUDIO
or SDL_INIT_TIMER)=-1)) then
//Initialisation SDL
begin
exit;
end;
if (Mix_OpenAudio(22040,AUDIO_U8,1,512)
< 0) then
begin
exit;
end;
sens:=false;
SDL_WM_SetCaption('Mon Programme',nil);
//Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32, SDL_HWSURFACE);
//Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge
un JPG dans une surface
sprite:=IMG_Load(PCHAR('avion.bmp'));
//Charge le sprite dans une surface
sprite:=SDL_DisplayFormat(sprite);
SDL_BlitSurface(image,nil,screen,nil);
//Copie image sur ecran
rect1.x:=300;
rect1.y:=240;
rect1.w:=150;
rect1.h:=95;
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR
SDL_RLEACCEL,SDL_MapRGB(sprite.format,255,255,255));
SDL_ShowCursor(0); //Cache la
souris
music:=Mix_LoadMUS( PChar('ma_musique.mod'));
SDL_UpdateRect(screen,0,0,0,0); //Actualise
l'ecran
time:=20; //Periodicite du timer
bouge:=affichespr; //Fonction
appelée par le timer
timer:=SDL_AddTimer(time,@bouge,nil);
//Initialise un timer
Repeat
while (SDL_PollEvent(@Event) >
0) do
begin
case Event.type_ of
SDL_QuitEv:
begin
Exit;
end;
end;
end;
keys:=PKeyStateArr(SDL_GetKeyState(nil));
if (not(Mix_PlayingMusic=1))
then
begin
Mix_PlayMusic(music,0);
end;
Until (keys[SDLK_SPACE]=SDL_PRESSED);
//Si appui sur espace
SDL_RemoveTimer(timer); //Detruit
le timer
Mix_CloseAudio();
SDL_ShowCursor(1); //Affichage
souris
SDL_Quit; //On quitte
end. |
|
La fonction "affichespr"
gère le déplacement du sprite. Nous ajoutons à
cette fonction les paramètres ("interval : UInt32; param
: Pointer") comme défini dans la documentation SDL.
Via "param", nous pouvons passer des paramètres
à cette fonction (nous ne nous en servirons pas dans cet
exemple). "interval" est une variable qui permet de retourner
le prochain intervalle du timer (d’où la ligne "affichespr:=interval;"
en fin de fonction).
La fonction "SDL_AddTimer" retourne un identificateur
unique pour le timer crée. C’est cet identificateur qui permet
supprimer le timer en temps voulu avec la fonction "SDL_RemoveTimer(id)".
|
A
noter, le paramètre "SDL_INIT_TIMER" qui
se trouve dans la ligne d’initialisation de SDL. |
Introduction
à SDL |
[ 21-11-2004 ] |
Exemples
d'utilisation de SDL en Delphi.
Télécharger : [114
Ko] [
sdl.zip]
Auteur : Shogun
|
|
Ici s’achève cette
introduction sur l’utilisation de la bibliothèque SDL en
Delphi, via les unités Jedi-SDL. Bien sûr, nous sommes
loin d’avoir fait le tour de toutes les possibilités offertes
par SDL.
Pour aller plus loin, voici quelques liens intéressants :
|