Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: [Résolu] Suis-je sur la bonne voie pour bien programmer?  (Lu 5010 fois)

0 Membres et 1 Invité sur ce sujet

[R]Viper

  • Newbie
  • *
  • Messages: 27
    • Voir le profil
[Résolu] Suis-je sur la bonne voie pour bien programmer?
« le: Juin 26, 2014, 02:08:56 pm »
Bonjour à tous, cela fait quelques années que je ne suis pas venu ici (mes anciens message sont introuvables, est-ce que le forum aurait été remis à zéro?)

Enfin bref, je me suis (re)lancé dans le développement d'application graphiques avec le binding .Net puisque dans mes études et mon travail j'ai énormément touché à ce langage. Je me suis lancé depuis peu dans le développement d'un petit moteur de jeu via ce tutorial http://www.games-creators.org/index.php/Gestion_des_Game_States_en_C_plus_plus

Plus j'avance, plus je me demande si je suis sur la bonne voie dans ma manière de programmer. Je vois différents moyens de faire les choses et je me demandais si ma façon de faire est bonne ou s'il fallait plutôt revoir ma logique et recommencer d'une autre manière.

Ma classe IntroState, qui ne fait qu'afficher une image de fond, avec un rectangle qui passe d'opaque à transparent laissant apparaître cette image de fond (oui c'est laid, mais je suis encore en train de faire des tests en même temps que je développe mon moteur). En appuyant sur la touche Échap, on quitte l'application. En appuyant sur la touche Espace, on entre dans l'état FightState.
namespace SFML_Test1.Engine2
{
    class IntroState : GameState
    {
        private SFML.Graphics.Sprite _Background = null;
        private SFML.Graphics.Sprite _SFMLLogo = null;
        private byte _Fade = 255;
        private SFML.Graphics.RectangleShape _FadingRectangle = null;
        private SFML.Graphics.Text _Text = null;
        private Text _Copyright = new Text("© 2014", new SFML.Window.Vector2f(0, 580), 12);
       
        private System.Diagnostics.Stopwatch _Stopwatch = null;

        public override void Init()
        {
            this._Background = new SFML.Graphics.Sprite(new SFML.Graphics.Texture("mainmenu/menubg.jpg"));
            this._SFMLLogo = new SFML.Graphics.Sprite(new SFML.Graphics.Texture("mainmenu/sfml-logo-small.png"));
            this._SFMLLogo.Scale = new SFML.Window.Vector2f(0.5f, 0.5f);
            this._SFMLLogo.Position = new SFML.Window.Vector2f(800 - this._SFMLLogo.GetGlobalBounds().Width, 600 - this._SFMLLogo.GetGlobalBounds().Height);                      
            this._FadingRectangle = new SFML.Graphics.RectangleShape(new SFML.Window.Vector2f(800, 600));
            this._Text = new SFML.Graphics.Text("", new SFML.Graphics.Font("ARIAL.TTF"));

            Console.WriteLine("IntroState.Init()");
            this._Stopwatch = new System.Diagnostics.Stopwatch();
            this._Stopwatch.Start();
        }

        public override void Cleanup()
        {
            throw new NotImplementedException();
        }

        public override void Pause()
        {
            throw new NotImplementedException();
        }

        public override void Resume()
        {
            throw new NotImplementedException();
        }

        public override void HandleEvents(GameEngine ge)
        {
            if (SFML.Window.Keyboard.IsKeyPressed(SFML.Window.Keyboard.Key.Space))
            {
                Console.WriteLine("IntroState.KeyPressed(Space)");
                ge.ChangeState(new FightState());
            }
            if (SFML.Window.Keyboard.IsKeyPressed(SFML.Window.Keyboard.Key.Escape))
            {
                Console.WriteLine("IntroState.KeyPressed(Escape)");
                ge.Quit();
            }
        }

        public override void Update(GameEngine ge)
        {
            if (_Stopwatch.Elapsed.Milliseconds > 20)
            {
                if (this._Fade > 0)
                {
                    this._Fade--;
                    this._Stopwatch.Restart();
                }
            }

            this._FadingRectangle.FillColor = new SFML.Graphics.Color(255,255,255, _Fade);

            this._Text.CharacterSize = 55;
            this._Text.Origin = new SFML.Window.Vector2f(this._Text.GetGlobalBounds().Width / 2, this._Text.GetGlobalBounds().Height / 2);
            this._Text.Position = new SFML.Window.Vector2f(400, 100);
            this._Text.DisplayedString = "Engine v0.01";
            this._Text.Color = SFML.Graphics.Color.White;            
        }

        public override void Draw(GameEngine ge)
        {
            ge.Window.DispatchEvents();
            ge.Window.Clear();

            ge.Window.Draw(this._Background);

            ge.Window.Draw(this._Text);
            ge.Window.Draw(this._SFMLLogo);

            ge.Window.Draw(this._Copyright);          

            ge.Window.Draw(this._FadingRectangle);

            ge.Window.Display();            
        }
    }
}
 

La classe FightState ne se différencie pas énormément de la classe IntroState, je ne vais que poster ce qui est important, c'est à dire l'utilisation de mon GUI.
namespace SFML_Test1.Engine2
{
    class FightState : GameState
    {
        private GUI _Gui = null;

        public override void Init()
        {
            Console.WriteLine("FightState.Init()");

            this._Gui = new GUI(new SFML.Window.Vector2f(10, 440), new SFML.Window.Vector2f(250,150), SFML.Graphics.Color.Black);
        }

        public override void Draw(GameEngine ge)
        {
            ge.Window.DispatchEvents();
            ge.Window.Clear();

            ge.Window.Draw(this._Gui);

            ge.Window.Display();
        }
    }
}
 

La classe GUI implémente l'interface Drawable dans le but d'être directement affichable en tant que classe (et non avoir à afficher chaque élément de mon GUI  dans ma classe FightState). Cette Gui s'affiche
namespace SFML_Test1.Engine2
{
    class GUI : SFML.Graphics.Drawable
    {
        private SFML.Graphics.RectangleShape _Background = null;
        private SFML.Graphics.RectangleShape _LifeBar = null;

        public GUI(SFML.Window.Vector2f Position, SFML.Window.Vector2f Size, SFML.Graphics.Color BackgroundColor)
        {
            this._Background = new SFML.Graphics.RectangleShape(Size) { Position = Position, FillColor = BackgroundColor };
            this._LifeBar = new SFML.Graphics.RectangleShape(new SFML.Window.Vector2f(80, 20)) { Position = new SFML.Window.Vector2f(50, 500), FillColor = SFML.Graphics.Color.Green };
        }

        public void Draw(SFML.Graphics.RenderTarget target, SFML.Graphics.RenderStates states)
        {
            target.Draw(this._Background, states);
            target.Draw(this._LifeBar, states);
        }
    }
}
 

Alors voilà, en gros le moteur affiche l'état IntroState jusqu'à ce que je décide de changer d'état (ici en appuyant sur Échap ou sur Espace). Une fois dans l'état FightState, je boucle cet état (gestion des événements, mise à jour des valeurs et affichage à l'écran) et par dessus tout ce qu'affiche mon FightState, j'affiche mon GUI.

Je voulais donc savoir si ce que je faisais était bien ou si je devais tout revoir mon système. Pour le moment ce n'est que minime, mais si je me lance dans un gros projet (ce que je vais faire éventuellement), je ne veux pas arriver à un point ou ma base est mauvaise et devoir recommencer mon moteur de jeu presqu'entièrement.

Merci d'avance.
« Modifié: Juin 05, 2015, 09:59:19 pm par [R]Viper »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Suis-je sur la bonne voie pour bien programmer?
« Réponse #1 le: Juin 26, 2014, 02:51:07 pm »
Il n'y a pas de mauvaise et de bonne façon de faire. Il y a beaucoup de façons de programmer, et ce qui est bien ou pas dépend de ton projet, de ton niveau et de tes préférences personnelles. Si ce que tu as fait te semble élégant et fonctionnel alors continue avec ça.

Si tu te lances dans un gros projet tu vas de toute façon tout recommencer plusieurs fois, comme tout le monde. Faut pas rêver ;) C'est comme ça qu'on progresse ; les tutoriels et les forums c'est bien, mais seule l'expérience peut te permettre de juger ce qui est "bien" ou pas en terme de code et de conception.
Laurent Gomila - SFML developer

[R]Viper

  • Newbie
  • *
  • Messages: 27
    • Voir le profil
Re : Re : Suis-je sur la bonne voie pour bien programmer?
« Réponse #2 le: Juin 26, 2014, 05:44:27 pm »
Il n'y a pas de mauvaise et de bonne façon de faire. Il y a beaucoup de façons de programmer, et ce qui est bien ou pas dépend de ton projet, de ton niveau et de tes préférences personnelles. Si ce que tu as fait te semble élégant et fonctionnel alors continue avec ça.

Pour le moment, ça me semble élégant et fonctionnel. J'ai pas eu de problème particulier ou de difficulté à implémenter quoi que ce soit. Mais c'est mon avis, peut-être que si certaines personnes plus compétentes que moi voient quelque chose de mal ou un point à améliorer dans ce que j'ai déjà de fait, ça me permettrait de m'améliorer.

Si tu te lances dans un gros projet tu vas de toute façon tout recommencer plusieurs fois, comme tout le monde. Faut pas rêver ;) C'est comme ça qu'on progresse ; les tutoriels et les forums c'est bien, mais seule l'expérience peut te permettre de juger ce qui est "bien" ou pas en terme de code et de conception.
C'est souvent le cas en programmation, autant du côté professionnel que personnel, le nombre incalculable de fois où j'ai du recommencer à 0 une partie d'un programme, voir même un programme complet. Mais en bout de ligne, l'expérience que ça m'a donné et le fait que je ne referai plus de tels erreurs dans l'avenir n'est que positif.

Merci pour ta réponse rapide.

Ma classe GUI qui implémente Drawable, est-ce bien réalisé? Je veux dire, ce que ma classe GUI fait pour le moment, elle crée deux RectangleShape et les affichent un par-dessus l'autre et ma classe FightState ne fait qu'un Draw(MonGUI). Ça me semble être la bonne manière d'implémenter Drawable, quelqu'un pourrait confirmer?

Outre de la clarté, est-ce que le fait d'afficher mon GUI via mon objet GUI donne un gain quelconque comparé à si je l'avais créé (les éléments de mon GUI) directement dans ma classe FightState?

Merci.
« Modifié: Juin 26, 2014, 05:50:20 pm par [R]Viper »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Suis-je sur la bonne voie pour bien programmer?
« Réponse #3 le: Juin 26, 2014, 06:02:00 pm »
Personnellement ça me paraît pas mal.

Quelques détails que je changerais :

1. Je ferais hériter tout ce qui se dessine de Drawable, en l'occurence les GameState.

2. Je bougerai la logique haut-niveau dans le GameEngine ou le main (selon comment tu gères les GameState) ; en effet ça n'est pas logique de gérer le DispatchEvent / Clear / Display dans chaque state, c'est commun à tout le monde. Seuls les draw spécifiques doivent être dans le Draw des GameState.

