Télécharger la présentation
1
Codage d’un jeu de plateforme avec SDL 2.0
Formation C Codage d’un jeu de plateforme avec SDL 2.0
2
Sommaire Présentation et installation de la SDL2.0 Principes de base
Gestion du monde Mouvements du personnage Animations
3
La SDL 2.0 Bibliothèque 2D pour le jeu vidéo Écrite en C
Libre et gratuite Gestion d’images, de son Prise en charge de manettes Utilisation de la carte graphique
4
Installation de la SDL Suivre le tutoriel de developpez.com ( laurent.developpez.com/tutoriels/sdl-2/installation-et-configuration/) Projets préconfigurés pour CodeBlocks sur windows et makefile pour linux Rajouter l’option -std=c99 (project build options/compiler settings/other options sous code blocks)
5
Principes de base Boucle de jeux
initialisations update Boucle principale draw free
6
Initialisation de la SDL
int main(int argc, char** argv) { /* initialisation de la SDL */ if (SDL_Init(SDL_INIT_VIDEO) != 0 ) fprintf(stdout,"Échec de l'initialisation de la SDL (%s)\n",SDL_GetError()); return -1; } else /* Création de la fenêtre */ SDL_Window* window = NULL; window = SDL_CreateWindow("Ma première application SDL2",SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN); //création du renderer SDL_Renderer* renderer = NULL; renderer = SDL_CreateRenderer( window, 0, SDL_RENDERER_ACCELERATED); /* Initialisations */ if(window) /* Boucle principale */ /* Destructions */ /* Destruction de la fenêtre */ SDL_DestroyWindow(window); fprintf(stderr,"Erreur de création de la fenêtre: %s\n",SDL_GetError()); /* Fermeture de la SDL */ SDL_Quit(); return 0;
7
Gestion du temps SDL_GetTicks() : temps écoulé depuis le lancement du programme (en ms) SDL_Delay(int time) : met en pause durant la durée time (en ms) Framerate cherché : 60 fps Attente entre 2 frames pour limiter le framerate frameTime = SDL_GetTicks(); /* update et draw */ currentTime = SDL_GetTicks(); if(currentTime - frameTime < 1000/60) SDL_Delay(1000/60-currentTime+frameTime);
8
Principes de base Structure du code
main.c le plus léger possible Définit la boucle de jeu et délègue Préfixes ou suffixe pour les noms de fonctions (exemple : updatePlayer() ou player_update()) Choisir une convention de nommage et s’y tenir Coder en anglais ou en français, mais pas les deux
9
Principes de base Gestion des entités
Utilisation de structures : Instantiation et destruction via des fonctions typedef struct Player { float x, y, w, h, vx, vy; int isOnGround; } Player; Player* initPlayer(float x, float y, float w, float h) { Player* player = malloc(sizeof(Player)); player->x = x; player->y = y; player->w = w; player->h = h; player->vx = 0; player->vy = 0; player->isOnGround = 0; return player; } void freePlayer(Player *player) free(player);
10
L’affichage avec SDL Utilisation du renderer
SDL_SetRenderDrawColor : choisit la couleur à utiliser Arguments : renderer et composantes RGBA de la couleur SDL_RenderFillRect : dessine un rectangle avec la couleur choisie Arguments : SDL_Renderer et SDL_Rect Autres fonctions : SDL_RenderDrawLine, SDL_RenderDrawPoint, SDL_RenderClear void drawRect(SDL_Renderer *renderer, int x, int y, int w, int h) { SDL_Rect rect; rect.x = x; rect.y = y; rect.w = w; rect.h = h; SDL_RenderFillRect(renderer, &rect); }
11
L’affichage avec SDL Utilisation du renderer
SDL_SetRenderDrawColor : choisit la couleur à utiliser Arguments : renderer et composantes RGBA de la couleur SDL_RenderFillRect : dessine un rectangle avec la couleur choisie Arguments : SDL_Renderer et SDL_Rect Autres fonctions : SDL_RenderDrawLine, SDL_RenderDrawPoint, SDL_RenderClear void drawRect(SDL_Renderer *renderer, int x, int y, int w, int h) { SDL_Rect rect; rect.x = x; rect.y = y; rect.w = w; rect.h = h; SDL_RenderFillRect(renderer, &rect); } ATTENTION : l’axe y est vers le bas 800 600
12
Affichage du monde Monde = quadrillages avec cases remplies ou non
13
Affichage du monde Monde = tableau 2D hTile wTile h w
14
Affichage du monde Tableau 2D de dimensions (w, h) = tableau 1D de longueur w*h 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 id ligne i colonne j = i*w + j Colonne de la case k = k%w Ligne de la case k = k/w
15
Gestion du monde #ifndef WORLD_H_INCLUDED #define WORLD_H_INCLUDED
typedef struct World { int *tiles; int w, h, wTile, hTile; } World; World* initWorld(int w, int h, int wTile, int hTile); void freeWorld(World *world); void setTile(World *world, int x, int y, int type); int getTile(World *world, int x, int y); void drawWorld(World *world, SDL_Renderer *renderer); #endif // WORLD_H_INCLUDED World* initWorld(int w, int h, int wTile, int hTile) { World* world = malloc(sizeof(World)); world->tiles = malloc(sizeof(int)*w*h); for(int i=0; i<w*h; i++) world->tiles[i] = 0; world->w = w; world->h = h; world->wTile = wTile; world->hTile = hTile; } void freeWorld(World *world) free(world->tiles); free(world); void setTile(World *world, int x, int y, int type) { world->tiles[x+world->w*y] = type; } int getTile(World *world, int x, int y) return world->tiles[x+world->w*y];
16
Gestion du monde void drawWorld(World *world, SDL_Renderer* renderer)
hTile void drawWorld(World *world, SDL_Renderer* renderer) { SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); for(int i=0; i<world->w; i++) for(int j=0; j<world->h; j++) if(getTile(world, i, j)) drawRect(renderer, world->wTile*i, world->hTile*j, world->wTile, world->hTile); } wTile j i
17
Gestion des événements
Utilisation de la structure SDL_Event SDL_PollEvent : remplit un SDL_Event Traite le plus vieil événement non traité Renvoie 0 si tous les événements ont été traités Utilisation dans une boucle : SDL_Event event; while(SDL_PollEvent(&event)) { /* Traitement de l’événement */ }
18
Gestion des événements
SDL_Event est une structure Event.type donne le type d’événement : SDL_WINDOWEVENT : événement concernant la fenêtre SDL_MOUSEBUTTONDOWN/ SDL_MOUSEBUTTONUP : bouton de la souris appuyé/relâché SDL_KEYDOWN/SDL_KEYUP : touche du clavier enfoncée/relâchée
19
Gestion des événements
SDL_WINDOWEVENT : event.window.event donne le type d’événement (fermer la fenêtre, agrandissement, etc) SDL_MOUSEBUTTONDOWN/ SDL_MOUSEBUTTONUP event.button.button donne l’id du bouton enfoncé Clic gauche => 1, clic droit => 3 SDL_KEYDOWN/SDL_KEYUP event.key.keysym.sym donne le code de la touche appuyée Les codes des touches sont définies dans des macros (SDLK_SPACE, SDLK_RIGHT, etc)
20
Gestion des événements
void updateInput(int *exitGame, World *world, Player *player) { SDL_Event event; while(SDL_PollEvent(&event)) switch(event.type) case SDL_WINDOWEVENT: if(event.window.event == SDL_WINDOWEVENT_CLOSE) *exitGame = 1; break; case SDL_MOUSEBUTTONDOWN: if(event.button.button == 1) int tileId = getTile(world, event.button.x / world->wTile, event.button.y / world->hTile); setTile(world, event.button.x / world->wTile, event.button.y / world->hTile, 1-tileId); } break; } Gestion des événements
21
Gestion du personnage Variables importantes :
Player* initPlayer(float x, float y, float w, float h) { Player* player = malloc(sizeof(Player)); player->x = x; player->y = y; player->w = w; player->h = h; player->vx = 0; player->vy = 0; player->isOnGround = 0; player->walkDir = 0; return player; } void freePlayer(Player *player) free(player); Variables importantes : Position x et y Dimensions Vitesse x et y (vx et vy) Deux autres valeurs seront nécessaires : isOnGround, pour savoir si on peut sauter walkDir donne la direction appuyée (-1 à gauche, 1 à droite et 0 si pas de touche appuyée) typedef struct Player { float x, y, w, h, vx, vy; int isOnGround, walkDir; } Player;
22
Gestion du personnage Constantes à définir : Gravité
Accélération lors de la marche Vitesse de marche maximum Le coefficient de ralentissement (friction) Force des sauts #define MAX_FALL_SPEED 10 #define GRAVITY 0.5 #define ACCELERATION 1 #define MAX_WALK_SPEED 10 #define FRICTION 0.90 #define JUMP_STRENGTH 10
23
Gestion du personnage void updatePlayer(Player* player, World *world)
{ player->vx += player->walkDir*ACCELERATION; if(player->vx > MAX_WALK_SPEED) player->vx = MAX_WALK_SPEED; if(player->vx < -MAX_WALK_SPEED) player->vx = -MAX_WALK_SPEED; player->vx *= FRICTION; if(player->vy < MAX_FALL_SPEED) player->vy += GRAVITY; player->x += player->vx; player->y += player->vy; } void jump(Player *player) { if(player->isOnGround) player->vy -= JUMP_STRENGTH; } void drawPlayer(SDL_Renderer *renderer, Player* player) { SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); drawRect(renderer, (int)player->x, (int)player->y, (int)player->w, (int)player->h); }
24
Gestion des collisions
v v v v
25
Gestion des collisions
? v
26
Gestion des collisions
Solution : décomposition du mouvement vx vx v vx vx vx
27
Gestion des collisions
void updatePlayer(Player* player, World *world) { player->vx += player->walkDir*ACCELERATION; if(player->vx > MAX_WALK_SPEED) player->vx = MAX_WALK_SPEED; if(player->vx < -MAX_WALK_SPEED) player->vx = -MAX_WALK_SPEED; player->vx *= FRICTION; if(player->vy < MAX_FALL_SPEED) player->vy += GRAVITY; player->x += player->vx; checkCollisionsX(player, world); player->y += player->vy; checkCollisionsY(player, world); } void checkCollisionsX(Player *player, World* world) { int topY = (player->y+1)/world->hTile; int bottomY = (player->y+player->h-1)/world->hTile; int leftX = player->x/world->wTile; int rightX = (player->x+player->w)/world->wTile; for(int j=topY; j<=bottomY; j++) if(player->vx < 0 && getTile(world, leftX, j)) player->x = leftX*world->hTile+world->wTile; player->vx = 0; } if(player->vx > 0 && getTile(world, rightX, j)) player->x = rightX*world->hTile-player->w;
28
Gestion des collisions
void updatePlayer(Player* player, World *world) { player->vx += player->walkDir*ACCELERATION; if(player->vx > MAX_WALK_SPEED) player->vx = MAX_WALK_SPEED; if(player->vx < -MAX_WALK_SPEED) player->vx = -MAX_WALK_SPEED; player->vx *= FRICTION; if(player->vy < MAX_FALL_SPEED) player->vy += GRAVITY; player->x += player->vx; checkCollisionsX(player, world); player->y += player->vy; checkCollisionsY(player, world); } void checkCollisionsY(Player *player, World* world) { player->isOnGround = 0; int topY = player->y/world->hTile; int bottomY = (player->y+player->h)/world->hTile; int leftX = (player->x+1)/world->wTile; int rightX = (player->x+player->w-1)/world->wTile; for(int i=leftX; i<=rightX; i++) if(player->vy < 0 && getTile(world, i, topY)) player->y = topY*world->hTile+world->hTile; player->vy = 0; } if(player->vy > 0 && getTile(world, i, bottomY)) player->y = bottomY*world->hTile-player->h; player->isOnGround = 1;
29
Affichage d’images Chargement de bitmap : SDL_Surface* SDL_LoadBMP(char *path); Autres format : voir SDL_Image Générer une texture à partir de la SDL_Surface : SDL_CreateTextureFromSurface(SDL_Renderer* renderer, SDL_Surface *image)
30
Affichage d’images SDL_RenderCopyEx(SDL_Renderer *renderer, SDL_Texture *texture, SDL_Rect *src, SDL_Rect *dst, float rotation, SDL_Point *rotationCenter, int flip); SDL_FLIP_HORIZONTAL, SDL_FLIP_VERTICAL ou SDL_FLIP_NONE
31
Affichage d’images : les Sprites
32
Affichage d’images : les Sprites
src dst
33
Animation du personnage
#define MAX_WALK_SPEED 5 #define FRICTION 0.90 #define JUMP_STRENGTH 5 #define ANIM_SPEED 6 #define W_IMG 48 #define H_IMG 48 typedef struct Player { float x, y, w, h, vx, vy; int isOnGround, walkDir; SDL_Texture* texture; SDL_Surface* image; int animX, animY, animTime, animDir; } Player; animX animY
34
Animation du personnage
Player* initPlayer(SDL_Renderer* renderer, float x, float y, float w, float h) { Player* player = malloc(sizeof(Player)); player->x = x; player->y = y; player->w = w; player->h = h; player->vx = 0; player->vy = 0; player->isOnGround = 0; player->walkDir = 0; player->image = SDL_LoadBMP("img/player.bmp"); SDL_SetColorKey( player->image, SDL_TRUE, SDL_MapRGB(player->image->format, 255, 0, 255)); player->texture = SDL_CreateTextureFromSurface(renderer, player->image); player->animX = 0; player->animY = 0; player->animTime = 0; return player; } Couleur transparente void freePlayer(Player *player) { SDL_DestroyTexture(player->texture); SDL_FreeSurface(player->image); free(player); }
35
Animation du personnage au sol
void updatePlayer(Player* player, World *world) { /* Animation au sol */ if(player->isOnGround) player->animY = 0; if(player->walkDir == 0) player->animX = 6; } else player->animTime++; if(player->animTime > ANIM_SPEED) player->animTime = 0; player->animX++; if(player->animX >= 6) player->animX = 0; /* … */ 1 2 3 4 5 6
36
Animation du personnage au sol
/* … */ else { player->animY = 3; player->animTime++; if(player->animTime > ANIM_SPEED) player->animTime = 0; player->animX++; if(player->animX >= 3) player->animX = 0; } 1 2 3
37
Affichage du personnage
if(event.key.keysym.sym == SDLK_RIGHT) { player->animDir = 1; player->walkDir = 1; } else if(event.key.keysym.sym == SDLK_LEFT) player->animDir = -1; player->walkDir = -1; void drawPlayer(SDL_Renderer *renderer, Player* player) { SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); SDL_Rect srcrect = {player->animX*W_IMG, player->animY*H_IMG, W_IMG, H_IMG}; SDL_Rect dstrect = {(int)player->x, (int)player->y, (int)player->w, (int)player->h}; SDL_Point center = {0, 0}; if(player->animDir == -1) SDL_RenderCopyEx(renderer, player->texture, &srcrect, &dstrect, 0, ¢er, SDL_FLIP_HORIZONTAL); else SDL_RenderCopyEx(renderer, player->texture, &srcrect, &dstrect, 0, ¢er, SDL_FLIP_NONE); }
Présentations similaires
© 2024 SlidePlayer.fr Inc.
All rights reserved.