Chinese (People's Republic of China)  English  Français


Supinfo-Projects.com
Tous les projets des élèves ingénieurs de Supinfo



Projets
  Dernier Projet
  Les plus populaires
  Tous les Projets

185 Visiteurs
3168 Projets


My Supinfo-Projects

   Connectez-vous
   Créez un Compte


Synopsis

   44 Visites
   Note INTERNET : 18.6
    (3 Votants)
   0 Commentaires

   Lire l'article

Evaluez cet article

20
18
16
14
12
10
8
6
4
2
0


Commentez cet article

Auteur :

Email :

Votre commentaire :



 
2005 - Pérennisation
Creation d'un moteur de jeu base sur les tiles
[40 mn de lecture - paru le 5/17/2005 5:39:48 PM - Public : Confirmé]

Auteur

cuella_sSamuel CUELLA
Elève-Ingénieur Supinfo Paris
Promotion SUPINFO 2009

   Lui écrire
   Tous les projets de cet auteur
   Le mini-CV de cet auteur

3 Ameliorations

3.1 Principe des Animations

Ces deux aspects du jeu ont un point commun, il s'agit d'animations, d'images
qui changent d'un tour de boucle principale sur l'autre.
Ils seront donc basés sur la même structure de donnée.
Voyons tout d'abord comment créer une animation anonyme, c'est à dire une structure associée à une fonction qui retourne l'image suivante.

3.1.1 Structure

Voici le type de base :

typedef struct{
    int n_frames;
    int current_frame;
    int playing;
    int loop;
    SDL_Surface **frames;
}anim_t;


    Il comporte 5 champs :
  • Le nombre d'images composant l'animation       
  • Le numéro de l'image devant être affichée au prochain tour
  • Un flag indiquant si l'animation doit être jouée ou non    
  • Un flag indiquant si l'animation doit repartir au début une fois la dernière          image atteinte       
  • Un tableau de pointeurs sur les images

Intéressons-nous aux champs playing et loop :

Une animation dont le champ playing est à 0 renverra toujours l'image courante c'est à dire par défaut l'image n°0, sans passer à la suivante ce qui peut être utile pour un levier par exemple :
Le champ playing est à 0, l'animation est arrêtée et montre le levier en position
haute, si le joueur l'actionne, le champ playing passe à 1 et le levier s'abaisse !
Bien entendu, le champ loop doit être à 0, sous peine de voir le levier monter et descendre tout seul !
Ce champ loop à 0 peut aussi servir pour une explosion par exemple :
En général les objets n'explosent qu'une fois !


3.1.2 Creation

Remplir tous les champs de la structure « à la main » serait fastidieux,
surtout la séquence d'images !
La fonction suivante permet de créer une animation avec autant d'images que vous
le souhaitez :

#include

anim_t *create_animation( int loop, int playing ,int n_frames, ... )
{
    va_list ap;
    anim_t *rv;
    int i;

    rv = ( anim_t * )malloc( sizeof(anim_t) );
    if( !rv )
        return(NULL);
    memset(rv, 0, sizeof(anim_t));
   
    rv->frames = ( SDL_Surface ** )malloc( sizeof(SDL_Surface *) * n_frames );
    if( !rv->frames )
        return(NULL);

    va_start(ap, n_frames);   

    for( i = 0; i < n_frames; i ++ )
        rv->frames[i] = va_arg(ap, SDL_Surface *);

    rv->n_frames = n_frames;
    rv->loop = loop;
    rv->playing = playing;

    va_end(ap);
    return(rv);
}

N'oubliez pas d'inclure le nouvel entête stdarg.h, il est indispensable aux fonctions
acceptant un nombre variable d'arguments.
Cette fonction renvoie l'adresse d'une structure anim_t dûment allouée et remplie pourvu que l'on lui passe en argument les flags loop et playing décrits plus haut, le nombre d'images composant l'animation, puis les images elles-mêmes sous forme de pointeurs sur SDL_Surface.
Afin de gérer les arguments en nombre variable, il faut créer une variable de type
va_list, puis l'initialiser grâce à la macro va_start qui prends en premier paramètre
la liste des arguments déclarée plus haut ainsi que le dernier argument connu, ce qui dans notre cas devient va_start(ap, n_frames).
Le nombre d'argument est inconnu à la compilation, mais pas à l'exécution !
Il y a autant d'arguments dans la liste que l'indique n_frames, ainsi nous récupérons
touts les arguments grâce à la macro va_arg qui prends en paramètre la liste des
arguments, et le type attendu, puis retire l'argument suivant de la liste et le renvoie.
Comme nous attendons des arguments de type pointeur sur SDL_Surface nous
ecrivons va_arg(ap, SDL_Surface *).

ATTENTION: Passer des arguments d'un type différent causera une erreur !

Enfin, nous libérons la mémoire occupée par la liste des arguments grâce à
va_end(ap), puis nous retournons l'adresse de notre animation.

3.1.3 Affichage

La structure qui représente l'animation n'est pas conçue pour être manipulée directement, mis à part pour ses champs loop et playing. Pour la jouer, il suffit d'afficher l'image suivante sur l'écran.
L'image suivante d'une animation est obtenue par l'appel de la fonction
get_next_frame avec l'animation concernée en paramètre :

SDL_Surface *get_next_frame( anim_t *anim )
{
    int frame_returned;

    frame_returned = anim->current_frame;
    if( anim->playing ){
        if( anim->current_frame < (anim->n_frames - 1) ){
            anim->current_frame++;
        }
        else{
            if( anim->loop )
                anim->current_frame = 0;
        }
    }

    return(anim->frames[frame_returned]);
}

Cette fonction simple gère l'animation, si elle doit être jouée ou boucler.

3.2 Un joueur animé

Plus rien ne nous oblige maintenant à conserver un joueur immobile :
Faisons le marcher !
Quatre animations sont nécessaires : lorsqu'il se dirige en haut, en bas, à droite ou encore à gauche.

3.2.1 Structure

Améliorons notre structure de base:

typedef struct{
    SDL_Surface *img;
    anim_t *up, *down, *left, *right;
    int x,y;
    int vx,vy;
}player_t;

Nous conservons l'image courante dans le champ img qu'il suffira de modifier
dans la fonction d'affichage de manière à refléter l'état du joueur selon sa
direction.

3.2.2 Creation

La structure ayant changée, il nous faut aussi modifier la fonction de création :

player_t *make_player( SDL_Surface *def, anim_t *up, anim_t *down, anim_t *left, anim_t *right, int x, int y )
{
    player_t *rv;
   
    if( !def )
        return(NULL);

    rv = (player_t *)malloc( sizeof(player_t) );
    if( !rv )
        return(NULL);
    memset( rv, 0, sizeof(player_t) );

    rv->img = def;
    rv->up = up;
    rv->down = down;
    rv->left = left;
    rv->right = right;
    rv->x = x;
    rv->y = y;

    return(rv);
}

le paramètre def contiendra l'image présentée au tout début du jeu,  la
première image d'une des animations suivant dans quelle direction regarde le joueur
lors du chargement.
Rien ne nous oblige à utiliser cette fonctionnalité !
Le seul pointeur obligatoire est def : si les 4 pointeurs sur animation sont nuls,
il n'y aura simplement pas d'animation.

3.2.3 Affichage

Pour que l'animation soit visible, si elle existe, la fonction d'affichage du joueur
doit être capable de prendre en charge cette nouvelle fonctionnalité :

int draw_player( level_t *level, player_t *player )
{
    SDL_Rect player_rect;

    if( !(player && level ) )
        return(-1);

    player_rect = player_coords_to_screen_area( level, player );

    if( player->vy ){
        if( player->vy < 0 ){
            if( player->up )
                player->img = get_next_frame( player->up );
        }
        else{
            if( player->down )
                player->img = get_next_frame( player->down );
        }
               
    }
    else{
        if( player->vx ){
            if( player->vx < 0 ){
                if( player->left )
                    player->img = get_next_frame( player->left );
            }
            else{
                if( player->right )
                    player->img = get_next_frame( player->right );
            }
               
        }
    }

    SDL_BlitSurface(player->img, NULL, screen, &player_rect);

    return(0);
}

Si l'animation correspondante existe, on détermine la direction grâce au...
Vecteur vitesse ! Tout simplement.
Remarquez que vous pouvez détailler le mouvement autant que vous le souhaitez :
Il n'y a aucune limite : l'animation qui permet au joueur d'aller sur sa gauche par exemple peut très bien comporter 2 ou 20 images !

3.3 Supports de multiples formats de fichier

Le nombre d'images nécessaires devient de plus en plus grand, et le support de la
transparence pourrait être appréciable...
Utilisons SDL_Image !
SDL_Image est une librairie additionnelle à la SDL qui permet de charger une
Grande variété de formats, dont le png, dans une SDL_Surface.

Pour l'utiliser, rien de plus simple :

  • Tout d'abord l'installer, bien sur elle se trouve sur le même site que SDL www.libsdl.org
  • Ajouter l'entête SDL/SDL_image.h : #include 
  • A la compilation ajouter -lSDL_image, ce qui donne : gcc sample.c -o sample `sdl-config -libs --cflags`-lSDL_image
  • Enfin modifions la fonction permettant de charger une image :


SDL_Surface *load_img_from_file( char *filename )
{
    SDL_Surface *rv;
   
    if( !filename )
        return(NULL);


    rv = IMG_Load(filename);

    return(rv);
}

Il suffit de remplacer SDL_LoadBMP par IMG_Load, c'est tout !
Vous voilà prêt à supporter quasiment tous les formats d'images en circulation.

3.4 Le nouveau main()

Il ne reste plus qu'à reprendre notre main() pour pour profiter de nos améliorations :


int main(void)
{
    int i,j;
    SDL_Surface *pict = load_img_from_file("tile.png");

    level_t *level = create_tile_map( 40, 50 );

    for( i = 0; i < level->width; i++ ){
        for( j = 0; j < level->height; j++ ){
            level->map[i][j].img = pict;
        }
    }

    anim_t *up = create_animation( 1, 1, 6,
                                                            load_img_from_file("Player1H1.png"),                                                                     load_img_from_file("Player1H2.png"),
                                                            load_img_from_file("Player1H3.png"),
                                                            load_img_from_file("Player1H4.png"),
                                                            load_img_from_file("Player1H5.png"),
                                                            load_img_from_file("Player1H6.png")
                                               );
   
    anim_t *down = create_animation( 1, 1, 6,
                                                            load_img_from_file("Player1B1.png"),
                                                            load_img_from_file("Player1B2.png"),
                                                            load_img_from_file("Player1B3.png"),
                                                            load_img_from_file("Player1B4.png"),
                                                            load_img_from_file("Player1B5.png"),
                                                            load_img_from_file("Player1B6.png")
                                                   );
   
    anim_t *left = create_animation( 1, 1, 6,
                                                            load_img_from_file("Player1G1.png"),
                                                            load_img_from_file("Player1G2.png"),
                                                            load_img_from_file("Player1G3.png"),
                                                            load_img_from_file("Player1G4.png"),
                                                            load_img_from_file("Player1G5.png"),
                                                            load_img_from_file("Player1G6.png")
                                                );

    anim_t *right = create_animation( 1, 1, 6,
                                                            load_img_from_file("Player1D1.png"),
                                                            load_img_from_file("Player1D2.png"),
                                                            load_img_from_file("Player1D3.png"),
                                                            load_img_from_file("Player1D4.png"),
                                                            load_img_from_file("Player1D5.png"),
                                                            load_img_from_file("Player1D6.png")
                                                 );
   
    player_t *player = make_player(down->frames[0],up,down,left,right,0,0);

    if( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
                printf("Couldn't initialize SDL: %s\n", SDL_GetError());
                exit(EXIT_FAILURE);
    }

    atexit(SDL_Quit);

    screen = SDL_SetVideoMode(800,
                                                600,
                                                24,   
                                                SDL_HWSURFACE|SDL_DOUBLEBUF);
   
     if ( !screen  ) {
            printf("Unable to set 800x600x24 video mode: %s\n", SDL_GetError());
            exit(EXIT_FAILURE);
     }

    main_loop(level, player);
   
    exit(EXIT_SUCCESS)
}   

Nous créons les 4 animations, comportant chacune 6 images, et nous les réglons pour
se jouer, et bien entendu elles doivent toujours recommencer pour que l'effet de
marche soit réaliste.
Puis, nous créons notre joueur dirige vers le bas, sur la tile(0,0).
Enfin, une fois SDL correctement initialisée, nous lançons la boucle principale
Qui durera jusqu'à l'appui sur la touche ESCAPE.

3.5 Des tiles animés

Puisque nous avons tous les éléments en main pour réaliser des animations, il serait
dommage de se limiter au joueur, donnons une vie aux tiles !

3.5.1 Structure

Il suffit, comme pour le joueur, de modifier légèrement la structure :

typedef struct __tile_t{
    SDL_Surface *img;
    anim_t *anim;
    int blocked;
}tile_t;

Ici, pas de fonction de création  à modifier, puisque c'est la fonction de création de la
carte qui se charge d'allouer les tiles. De plus, le nouveau champ sera automatiquement
mis à NULL par memset, puisque cette dernière se base sur la taille de la structure : Il n'y à rien à changer !

3.5.2 Affichage

Par contre, si l'on veut que l'animation soit « rendue » il faut rajouter deux lignes
à la fonction d'affichage du niveau :

int draw_level( level_t *level, player_t *player )
{
    int i,j;
    SDL_Rect dest_rect;

    if( !level )
        return(-1);

    SDL_FillRect( screen, NULL, SDL_MapRGB(screen->format,0,0,0) );

    for( i = 0; i < level->width; i++ ){
        for( j = 0; j < level->height; j++ ){
            dest_rect.x = i * level->map[i][j].img->w - level->x_offset;
            dest_rect.y = j * level->map[i][j].img->h - level->y_offset;
            if( level->map[i][j].anim )
                level->map[i][j].img = get_next_frame(level->map[i][j].anim);
            SDL_BlitSurface(level->map[i][j].img,NULL,screen, &dest_rect);
        }
    }
    return(0);
}

Si le tile contient une animation, on met à jour son champ img, tout simplement !

ATTENTION: Tout comme une fonction particulière( ou directement dans le main ) doit être chargée de remplir la carte, elle doit aussi faire pointer le champ anim de la structure vers une animation valide, toute autre valeur que celle d'origine(NULL) doit être une animation valide, sinon une erreur de segmentation se produira.

Une fois l'univers animé, la plus grande partie du travail est accomplie, nous pouvons maintenant songer sérieusement à l'écriture d'un jeu basé sur notre moteur, mis à part...
Qu'il risque d'être bien difficile de développer un minimum d'interactivité !
Aucun événement, même pas de touche action !
 

3.6 Evénements

Nous avons choisi de gérer les événements du jeu grâce au mécanisme des fonctions
de rappel ou encore callbacks :
Un événement se produit( le joueur se déplace, le bouton action est pressé sur une tile
"sensible"...) et une fonction définie par le programmeur se déclenche.
Pour gérer les événements, il nous faut commencer par modifier notre structure tile_t :

3.6.1 Structure

typedef struct __tile_t{
    SDL_Surface *img;
    anim_t *anim;
    int sensitive;
    int blocked;
    void (*sensitive_callback)(struct __tile_t *, player_t *, void *);
    void (*over_callback)(struct __tile_t *, player_t *, void *);
    void *userdata;
}tile_t;
 
quatre nouveaux champs font leur apparition :

  • Un flag indiquant si la case est `sensible' ou non.  
  • Un pointeur générique permettant de passer des données arbitraires aux fonctions de callback.
  • Deux pointeurs sur fonctions ayant le même prototype réagissant aux deux événements.

Et c'est ici que le __tile_t trouve son utilité :
Il est en effet impossible de définir le (proto)type des fonctions de cette manière :
(*f)(tile_t *, player_t *, void *), en effet, tile_t n'existe pas encore, alors que __tile_t si.

Le premier callback( sensitive_callback ) sera appelé si le joueur presse le bouton d'action sur une tile dont le flag sensitive est à 1. Modifier ce flag revient à rendre sensible une case qui ne l'était pas ou inversement : tel bouton devient fonctionnel lorsque tel levier a ete actionné...
Le callback over_callback est appelé dès que le joueur arrive sur la tile concernée.
Tout comme dans le cas de l'animation, ces flags et callbacks doivent être réglés et
connectés après avoir crée la carte.

3.6.2 Implémentation

Adaptons la seule fonction concernée : move_player

int move_player( level_t *level, player_t *player )
{
    SDL_Event event;
    SDL_Rect player_rect;

    while( SDL_PollEvent( &event ) ){
        switch( event.type ){
            case SDL_KEYDOWN:
                switch( event.key.keysym.sym ){
                    case SDLK_LEFT:
                        player->vx = -1;
                        break;
                    case SDLK_RIGHT:
                        player->vx =  1;
                        break;
                    case SDLK_UP:
                        player->vy = -1;
                        break;
                    case SDLK_DOWN:
                        player->vy =  1;
                        break;
                    case SDLK_ESCAPE:
                        return(0);
                        break;
                    case SDLK_RETURN:
                        if( level->map[player->x][player->y].sensitive &&       
                             level->map[player->x][player->y].sensitive_callback )     level->map[player->x][player->y].sensitive_callback(&level->map[player->x][player->y], player, level->map[player->x][player->y].userdata);                          
                        return(1);
                        break;
                    default:
                        break;
                }
                break;
            case SDL_KEYUP:
                switch( event.key.keysym.sym ){
                    case SDLK_LEFT:
                        if( player->vx < 0 )
                            player->vx = 0;
                        break;
                    case SDLK_RIGHT:
                        if( player->vx > 0 )
                            player->vx = 0;
                        break;
                    case SDLK_UP:
                        if( player->vy < 0 )
                        player->vy = 0;
                        break;
                    case SDLK_DOWN:
                        if( player->vy > 0 )
                        player->vy = 0;
                        break;
                    default:
                        break;
                }
                break;
            default:
                break;
        }
    }
    /* Update the player position */
    player->x += player->vx;
    if( player->x < 0 || player->x >= level->width )
        player->x -= player->vx;

    player->y += player->vy;
    if( player->y < 0 || player->y >= level->height )
        player->y -= player->vy;

    if( is_blocked( player->x, player->y, level) ){
        player->y -= player->vy;
        player->x -= player->vx;
    }
      
    player_rect = player_coords_to_screen_area( level, player );
    if( player_rect.y > 500 )
        level->y_offset += 400;

    if( player_rect.x > 700 )
        level->x_offset += 400;

    if( player_rect.y < 100 && level->y_offset > 0 )
        level->y_offset -= 400;

    if( player_rect.x < 100 && level->x_offset > 0 )
        level->x_offset -= 400;

    if( level->map[player->x][player->y].over_callback )
        level->map[player->x][player->y].over_callback(&level->map[player->x][player->y], player, level->map[player->x][player->y].userdata);

    return(1);

}

La touche RETURN devient la touche action, si le flag sensitive est vrai, et bien entendu que le pointeur sur fonction sensitive_callback est non-nul, alors la fonction de rappel est appelée.

L'événement over, quant a lui, si le pointeur est non-nul est appelé dès que le joueur arrive sur la tile concernée.

3.6.3 Exemple de fonction de rappel

Voici un exemple de fonction de rappel sur cet événement, qui permet de pousser
un objet quelconque sur toute la carte, dans toutes les directions :

 void push_key( tile_t *tile, player_t *player, level_t *userdata )
{
    int x,y, inc;
    x = player->x;
    y = player->y;

    if( !userdata->map[x + player->vx][y+player->vy].blocked ){
    userdata->map[x + player->vx][y+player->vy].img = userdata->map[x][y].img;
        userdata->map[0][0].blocked = 1;
    userdata->map[x][y].img = userdata->map[0][0].img;
        userdata->map[x+player->vx][y+player->vy].over_callback = tile->over_callback;
    userdata->map[x+player->vx][y+player->vy].userdata = userdata;
        tile->over_callback = NULL;
    }
}

Simple Non ?

Vous retrouverez ici le code complet du moteur, cet exemple compris, plus
animation que l'on peut arrêter et relancer en se plaçant sur la case marquée `ON' ou
`OFF' et en pressant la touche RETURN.

3.7 Temporisation

La puissance des machines personnelles allant croissant, votre prochain ordinateur a de
fortes chances d'être deux fois plus rapide que celui que vous possédez actuellement !
Résultat, votre jeu ira deux fois plus vite, et risque même de devenir injouable !
Afin d'éviter que le rythme du jeu suive exactement le rythme de votre machine, il suffit d'introduire une temporisation entre les itérations de la boucle principale.

3.7.1 Délai

Avant tout, il faut fixer un délai :

#define DELAY 20

Cette valeur représente le nombre de millisecondes que doit durer chaque itération
de la boucle principale. Veillez à l'adapter à votre application.

3.7.2 Fonction

Ensuite, écrivons une fonction qui retournera le nombre de millisecondes à attendre :
Une machine lente ne doit pas être pénalisée !

int time_to_wait( int next_time )
{
    int now;

    now = SDL_GetTicks();
    if(next_time <= now)
        return(0);
    else
        return(next_time - now);
}

time_to_wait prends en paramètre le moment, en millisecondes depuis l'initialisation de la librairie, ou la boucle principale sera autorisée à poursuivre son traitement, puis le compare au nombre de millisecondes réellement écoulées depuis l'initialisation de la librairie grâce à un appel à SDL_GetTicks qui renvoie cette information sous forme d'un entier.
Si  l' « heure » est atteinte ou dépassée, c'est à dire si l'exécution de la boucle principale
a duré ici 20 ms ou plus, elle renvoie 0. Sinon, elle renvoie le nombre de millisecondes restant à attendre afin de respecter le timing imposé.

3.7.3 Boucle principale améliorée

Bien entendu, la boucle principale doit être adaptée en conséquence :

void main_loop(level_t *level, player_t *player)
{
    int playing = 1;
    int next_time = SDL_GetTicks() + DELAY;


    while( playing ){
        playing = move_player(level, player);
        draw_level(level,player);
        draw_player(level, player);
        SDL_Flip(screen);
              SDL_Delay(time_left(next_time));
              next_time += DELAY;

    }

}

Premièrement, nous calculons l' « heure » a la quelle la prochaine itération doit avoir lieu en
Additionnant le délai à l' « heure » actuelle :

next_time = SDL_GetTicks() + DELAY;

Puis, en fin de boucle, nous comparons l'"heure" actuelle à l' «heure » prévue et attendons si nécessaire, grâce à un appel à SDL_Delay() qui permet de suspendre l'exécution durant un certain nombre de millisecondes passé en paramètre.

SDL_Delay(time_to_wait(next_time));

Enfin, nous calculons la prochaine "heure" d'exécution :

next_time += DELAY;

Ainsi, si la boucle met moins de temps, grâce à la rapidité du matériel, que la spécifié dans la valeur DELAY, le programme attendra, par contre, s'il met le temps spécifié ou plus, l'application ne sera pas ralentie.

3.8 Fonctions de libération de mémoire

La mémoire allouée pour nos structures et nos images, doit être, comme chacun le sait, évidement libérée.

Nous devons donc écrire une fonction de libération spécifique pour chaque type de données
que nous avons défini.

3.8.1 Libération des animations

Premièrement, voici la fonction de libération d'une animation :

void free_animation( anim_t *anim )
{
    int i;

    if( !anim )
        return;

    for( i = 0; i < anim->n_frames; i++ )
        SDL_FreeSurface(anim->frames[i]);

    free(anim->frames);
    free(anim);
}

Comme vous pouvez le constater, c'est le miroir exact de la fonction d'allocation :
Nous libérons d'abord leands surface allouées grâce à la fonction SDL_FreeSurface(), puis nous libérons la mémoire occupée par le tableau de pointeurs, et enfin nous libérons la structure elle-même.

3.8.2 Libération du joueur

A présent, examinons la fonction libérant la mémoire occupée par un joueur :

void free_player( player_t *player, int animated_player )
{
    if( !player )
        return;

    if( animated_player ){
        if( player->up )
            free_animation(player->up);   
        if( player->down )
            free_animation(player->down);   
        if( player->left )
            free_animation(player->left);   
        if( player->right )
            free_animation(player->right);   
    }
    else{
        SDL_FreeSurface(player->img);
    }

    free(player);
}


Ici, nous ne tentons de libérer les animations grâce à la fonction précédente seulement   si les pointeurs ne sont pas NULLs.
Remarquez le flag animated_player :
Si un joueur est animé, son champ img pointe vers une image allouée par la fonction de création d'une animation, donc il ne faut surtout tenter de le libérer, mais laisser ce travail à la fonction spécialisée.
Par contre, s'il s'agit d'un joueur statique, c'est à cette fonction d'effectuer la libération.

3.8.3 Libération de la carte

Enfin voyons la fonction de libération de la carte :

void free_tilemap( level_t *level )
{
    int i,j;

    for( i = 0; i < level->width; i++ )
        free(level->map[i]);
   
    free(level->map);
    free(level);
}

Comme vous pouvez le constater, cette fonction ne libère que ce qui à été alloué par la
fonction de création !
En effet, c'est au programmeur de remplir les champs img des tiles, c'est donc à lui de les libérer.
La raison à cela est simple : Comme nous l'avions évoqué plus haut, une « tile map » est souvent composée d'un grand nombre de tiles identiques, dont le champ img pointent sur la même zone mémoire...
Je vous laisse imaginer ce qu'entraînerait l'exécution d'un free() sur chaque surface de chaque tile d'une telle carte !
Pour éviter ces fautes de segmentation, le seul moyen serait d'intégrer un compteur de
références, ce qui n'est pas implémenté par la SDL et sort largement du cadre de cet article !



Nos talents de graphiste étants ce qu'ils sont,  nous avons utilisé pour nos tests des images en provenances d'autres jeux(le joueur seulement) : Nous ne sommes donc pas en mesure de vous les fournir!

anim1.png    anim2.png    anim3.png    key.pngoff.png    on.png

anim1.png      anim2.png        anim3.png      key.png      off.png         on.png

tile.png

tile.png


Articles de la même catégorie

 Pages : Top


24 Visites
0 Commentaires
Initiation au Perl
[10 mn de lecture - paru le 5/17/2005 5:31:28 PM - Public : Débutant]

En savoir plus


61 Visites
0 Commentaires
Interface graphique Swing avec Visual Editor
[15 mn de lecture - paru le 5/17/2005 5:31:04 PM - Public : Débutant]

En savoir plus


16 Visites
0 Commentaires
Create a graphical interface with dialog under Bash Scripting
[30 mn de lecture - paru le 5/17/2005 4:22:46 PM - Public : Débutant]

En savoir plus

   Tous les Articles


SUPINFO Training Center peut vous proposer une formation ...

   Devenez Ingénieur Système Microsoft en 35 jours avec SUPINFO Training Center
   Devenez Certifiés Cisco en 13 jours avec SUPINFO Training Center
   Devenez Administrateur Système Microsoft avec SUPINFO Training Center
   Devenez Développeur Microsoft .NET en 13 jours avec SUPINFO Training Center



Powered by Campus-Booster Technology
Conditions d'utilisation & Copyright | Respect de la vie privée
© Copyright 1965-2006 Supinfo Paris, Paris Academy of Computer Science
Supinfo, Ecole Supérieure d'Informatique et Paris Academy Of Computer Science are trade marks.
23, rue de Château LANDON - 75010 PARIS - Phone : +33 (0) 153359 700 Fax : +33 (0) 153359 701

Web site autided by :