3. Tout ce qui est entrées temps-réel (Keyboard, Mouse, Joystick) devrait être utilisé dans Update, et HandleEvent devrait gérer les vrais évènements. Enfin, comme c'est géré différemment en C#, il y aurait plutôt un event handler par type d'évènement. D'ailleurs pour ton appui sur une touche pour changer d'écran, tu devrais utiliser un évènement.
Laurent Gomila - SFML developer

[R]Viper

  • Newbie
  • *
  • Messages: 27
    • Voir le profil
Re : Suis-je sur la bonne voie pour bien programmer?
« Réponse #4 le: Juillet 03, 2014, 08:02:56 pm »
Premier point :
Je suis encore à réfléchir à comment je pourrais transformer le tout, c'est de côté pour le moment le temps de régler les autres points qui me causent problème.

Deuxième point :
J'ai enlevé les DispatcheEvents, Clear et Display. Je t'avoue que je n'avais pas du tout porté attention à ces répétitions inutiles de code.

3. Tout ce qui est entrées temps-réel (Keyboard, Mouse, Joystick) devrait être utilisé dans Update, et HandleEvent devrait gérer les vrais évènements. Enfin, comme c'est géré différemment en C#, il y aurait plutôt un event handler par type d'évènement. D'ailleurs pour ton appui sur une touche pour changer d'écran, tu devrais utiliser un évènement.

