IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

[Conception] généricité des données manipulées


Sujet :

C

  1. #1
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut [Conception] généricité des données manipulées
    Bonjour à tous.

    Dans le cadre de mes études, je dois développer un zuma en C.
    J'ai commencé l'analyse et en parallèle je teste 2/3 bouts de code et je me heurte à un problème.

    En effet, dans l'état actuel j'ai articulé mon jeu autour de la notion de "game state".
    Chaque game state represente un état dans le lequel peut se trouver à un instant T (écran d'accueil, jeu principal, score, option ...).

    Pour rendre le tout générique j'ai crée une structure game_state avec deux pointeurs de fonction: l'un va être appelé pour gérer les événements et l'autre l'affichage.

    Le soucis se pose dans les données manipulées par chaque état. En effet, celle ci sont différentes d'un état à l'autre et je ne sais pas comment en tenir compte.
    Par exemple, l'écran de jeu à proprement parler va devoir manipuler des liste de sprites et gérer les collisions entres elles, ce dont les autres états doivent ignorer l'existence.

    Pour le moment, j'ai tout fouré dans une structure game_data mais il faut dire que c'est totalement dégeulase.

    la seule solution que je vois pour segmenter les données. consiste à ajouter dans ma structure game_state un pointeur de type void* specific_data, à le faire pointer vers une structure spécifique (jeu_data, option_data, ...) au moment de l'appel des les fonctions d'initialisations spécifiques et à caster à chaque fois que j'en ai besoin.

    Mais venant du C++, ca ne me plaît pas. Après, je sais que c'est une pratique qui existe en C (je pense aux threads par exemple).

    Si vous avez une idée, n'hésitez pas !!!!

    Voici une version "synthétisée" de mon code pour (j'espère) rendre le tout plus clair:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    struct game_data
    {
      string name;
    };
     
    typedef void (*display_fct)(game_state*,displayer*);
    typedef void (*event_fct)(game_state*);
     
    struct game_state
    {
      game_data* common_data;
     
      /*Pointeur pour acceder aux données spécifique de chaque game_state*/
      /* 
        void* specific_data;
      */
     
      event_fct event_handler;
      display_fct display_handler;
     
      SDL_Surface* background;
      SDL_Event event;
     
      int continuer;
    };
     
    struct game
    {
      /** Donne du jeu*/
      game_data common_data;
     
      game_state* acceuil,jeu;
      game_state* current_state;
    };
    /*=====================*/
    int main(int argc, char *argv[])
    {
      game* g=0;
      displayer* d=0;
      /*...*/
      d=create_display();
      g=create_game(d);
     
      run_game(g,d);
      destruct_game(g);
     
     
      return EXIT_SUCCESS;
    }
    /*=====================*/
    game* create_game(displayer* d)
    {
      game* g=malloc(sizeof(*g));    
     
      init_data(&(g->common_data));
     
      g->acceuil=create_game_state(&display_acceuil,&event_acceuil,g);
      g->jeu=create_game_state(&display_jeu,&event_jeu,g);
     
      /*Initialisation specifique a accueil*/
      init_acceuil(g->acceuil,d);
     
      g->current_state=g->acceuil;
     
      return g;
    }
     
    /*Boucle principale du jeu*/
    void run_game(game* g,displayer* d)
    {
      int t1=0,t2=0;
      while(g->current_state->continuer)
        {
          t2 = SDL_GetTicks();
        if (t2 - t1 > period)
          {
            t1 = t2;
          }
        else
          {
            SDL_Delay(period/2);
            run_state(g->current_state,d);
          }
        }
    }
     
    game_state* create_game_state(display_fct d,event_fct e,game* game)
    {
      game_state* g=malloc(sizeof(*g));
     
      g->event_handler=e;
      g->display_handler=d;
     
      g->common_data=&(game->common_data);
      g->continuer=1;
     
      return g;
    }
     
    void run_state(game_state* s,displayer* d)
    {
      s->event_handler(s);
      s->display_handler(s,d);
    }
     
    void event_acceuil(game_state* state){/**/}
    void display_acceuil(game_state* state,displayer*){/**/}
     
    void event_jeu(game_state* state){/**/}
    void display_jeu(game_state* state,displayer*){/**/}
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  2. #2
    Membre expérimenté Avatar de Trademark
    Profil pro
    Inscrit en
    Février 2009
    Messages
    762
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2009
    Messages : 762
    Points : 1 396
    Points
    1 396
    Par défaut
    Salut,

    Tout d'abord, une erreur qui saute aux yeux : accueil

    Ensuite, en C, c'est effectivement un des seuls moyens que d'utiliser un pointeur générique void et de caster.

    Sinon une autre idée serait d'utiliser la structure common_data (j'ai cru voir ça dans ton code, mais n'ayant pas tout lu, je ne sais pas si ça a un rapport direct).
    Ensuite tu fais de "l'héritage", c'est-à-dire que tu crées par exemple une nouvelle structure specific_data_1, dans laquelle tu mets exactement les mêmes champs que dans common_data plus les nouveaux. Ainsi tu n'auras pas de pointeur sur void* supplémentaire. Ensuite lors de l'appel à la fonction tu castes common_data en specific_data_1. Vu que les données sont contigües (et vu que tu as réservé préalablement assez de place grâce à malloc) ça marchera.

    J'espère avoir pu répondre à ta question.

  3. #3
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2011
    Messages
    1 186
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Décembre 2011
    Messages : 1 186
    Points : 2 502
    Points
    2 502
    Par défaut
    Bonsoir,

    A la base, ce n'est pas fait pour ça, mais pour éviter des casts répétitifs, pourquoi ne pas utiliser une union ?

    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    struct myData
    {
        enum data_type {T1 , T2  };  // pour savoir le type de données.
        data_type t;
        union
        {
             struct type1
             {
                  int i;
             } * t1;   //pointeur sur les infos d'un type de données
     
             struct type2
             {
                  int i;
             } * t2;   //pointeur sur les infos d'un autre type de données
             //...
        };
    };
    Ici, même en multipliant les types de données, une structure de ce type prendra la taille de 2 entiers :
    - un pour le type.
    - un pour le pointeur vers les données.

    Il faudrait faire quelques tests pour ne pas avoir de mauvaise surprise lié à l'alignement mémoire dans l'union.
    Mais si l'union reste simple, ça ne devrait pas poser de problème.

  4. #4
    Membre éclairé Avatar de valefor
    Profil pro
    Inscrit en
    Décembre 2006
    Messages
    711
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2006
    Messages : 711
    Points : 790
    Points
    790
    Par défaut
    En gardant ce que tu as déjà mis en place...

    Je rajouterai un init_handler qui va allouer la mémoire des données spécifiques et affecter leur adresse à specific_data. J'initialiserai les autres handlers ds cette fonction aussi.

    Je rajouterais un "créateur/destructeur de state" qui va prendre en charge l'initialisation des handler. Tu pourrais séparer les fichiers ainsi et tu aurais en gros :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    /* accueil.h */
    game_state* accueil_alloc();
    void accueil_free(game_state*);
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    /* accueil.c */
    static event_handler(...) {...}
    static display_handler(...) {...}
    static specific_handler(...) {...}
     
    game_state* accueil_alloc()
    {
       gs = malloc(sizeof(game_state))
       gs->event_handler = event_handler;
       gs->display_handler = display_handler;
       gs->specific_handler = specific_handler;
       return gs
    }
    void accueil_free(game_state*)
    {
      free(gs);
    }
    Pareil pour jeux.

    Et
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    /* main.c */
    game* create_game(displayer* d)
    {
      game* g=malloc(sizeof(*g));    
     
      g->acceuil = accueil_alloc();
      g->jeu       = jeu_alloc();
     
      /* test si accueil et jeux pas null */
      g->accueil->init_handler(g->accueil);
      g->jeux->init_handler(g->accueil);
     
      g->current_state=g->acceuil;
     
      return g;
    }
     
    void run_state(game_state* s,displayer* d)
    {
      s->event_handler(s);
      s->display_handler(s,d);
      s->specific_handler(s);
    }

Discussions similaires

  1. [Conception] Recuperer des données dans un tableau dynamique
    Par Tartanjet dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 05/09/2006, 01h28
  2. [Conception] affichage des données
    Par fabrice88 dans le forum PHP & Base de données
    Réponses: 1
    Dernier message: 08/07/2006, 16h14
  3. [Conception] affichage des données
    Par fabrice88 dans le forum Décisions SGBD
    Réponses: 0
    Dernier message: 06/07/2006, 19h46
  4. [Conception] Afficher des données en fonction du mois.
    Par fabrice88 dans le forum PHP & Base de données
    Réponses: 12
    Dernier message: 05/06/2006, 11h31

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo