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

SDL Discussion :

Quand le code devient illisible


Sujet :

SDL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé Avatar de Polyfructol
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Avril 2007
    Messages
    131
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Avril 2007
    Messages : 131
    Par défaut Quand le code devient illisible
    Bonjour à tous,

    Je suis en train de créer un jeu de plate-forme largement inspiré de Mario, en fait j'ai même pour but de coller au plus au jeu original, que ce soit au niveau de la maniabilité, de la physique ou des graphismes.

    Voilà mon problème : à force de bidouiller, de rajouter des fonctionnalités, de faire des combines à 3 francs pour que telle où telle chose ne bug plus, des "if else if" par centaine"s", j'en suis arriver à un code qu'on qualifierait de pourri (à moins qu'il y ai un qualificatif plus fort que pourri ).

    Bien que ce soit un problème purement conceptuel, je me permet de poster dans le forum SDL car une des raisons pour lesquelles mon code est illisible (si, personnellement j'ai du mal) est que je n'arrive pas a visualiser comment séparer ma partie affichage du reste du code. Il en résulte que des SDL_qqch trainent un peu partout dans mes classes.

    Un exemple simple sur lequel je bloque : ma classe cPlayer s'occupe de calculer la position du personnage et différente variable sur son état ensuite je veux l'afficher en fonction de ses paramètres calculés :

    dans mon cas j'exécute la fonction Draw contenu dans ma classe cPlayer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void cPlayer::Draw(SDL_Surface *screen, int xCamera, int yCamera);
    {
    	coord.x = int(x) - xCamera;
    	coord.y = int(y) - yCamera;
     
    	clip.x = pos * width; //pos équivaut à la position sur la feuille de sprite et width est la largeur du sprite
     
    	if ( SDL_BlitSurface(player, &clip, screen, &coord) < 0 )
    		fprintf(stderr, "Blit failed: %s\n", SDL_GetError());
    }
    Mais là c'est pas bon donc, j'aimerais que la classe player soit détachée de toute fonction d'affichage, et j'ai du mal a voir comment faire passer ses paramètres proprement dans une fonction d'affichage...

    dans ma tête ca donne ca :
    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
     
    int main (int argc, char** argv)
    {
    	cEngine engine;
    	cPlayer player;
     
    	/* Création de la map, des collisions */
     
    	while(!engine.end)
    	{
    		engine.Event();
    		...
    		/* Calcul map, camera, collisions, joueur  */
    		...
    		engine.DrawSprite(player.GetX(), player.GetY(), player.GetWidth(), player.GetPos(), "mario.bmp", etc ... 
    		// A n'en plus finir si je veux faire une fonction très générique
    	}
    	engine.Quit();
    }
    Mais je trouve ça lourd par rapport à une fonction Draw(...) comme au dessus, avec toute les variable initialisées avec le constructeur de classe.

    Un autre exemple où j'ai du mal : j'utilise (et abuse surement) de SDL_GetTicks() dans ma classe player, or comment récupérer ce timer si je n'utilise pas SDL dans ma classe cPlayer... (encore dans le main ?)

    Donc ma question finale (enfin ! ) :

    Comment s'y prend t'on pour garder un code organisé (d'un jeu video plus spécifiquement), sachant qu'il faut bidouiller tout le temps, faire des tests, ajouter moultes fonctionnalités.

    et

    Y a-t'il un méthode classique pour séparer la partie affichage du reste ?
    (je n'utilise pas vraiment les concepts de polymorphismes ni d'héritages, est-ce cela qu'il me manque ?)

    Merci de m'avoir lu en tout cas ! et encore merci si quelqu'un a des éclaircicements à m'apporter.

  2. #2
    Expert confirmé

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Par défaut
    Citation Envoyé par Polyfructol
    Je suis en train de créer un jeu de plate-forme largement inspiré de Mario, en fait j'ai même pour but de coller au plus au jeu original, que ce soit au niveau de la maniabilité, de la physique ou des graphismes.
    Histoire d'être chiant : attention à la légalité de la chose...

    Voilà mon problème : à force de bidouiller, de rajouter des fonctionnalités, de faire des combines à 3 francs pour que telle où telle chose ne bug plus, des "if else if" par centaine"s", j'en suis arriver à un code qu'on qualifierait de pourri (à moins qu'il y ai un qualificatif plus fort que pourri ).
    Il faut faire attention lorsqu'on programme est faire les choses doucement.

    Bien que ce soit un problème purement conceptuel, je me permet de poster dans le forum SDL car une des raisons pour lesquelles mon code est illisible (si, personnellement j'ai du mal) est que je n'arrive pas a visualiser comment séparer ma partie affichage du reste du code. Il en résulte que des SDL_qqch trainent un peu partout dans mes classes.
    Ce n'est pas vraiment un problème de la SDL mais plutôt un problème générique, ce n'est donc pas le bon forum.

    Un exemple simple sur lequel je bloque : ma classe cPlayer s'occupe de calculer la position du personnage et différente variable sur son état ensuite je veux l'afficher en fonction de ses paramètres calculés :

    dans mon cas j'exécute la fonction Draw contenu dans ma classe cPlayer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void cPlayer::Draw(SDL_Surface *screen, int xCamera, int yCamera);
    {
    	coord.x = int(x) - xCamera;
    	coord.y = int(y) - yCamera;
     
    	clip.x = pos * width; //pos équivaut à la position sur la feuille de sprite et width est la largeur du sprite
     
    	if ( SDL_BlitSurface(player, &clip, screen, &coord) < 0 )
    		fprintf(stderr, "Blit failed: %s\n", SDL_GetError());
    }
    Mais là c'est pas bon donc, j'aimerais que la classe player soit détachée de toute fonction d'affichage, et j'ai du mal a voir comment faire passer ses paramètres proprement dans une fonction d'affichage...
    Je ne vois pas le problème par contre. Généralement, si c'est le seul endroit où tu as du code de rendu je trouve ca propre. Chaque objet sait donc se dessiner, c'est correct. Mais effectivement, on peut faire mieux si on le souhaite.

    dans ma tête ca donne ca :
    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
     
    int main (int argc, char** argv)
    {
    	cEngine engine;
    	cPlayer player;
     
    	/* Création de la map, des collitions */
     
    	while(!engine.end)
    	{
    		engine.Event();
    		...
    		/* Calcul map, camera, collisions, joueur  */
    		...
    		engine.DrawSprite(player.GetX(), player.GetY(), player.GetWidth(), player.GetPos(), "mario.bmp", etc ... 
    		// A n'en plus finir si je veux faire une fonction très générique
    	}
    	engine.Quit();
    }
    Mais je trouve ça lourd par rapport à une fonction Draw(...) comme au dessus, avec toute les variable initialisées avec le constructeur de classe.
    Ben non, déjà, je ne vois pas pourquoi ce serait dans le main qu'on appellerait cela. Au pire, dans le main il y aurait un appel :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    engine.draw(); //Affichage de toute la scene
    A l'intérieur de la classe engine on aurait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class Engine
    {
      private:
         cPlayer joueur;
         int xCamera, yCamera;
     
         void drawPlayer(cPlayer &);
      public :
         void draw();
     
    }
    Dans la classe cPlayer, il y a toutes les informations : image à afficher, position, points de vie, ce qu'il a mangé à midi...

    Par contre, dans Engine, on a la position de la camera par exemple.

    Bref, du coup la fonction draw de la classe engine ressemblerait à ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void Engine::draw()
    {
      //On a un seul joueur, c'est assez basique comme jeu...
      drawPlayer(joueur);
    }
    et dans notre fonction drawPlayer on aura :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    void Engine::drawPlayer(cPlayer &p)
    {
    	coord.x = p.getX() - xCamera;
    	coord.y = p.getY() - yCamera;
     
    	clip.x = p.getPos() * p.getWidth(); //pos équivaut à la position sur la feuille de sprite et width est la largeur du sprite
     
    	if ( SDL_BlitSurface(player, &clip, screen, &coord) < 0 )
    		fprintf(stderr, "Blit failed: %s\n", SDL_GetError());
    }
    Bien sûr, je ne ferais pas comme ca. Je rajouterais une classe Jeu dans lequel on a le terrain et les joueurs et ce sera à ce niveau là qu'on appellerait tout. Du main, on appellerait une fonction miseAJour du moteur qui lui appellerait le rendu du jeu, vérifierait le son, regarderait le réseau...

    Avantage à cette facon de faire : le code de rendu peut être au même endroit. C'est en effet une bonne chose, on veut passer à du DirectX on a un endroit à modifier.

    C'est une solution comme une autre et celle qui me vient ce matin
    Une autre solution serait d'écrire une fonction comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    void maFonctionRendu(MonImage *im, MaPosition *pos, MonImage *ecran, MaPosition *dest)
    {
      SDL_BlitSurface(im, pos, ecran, pos);
    }
    Où les types sont juste des typedef pour le moment mais tu pourrais rajouter ce que tu veux...

    Du coup, encore une fois, le code spécifique à la SDL se retrouve au même endroit...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    Un autre exemple où j'ai du mal : j'utilise (et abuse surement) de SDL_GetTicks() dans ma classe player, or comment récupérer ce timer si je n'utilise pas SDL dans ma classe cPlayer... (encore dans le main ?)
     
    Donc ma question finale (enfin ! :yaisse2: ) :
    Tu rajoute une fonction à la classe Engine qui te le retourne directement... Du coup, tu n'auras qu'un seul endroit à modifier si tu veux utiliser autre chose...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    Comment s'y prend t'ont pour garder un code organisé (d'un jeu video plus spécifiquement), sachant qu'il faut bidouiller tout le temps, faire des tests, ajouter moultes fonctionnalités.
    Je ne suis pas d'accord, il ne faut jamais bidouiller. Il faut savoir ce qu'on fait et le faire, ensuite il faut tester pour trouver les erreurs


    Jc

  3. #3
    Membre éprouvé Avatar de Polyfructol
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Avril 2007
    Messages
    131
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur de jeux vidéo

    Informations forums :
    Inscription : Avril 2007
    Messages : 131
    Par défaut
    Bonjour et

    Tout d'abord je n'avais pas trop imaginé mettre ma classe player dans ma classe engine, c'est en effet très pratique ! Les paramètres seraient directement récupérables par la classe engine, pas de fonction lourde dans le main.
    Mais je préfèrerais garder cette classe engine exclusivement pour les fonctions d'affichage. Réutilisable dans d'autres codes.

    Donc la deuxième proposition a l'air de répondre parfaitement à mes attentes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    void maFonctionRendu(MonImage *im, MaPosition *pos, MonImage *ecran, MaPosition *dest)
    {
      SDL_BlitSurface(im, pos, ecran, dest);
    }
    Je pourrais remplacer tous les "SDL_BlitSurface" par "BlitSurface" c'est bien ca ? Donc j'immagine que je pourrais faire de même pour SDL_GetTicks, et aussi pour le type SDL_Rect.

    Mais je me pose une question, toutes ces nouvelles fonctions devront-elles être déclarées dans une classe ou tout simplement écrites dans un .h que je chargerais à la place de SDL.h ?

    En gros dois-je regroupe toute mes fonctions et types liées à SDL dans 2D.h (et dans 2D.cpp, mais là pour que ca soit plus lisible je l'écris dans l'entête)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <SDL/SDL.h>
    void BlitSurface(MonImage *im, MaPosition *pos, MonImage *ecran, MaPosition *dest) //faut que je vérifie les paramètres
    {
      SDL_BlitSurface(im, pos, ecran, dest);
    }
     
    Uint32 GetTicks()
    {
      return SDL_GetTicks();
    }
    puis dans mon jeu (engine.h):
    {
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "2D.h"
     
    class cPlayer
    {
      private:
      /* clip, coord, blabla */
     
      public:
      void Draw()
      {
        BlitSurface(player, &clip, screen, &coord);
      }
    };
    Et là si j'ai tout bien compris, si je veux changer de bibliothèque graphique, je n'ai qu'à modifier 2D.h.
    Mais c'est génial !! j'men vais tester ca tout de suite
    ... voir si j'ai d'autres p'tites questions à poser.

    Edit : point-virgule

  4. #4
    Expert confirmé

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Par défaut
    Si on veut rentrer dans la programmation intéressante, il serait bien de déclarer une classe avec toutes les fonctions en virtual que tu veux faire et ensuite écrire une classe qui hérite et implémente toutes ces fonctions.

    Comme ca, le passage serait encore plus transparent...
    Jc

  5. #5
    Membre confirmé Avatar de ironzorg
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    288
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2006
    Messages : 288
    Par défaut
    Moi aussi "histoire d'être chiant" :

    c'est ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "2D.h"
     
    class cPlayer
    {
      private:
      /* clip, coord, blabla */
     
      public:
      void Draw()
      {
        BlitSurface(player, &clip, screen, &coord);
      }
    }
    et pas ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    #include "2D.h"
     
    class cPlayer
    {
      private:
      /* clip, coord, blabla */
     
      public:
      void Draw()
      {
        BlitSurface(player, &clip, screen, &coord)
      }
    }

  6. #6
    Expert confirmé

    Avatar de fearyourself
    Homme Profil pro
    Ingénieur Informaticien Senior
    Inscrit en
    Décembre 2005
    Messages
    5 121
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur Informaticien Senior
    Secteur : Industrie

    Informations forums :
    Inscription : Décembre 2005
    Messages : 5 121
    Par défaut
    Citation Envoyé par ironzorg
    Moi aussi "histoire d'être chiant" :
    Il faudrait ajouter le ';' à la fin de la déclaration de la classe

    Jc

Discussions similaires

  1. Mob code devient illisible
    Par une_tite_question dans le forum AWT/Swing
    Réponses: 7
    Dernier message: 21/02/2008, 09h58
  2. Bean populate quand type String devient Date
    Par Mister Nono dans le forum Struts 1
    Réponses: 5
    Dernier message: 12/09/2007, 12h03
  3. exception quand le fichier devient grand
    Par christianf dans le forum Eclipse Java
    Réponses: 0
    Dernier message: 05/09/2007, 02h35
  4. Quand une propriété devient-elle objet ?
    Par ctobini dans le forum Schéma
    Réponses: 16
    Dernier message: 22/05/2007, 03h37
  5. new Option : ne marche pas quand le code est en alpha ???
    Par Leoxp dans le forum Général JavaScript
    Réponses: 4
    Dernier message: 19/12/2005, 15h23

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