Pour le moment, ça me cause problème. Si je prend l'exemple d'une application simple avec un seul fichier, je peux tout simplement faire comme dans l'exemple sur le github :

// Create the main window
Window window = new Window(new VideoMode(640, 480), "SFML window with OpenGL", Styles.Default, contextSettings);

// Setup event handlers
window.KeyPressed += new EventHandler<KeyEventArgs>(OnKeyPressed);

Or, dans mon exemple, je créé la RenderWindow dans mon GameEngine et je ne voit pas comment y accéder via une classe dérivée de mon GameState. J'ai pour le moment placé mon événement dans mon GameEngine et je vérifie dans quel GameState je me trouve afin de bien gérer l'événement, mais ce n'est aucunement pratique. Voici mon code :

void _Window_KeyPressed(object sender, SFML.Window.KeyEventArgs e)
{
    if (this._States.Peek().GetType() == typeof(PlayState))
    {
        switch (e.Code)
        {
            ...
        }
    }
    else if (this._States.Peek().GetType() == typeof(PauseState))
    {
        ...
    }
}
« Modifié: Juillet 03, 2014, 08:05:00 pm par [R]Viper »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Suis-je sur la bonne voie pour bien programmer?
« Réponse #5 le: Juillet 04, 2014, 07:51:53 am »
Deux solutions :

1. Redéclarer les évènements qui interesseront tes State (éventuellement modifiés à ta sauce) dans GameEngine, de sorte que les States puissent s'y abonner.

2. Gérer les évènements SFML dans GameEngine et les transmettre au State courant via des fonctions virtuelles.
Laurent Gomila - SFML developer

[R]Viper

  • Newbie
  • *
  • Messages: 27
    • Voir le profil
Re : Suis-je sur la bonne voie pour bien programmer?
« Réponse #6 le: Juillet 16, 2014, 09:51:08 pm »
Un peu de nouvelles...

Je ne réussi pas à bien comprendre tes deux solutions pour le moment, mais j'ai réussi à régler le problème d'une autre façon. Je passe un objet MyEvent qui contient un SFML.Window.KeyEventArgs (et éventuellement d'autres événements) à ma méthode HandleEvents. Dans cette méthode, je vérifie sur quel touche j'ai appuyé et je réponds à l'événement selon mes besoins. Pour l'instant, cela fonctionne bien à travers mes différents GameStates.

[R]Viper

  • Newbie
  • *
  • Messages: 27
    • Voir le profil
Re : Suis-je sur la bonne voie pour bien programmer?
« Réponse #7 le: Juin 05, 2015, 09:00:42 pm »
Près d'un an plus tard, et presque par hasard, je crois que j'ai enfin réussi à comprendre ta deuxième méthode!

Si cela peut éventuellement aider quelqu'un, voici mon code.

Ma classe abstraite de laquelle je créé mes différents éléments à afficher.
   
public abstract class GUIElement : SFML.Graphics.Transformable, SFML.Graphics.Drawable
    {
        public abstract void Draw(RenderTarget target, RenderStates states);
        public abstract void Event(KeyEventArgs keyEventArgs);
    }
 

Une classe dérivé qui utilise ma classe abstraite.
public class GUICombat : GUIElement
    {
        private SFML.Graphics.RectangleShape _Background;

        public GUICombat()
        {
                        //...
        }

        public override void Draw(RenderTarget target, RenderStates states)
        {
            states.Transform *= this.Transform;
            target.Draw(this._Background, states);
            foreach (GUICombatCharacter guic in this._Character)
            {
                target.Draw(guic, states);
            }
            target.Draw(this._SelectionIcon, states);
        }

        public override void Event(KeyEventArgs keyEventArgs)
        {
            switch (keyEventArgs.Code)
            {
                case Keyboard.Key.Up:
                                        //...
                    break;
            }
        }
    }
 

Je passe mon keyEventArgs à mon objet et je peux définir ce qui se passe en fonction de l'événement. Étais-ce bien cela que tu voulais dire par «2. Gérer les évènements SFML dans GameEngine et les transmettre au State courant via des fonctions virtuelles.»?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Suis-je sur la bonne voie pour bien programmer?
« Réponse #8 le: Juin 05, 2015, 09:10:37 pm »
Oui ;)
Laurent Gomila - SFML developer