Téléchargé 2 fois
Vote des utilisateurs
2
0
Détails
Licence : Non renseignée
Mise en ligne le 24 septembre 2013
Plate-formes :
Linux, Mac, Windows
Langue : Français
Référencé dans
Navigation
DonkeyKong, Code commenté sur la SDL
DonkeyKong, Code commenté sur la SDL
Voila un jeu tout simple réalisé avec la SDL, un jeu de labyrinthe où Donkey Kong doit aller manger les bananes (j'ai volé l'idée sur un TP du sdz).
C'est un code commenté (150 lignes de commentaires sur 200 lignes de code), afin de proposer une initiation à la SDL sur un exemple concret.
Les images sont dans le zip, le code est compilé avec Free-Pascal.
Pour le faire marcher, assurez-vous de posséder les librairies de la SDL (les .dll sous Windows et les .so sous Linux).
Bonne lecture et faites moi part de vos avis.
C'est un code commenté (150 lignes de commentaires sur 200 lignes de code), afin de proposer une initiation à la SDL sur un exemple concret.
Les images sont dans le zip, le code est compilé avec Free-Pascal.
Pour le faire marcher, assurez-vous de posséder les librairies de la SDL (les .dll sous Windows et les .so sous Linux).
Bonne lecture et faites moi part de vos avis.
Voici une version compatible Delphi 6 qui n'utilise pas les unités SDL
elle nécessite cependant SDL.DLL SDL_Image.DLL libpng12-0.dll et zlib1.dll, rien que ça
NB: la libération des images se fait avec SDL_FreeSurface et non Dispose !!!!
et il est inutile de convertir AMap[y,x] en String !
elle nécessite cependant SDL.DLL SDL_Image.DLL libpng12-0.dll et zlib1.dll, rien que ça
NB: la libération des images se fait avec SDL_FreeSurface et non Dispose !!!!
et il est inutile de convertir AMap[y,x] en String !
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 | program dk; { Epitouille Sur l'idee du TP python pygame Adaptation Delphi 6 par Paul TOTH } uses //sdl, sdl_image, sysutils; type TSDL_Rect = record x, y : SmallInt; w, h : Word; end; PSDL_Rect = ^TSDL_Rect; TSDL_Surface = record flags : Cardinal; format : Pointer; w, h : Integer; pitch : Word; pixels : Pointer; offset : Integer; hwdata : Pointer; clip_rect : TSDL_Rect; unused1 : Cardinal; locked : Cardinal; Blitmap : Pointer; format_version : Cardinal; refcount : Integer; end; PSDL_Surface = ^TSDL_Surface; TSDL_KeySym = record scancode: Byte; // hardware specific scancode sym : Cardinal; // SDL virtual keysym modifier: Cardinal; // current key modifiers unicode : Word; // translated character end; TSDL_KeyboardEvent = record type_ : Byte; // SDL_KEYDOWN or SDL_KEYUP which : Byte; // The keyboard device index state : Byte; // SDL_PRESSED or SDL_RELEASED keysym: TSDL_KeySym; end; TSDL_Event = record case Byte of 0: (type_: Byte); 1: (key : TSDL_KeyboardEvent); 2: (pad : array[1..1024] of Byte); // je ne connais pas la taille exacte de cette structure end; PSDL_Event = ^TSDL_Event; const SDL_INIT_VIDEO = $00000020; SDL_DOUBLEBUF = $40000000; SDL_KEYDOWN = 2; SDL_QUITEV = 12; SDLK_UP = 273; SDLK_DOWN = 274; SDLK_RIGHT = 275; SDLK_LEFT = 276; function SDL_Init(flags: Cardinal): Integer; cdecl; external 'SDL.DLL'; function SDL_SetVideoMode(width, height, bpp: Integer; flags: Cardinal): PSDL_Surface; cdecl; external 'SDL.DLL'; procedure SDL_WM_SetCaption(title, icon: PChar); cdecl; external 'SDL.DLL'; function SDL_UpperBlit(src: PSDL_Surface; srcrect: PSDL_Rect; dst: PSDL_Surface; dstrect: PSDL_Rect): Integer; cdecl; external 'SDL.DLL'; function SDL_FillRect(dst: PSDL_Surface; dstrect: PSDL_Rect; color: Cardinal) : Integer; cdecl; external 'SDL.DLL'; function SDL_MapRGB(format: Pointer; r, b, g: Byte) : Cardinal; cdecl; external 'SDL.DLL'; function SDL_PollEvent(event: PSDL_Event): Integer; cdecl; external 'SDL.DLL'; function SDL_Flip(screen: PSDL_Surface): Integer; cdecl; external 'SDL.DLL'; procedure SDL_Delay(msec: Cardinal); cdecl; external 'SDL.DLL'; procedure SDL_Quit; cdecl; external 'SDL.DLL'; procedure SDL_FreeSurface(Surface: PSDL_Surface); cdecl; external 'SDL.DLL'; function IMG_Load(filename: PChar): PSDL_Surface; cdecl; external 'SDL_Image.DLL'; function SDL_BlitSurface(src: PSDL_Surface; srcrect: PSDL_Rect; dst: PSDL_Surface; dstrect: PSDL_Rect): Integer; begin Result := SDL_UpperBlit(src, srcrect, dst, dstrect); end; { Dans ce code nous allons decouvrir les fonctions indispensables pour faire une application graphique via la SDL. Quelques cours pouvant aider : Les pointeurs/la stack la heap. Avoir des notions de C peuvent aussi etre judicieux, etant donnee que la SDL est a la base ecrite en C, on utilise des pointeurs qui auraient ete inutiles si la SDL avait ete ecrite en pascal, ansi que pour lire la documentation. Ce n'est pas un tutoriel, mais la comprehention de ce code peu permettre a quelqu'un de se lancer dans la SDL sans connaissance a ce sujet Sur ce, bonne lecture, et faites moi part de vos suggestions/demandes. Merci } {On cree notre type map, elle va contenir notre niveau qui est en fait une grille } { de 15 sur 15, pourquoi char, car les objects vont etre representes via des char} { (voir level1.map)} {a : arrive ; d : depart ; m : mur ; 0 : vide } type TMap = array[1..15, 1..15] of Char; {Initialitsation d'une fenetre avec la SDL} function NewWindow(x, y : Integer ; Caption : PChar) : PSDL_Surface; var {Notre fenetre est un PSDL_Surface, c'est a dire un pointeur sur une surface} {Une surface est en fait une map de pixel, donc une image par exemple, ici, } {notre fenetre} PWindow : PSDL_Surface; begin {On va initialiser la SDL, retourne -1 en cas d'erreur} {Attention, ici je ne verifie pas les fonctions, car ce n'est pas le but} {je vous donne par contre les valeurs de retours des fonctions pouvant facilement} {echouee, a vous dans vos code de les verifiers} SDL_Init(SDL_INIT_VIDEO); {Ici on va creer notre fenetre, x et y sont la taille, 32 est le nombre } {de bit par pixel, apres viennent les flags, SDL_DOUBLEBUF est utilise pour} {le double buffering, cf la doc pour les autre flags} PWindow := SDL_SetVideoMode(x, y, 32, SDL_DOUBLEBUF); {Ici, on va changer le titre de la fenetre, le 1er argument est un PChar qui } {est le titre, le 2eme argument est l'icon de la fenetre, le 2eme argument} {est le chemin de l'icon (Un PChar egaement)} SDL_WM_SetCaption(Caption, Nil); {Retournons notre jolie fenetre} //Exit(PWindow); Result := PWindow; end; procedure LoadImage(var AImage : Array of PSDL_Surface); begin {On va se servir d'une autre librairie de la SDL (SDL_image) } {Elle va nous permettre de charger des images autre que des .bmp} {Nous allons donc charger dans un tableau nos images .png } {Cette fontion renvoie un PSDL_Surface (je repete, une map des pixels)} {Comme on travail avec des pointeurs, cette fonction renvoie nil en cas d'erreur} AImage[1] := IMG_Load('./arrivee.png'); AImage[2] := IMG_Load('./depart.png'); AImage[3] := IMG_Load('./mur.png'); AImage[4] := IMG_Load('./dk_bas.png'); AImage[5] := IMG_Load('./dk_haut.png'); AImage[6] := IMG_Load('./dk_droite.png'); AImage[7] := IMG_Load('./dk_gauche.png'); {Un exemple de gestion d'erreur : } {if AImage[1] = nil then GestionErreur} end; procedure LoadMap(APath : String ; var AMap : TMap); var LevelMap : Text; Buffer : String; x, y : Integer; Iterator : Char; Index : Integer; begin {Dans cette fonction, on va transformer le contenu d'un fichier double } {tableau de char} {rien a voir la SDL, je n'explique pas} y := 1; Assign(LevelMap, APath); Reset(LevelMap); while not Eof(LevelMap) do begin Readln(LevelMap, Buffer); x := 1; //for Iterator in Buffer do for Index := 1 to Length(Buffer) do begin Iterator := Buffer[Index]; AMap[y][x] := Iterator; x := x + 1; end; y := y + 1; end; Close(LevelMap); end; procedure DrawScene(AWindow : PSDL_Surface ; var AImage : Array of PSDL_Surface ; var AMap : TMap); var x, y : Integer; {TSDL_Rect est une structure (record) de la SDL qui definie une position} {Elle a comme champs : x, y, w, h. Ici seul x et y vont nous servir} Position : TSDL_Rect; begin for y := 1 to 15 do begin for x := 1 to 15 do begin {On va donc assigner les bonnes coordonnees, on enleve 1 car notre } {tableau commence a 1 alors que les coordonnees de la fenetre commence } {a 0} Position.x := (x - 1) * 30; Position.y := (y - 1) * 30; if { String !!! }(AMap[y][x]) = 'm' then {Le blit surface est la fonction qui permet d'afficher une image} {(SDL_Surface si vous avez suivi) sur notre ecran (Qui est aussi} {un PSDL_Surface). Elle prend en argument, l'image a afficher, } {la partie de l'image (Qui est un PSDL_Rect) (et oui, le mot var} {n'existant pas en C, il faut passer des adresses), la surface de} {destination, et enfin un PSDL_Rect qui sont les positions} {Dans notre code, on choisie l'image a blitter en fontion de la} {lettre contenue dans notre TMAP} SDL_BlitSurface(AImage[3], nil, AWindow, @Position); if (AMap[y][x]) = 'a' then SDL_BlitSurface(AImage[1] , nil, AWindow, @Position); if (AMap[y][x]) = 'd' then SDL_BlitSurface(AImage[2] , nil, AWindow, @Position); end; end; end; procedure DrawDK(AWindow : PSDL_Surface; x, y : Integer ; ASide : PSDL_Surface); var {Ici nous aurions pu utiliser un PSDL_Rect, et l'allouer via GetMem} {Il aurait bien sur le liberer a la fin pour eviter les fuites de memoires} {Mais en utilisant un TSDL_Rect, l'allocation/desalocation se fait toute seule} {Etant donne que la ressource est cree sur la pile (Un petit cours sur la} {Heap/Stack ou Tas/Pile peuvent etre utiles)} Position : TSDL_Rect; begin Position.x := (x - 1) * 30; Position.y := (y - 1) * 30; {Pareil qu'au dessus, on choisie la position, l'image, puis on la blit} SDL_BlitSurface(ASide, nil, AWindow, @Position); end; function IsAvailable(AMap : TMap; x, y : Integer) : Boolean; begin {Cette fonction, nous renvoie vrai si la case est disponible sinon false} { m = mur} {Rien a voir non plus avec la SDL} (** if (x = 0) or (x = 16) or (y = 0) or (y = 16) then Exit(False); if AMap[y][x] <> 'm' then Exit(True) else Exit(False); **) Result := (x > 0) and (x < 16) and (y > 0) and (y < 16) and (AMap[y, x] <> 'm'); end; function IsWin(AMap : TMap; x, y : Integer) : Boolean; begin {Nous renvoie si oui ou non (true or false) le personnage est sur la case} {arrivee : 'a'} {Encore rien a voir avec la SDL :D } (** if AMap[y][x] = 'a' then Exit(True) else Exit(False); **) Result := AMap[y, x] = 'a'; end; procedure ClearBackGround(Screen : PSDL_Surface); var r, g, b : Integer; Position : TSDL_Rect; begin {Notre couleur sera noire : RGB = 0 0 0 } r := 0; g := 0; b := 0; {On defenit notre carre } Position.x := 0; Position.y := 0; {Petit rappelle Screen est notre fenetre, donc un pointeur, pour acceder a ses} {champs : on utilise l'operateur de deferencement '^', Un cours sur les pointeurs} {est necessaire pour etre a l'aise} Position.w := Screen^.w; Position.h := Screen^.h; {La fontion FillRect nous permet de remplir d'une couleur une image (ou une fenetre)} {si vous avez suivi, c'est presque la meme chose} {Elle prend en argument : l'image de destination, les carre, puis une couleur} {Pour convertir notre RGB en couleur pour la SDL (UInt32) on utilise alors} {MapRGB (cf : doc)} SDL_FillRect(Screen, @Position, SDL_MapRGB(Screen^.Format, r, g, b)); end; procedure MainLoop(AWindow : PSDL_Surface ; var AImage : Array of PSDL_Surface ; var AMap : TMap); var {TSDL_Event (et son reciproque PSDL_Event) est le type dans la SDL qui } {contient un evenement, un clique, la pression d'une touche etc...} Event : TSDL_Event; {Variable qui quand est a true, ordonne de quitter} Fin : Boolean; {les positions en x et en y de notre donkeykong} dk_x : Integer; dk_y : Integer; {Side est le cote de mon donkey kong que je veux afficher, c'est un element} {de mon tableau de PSDL_Image} Side : PSDL_Surface; begin {J'initialise mes variables} Fin := False; dk_x := 1; dk_y := 1; {je dis que mon donkey kong regarde vers la droite au debut} {on peu voir les correspondace dans la fonction LoadImages} Side := AImage[6]; {Tant qu'on a pas quitter ou gagner} while not Fin do begin {SDL_PollEvent prendre en parametre un PSDL_Event (Event chez nous est)} {une TSDL_Event, l'operateur @ nous permetre d'avoir son adresse, donc} {de convertir un TSDL_quelquechose et PSDL_quelquechose} {La fonction PollEvent remplie notre event avec le prochaine evenement} {de la pile d'evenement, elle retourne 1 si il y a encore des evemenets dans} {la pile et 0 si c'est le dernier, ici, on va lire tous les evenements} {jusqu'au dernier} while SDL_PollEvent(@Event) <> 0 do begin {Pour acceder au type d'evenement, il suffit d'aller voir son champs} {Type_, l'underscore est ici car Type est un mot reserve en pascal} {alors qu'il ne l'est pas en C} {Ici, on dit que quand on rencontre l'evenement QUITEV (l'evenement} {de la croix en haut a droite) on quite } if Event.Type_ = SDL_QUITEV then Fin := True; {ici on regarde l'appuis sur une touche} if Event.Type_ = SDL_KEYDOWN then begin {on sait donc qu'une touche est appuiyee, mais nous ne savons pas} {laquelle, le champs key.keysym.sym d'une TSDL_Event nous permet} {de recuperer le code de la touche pressee} {On peut donc la comparer au constante de touche de la SDL} if Event.key.keysym.sym = SDLK_DOWN then {Vous l'avez surrement compris, la touche du bas} begin {On test alors si la case y + 1 est libre} if IsAvailable(AMap, dk_x, dk_y + 1) then begin {Si oui, on fait donc descendre notre donkeykong} Inc(dk_y); {Puis on dit a notre donkeykong de regarder vers le bas} Side := AImage[4]; end; end; {Je me terrais a partir d'ici car on retrouve 4 fois le meme bloque} { Pour tester nos 4 fleches de clavier} if Event.key.keysym.sym = SDLK_UP then begin if IsAvailable(AMap, dk_x, dk_y - 1) then begin Dec(dk_y); Side := AImage[5]; end; end; if Event.key.keysym.sym = SDLK_LEFT then begin if IsAvailable(AMap, dk_x - 1, dk_y) then begin Dec(dk_x); Side := AImage[7]; end; end; if Event.key.keysym.sym = SDLK_RIGHT then begin if IsAvailable(AMap, dk_x + 1, dk_y) then begin Inc(dk_x); Side := AImage[6]; end; end; {On va appeler notre fonction qui va nous dire si on a gagner} {Si elle nous renvoie vrai, quittons tout simplement le jeu} if IsWin(AMap, dk_x, dk_y) then Fin := True; end; end; {Maintenant, appelons en boucle notre affichage} {1 - on efface l'ecran} ClearBackGround(AWindow); {2 - On affiche le decors} DrawScene(AWindow, AImage, AMap); {3 - On affiche notre donkeyKong} DrawDK(AWindow, dk_x, dk_y, Side); {4 - On raffraichit notre ecran} {cette fonction necessite quelques explications} {quand on blit une surface, on l'ecris sur un buffer (une autre fenetre} {en memoire) qui n'est pas affichee} {on doit alors dire, d'afficher notre buffer} {attention, doit etre appelee qu'une fois dans la boucle principale} { et quand tout les affichages memoires sont finit, sinon, risque de } {clignotement} SDL_Flip(AWindow); {On attends 30ms seconde, histoire de faire du bien a notre CPU, sinon} {il tourne a 100%, c'est dommage pour un donkeykong quand meme :)} SDL_Delay(30); end; end; {ici, on va libere nos images allouees via IMG_Load un peu plus tot} procedure FreeImages(var Image : Array of PSDL_Surface); var i : Integer; begin for i := 1 to 7 do begin // Dispose(Image[i]); QUOI ?! SDL_FreeSurface(Image[i]); end; end; var {Nos variables principales on a Notre fameux TMap, la liste des images} {Puis pour finir, le pointeur sur notre fenetre} Map : TMap; Image : Array [1..8] of PSDL_Surface; PWindow : PSDL_Surface; begin {On va charger la map depuis notre fichier (cela rends les maps adaptables)} LoadMap('./level1.map', Map); {Chargons maintenant les images dans notre tableau} LoadImage(Image); {Creeons notre fenetre} PWindow := NewWindow(450, 450, 'Donkey Kong'); {Maintenant que tout est pres, nous pouvons lancer le jeu} MainLoop(PWindow, Image, Map); {Liberons les ressources} FreeImages(Image); {Quitons proprement} SDL_Quit; end. |
juste pour info, j'ai fait une petite démo de type PacMan avec ce programme en pure VCL (ImageList)
http://www.developpez.net/forums/d13...t/#post7583089
http://www.developpez.net/forums/d13...t/#post7583089
je n'ai pas résisté
en voici une version GDI+, elle aurait très bien pu être une simple version GDI vu que le seul cas de transparence est la case de départ...mais bon, j'ai voulu aussi conserver le format PNG plus compact que le BMP et GDI+ sait lire nativement du PNG. En passant sur un format ICO on aurait pu gérer facilement la transparence aussi.
A part GDI+ (qui est présent depuis XP) ce projet ne nécessite aucune DLL - mais ne fonctionne que sous Windows, alors que SDL est disponible sur Windows, Mac et Linux.
[ATTACH]127477d1/a/a/a" /> (mis à jour)
NB: j'ai mis aussi toutes les images dans un seul PNG et n'ai conservé la transparence que pour Donkey (sur la case de départ). La compression d'une grande image est plus efficace que la compression de chaque image séparée.
en voici une version GDI+, elle aurait très bien pu être une simple version GDI vu que le seul cas de transparence est la case de départ...mais bon, j'ai voulu aussi conserver le format PNG plus compact que le BMP et GDI+ sait lire nativement du PNG. En passant sur un format ICO on aurait pu gérer facilement la transparence aussi.
A part GDI+ (qui est présent depuis XP) ce projet ne nécessite aucune DLL - mais ne fonctionne que sous Windows, alors que SDL est disponible sur Windows, Mac et Linux.
[ATTACH]127477d1/a/a/a" /> (mis à jour)
NB: j'ai mis aussi toutes les images dans un seul PNG et n'ai conservé la transparence que pour Donkey (sur la case de départ). La compression d'une grande image est plus efficace que la compression de chaque image séparée.
Très intéressant.
Je n'ai pas encore réussi à faire marcher le jeu. J'ai compilé le programme ; j'ai ajouté dans le dossier SDL.dll et SDL_image.dll : je n'obtiens qu'un écran noir. Mon système d'exploitation est Windows 8.
Je n'ai pas encore réussi à faire marcher le jeu. J'ai compilé le programme ; j'ai ajouté dans le dossier SDL.dll et SDL_image.dll : je n'obtiens qu'un écran noir. Mon système d'exploitation est Windows 8.
Bonjour,
L'ecran noir, je n'ai aucune idée d'où ça peu venir, les possibilitées sont :
- Ta dll est celle de la SDL 2.0 alors que mon code utilise la SDL 1.* (Mais ça m'etonnerai)
- Les images ne sont pas dans le repertoire courant (Plus probable)
Merci pour ton retoure, essaye de voir si les images sont bien chargées (dans la procedure, il y a les instructions pour detecter cela)
L'ecran noir, je n'ai aucune idée d'où ça peu venir, les possibilitées sont :
- Ta dll est celle de la SDL 2.0 alors que mon code utilise la SDL 1.* (Mais ça m'etonnerai)
- Les images ne sont pas dans le repertoire courant (Plus probable)
Merci pour ton retoure, essaye de voir si les images sont bien chargées (dans la procedure, il y a les instructions pour detecter cela)
Les DLL, je les ai prises dans le Tetris de M.Dlb. (Très beau programme, soit dit en passant, qui mériterait un peu plus de visibilité : le lien vers l'archive n'est donné, si je ne me trompe, nulle part ailleurs que dans ce message.)
Pour les images, je les ai laissées dans le même dossier que le programme : celui aussi où j'ai copié les DLL. Je vais regarder ça de plus près ce soir.
Pour les images, je les ai laissées dans le même dossier que le programme : celui aussi où j'ai copié les DLL. Je vais regarder ça de plus près ce soir.
ok cool, n'hesite pas a me faire savoir si tu as des news. En utilisant SDL_Image en pascal, j'ai vu que la fonction IMG_init() n'existait pas en pascal. et du coup si je charge les images apres avoir fait un SDL_Init, on ne voyait pas non plus les images, peut etre que ca vient aussi de la. Bonne recherche
Beau travail, c'est un bel exemple de l'utilisation de la SDL!
J'approuve!
J'approuve!
Developpez.com décline toute responsabilité quant à l'utilisation des différents éléments téléchargés.