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

Auteur Sujet: Besoin de conseils  (Lu 8209 fois)

0 Membres et 1 Invité sur ce sujet

damjuve

  • Newbie
  • *
  • Messages: 48
    • Voir le profil
Besoin de conseils
« le: Juin 03, 2012, 09:21:07 pm »
Bonjours à tous.

Désolé pour le titre pas très claire, mais je savais pas trop comment formuler ça.
Voilà déjà je voudrais vous présenter une classe héritant de sf::Sprite que j'ai écrite :

AnimSprite.h
/*
 * AnimSprite.h
 *
 *  Created on: 3 juin 2012
 *      Author: Damien
 */


#ifndef ANIMSPRITE_H_
#define ANIMSPRITE_H_

#include       <SFML/Graphics.hpp>

class          AnimSprite : public sf::Sprite
{
   public:
      /*
       *  Default Constructor
       */

      AnimSprite();

      /*
       *    Complete Constructor :
       *       nb_anim = nombre d'animation.
       *       nb_move = nombre de frame pour chaque animation.
       *       first_tile_subrect = subrect de la première frame pour chaque animation.
       */

      AnimSprite(   const sf::Image& img, const unsigned int nb_anim, const unsigned int* nb_move, const sf::IntRect* first_tile_subrect, const sf::Vector2f& pos = sf::Vector2f(0, 0), const sf::Vector2f& scale = sf::Vector2f(1, 1), float rotation = 0.f, const sf::Color& col = sf::Color(255, 255, 255, 255));

      /*
       *    Default destructor
       */

      virtual ~AnimSprite();

      /*
       *    Setteur for anim
       */

      void setAnim(const unsigned int nb_anim, const unsigned int* nb_move, const sf::IntRect* first_tile_subrect);

      /*
       *    Setteur for static frame
       *    (frame sélectionné lorsqu'aucune animation n'est lancé)
       */

      void setStaticFrame(const unsigned int stat_frame);
      void setStaticAnim(const unsigned int stat_anim);
      void setStaticStuff(const unsigned int stat_anim, const unsigned int stat_frame);

      /*
       *    Is funcs
       */

      const bool is_anim() const;

      /*
       *  Configure Anim funcs
       *        nb_repeat : nombre de fois où l'annimation doit être effectué (0 pour boucler tant qu'aucun appel à stopAnim n'est fait).
       *         end_turn : si true, l'annimation s'arretera une fois terminée.
       */

      void startAnim(const unsigned int id_anim, const unsigned int nb_repeat = 0);
      void stopAnim(const bool end_turn = false);

      /*
       *  Call whence frame has to be updated
       */

      void updateAnim();

   private:
         /* Data */
         unsigned int   nb_anim;            /* nombre d'animation disponible. */
         unsigned int   *nb_move;            /* nombre de tiles pour chaque animation. */
         sf::IntRect      *first_tile_subrect;   /* subrect de la première tile de chaque anim. (les suivantes doivent être à la suite à droite et faire la même taille. */

         /* Anim Stuff */
         unsigned int   current_anim;
         unsigned int   current_frame;
         bool         anim;
         unsigned int   static_anim;
         unsigned int   static_frame;
         unsigned int   nb_repeat;

         /* Funcs */
         void         init_animStuff();
         void         setNewSubRectByAnimAndFrame(unsigned int anim, unsigned int frame);


};

#endif /* ANIMSPRITE_H_ */


AnimSprite.cpp
/*
 * AnimSprite.cpp
 *
 *  Created on: 3 juin 2012
 *      Author: Damien
 */


#include "AnimSprite.h"

/*
**  ************************** CONSTRUCT & SETTEUR **************************
*/

void   AnimSprite::init_animStuff()
{
   this->current_anim = 0;
   this->current_frame = 0;
   this->anim = false;
   this->static_anim = 0;
   this->static_frame = 0;
   this->nb_repeat = 0;
}

      AnimSprite::AnimSprite()
{
   this->init_animStuff();
   this->nb_anim = 0;
   this->nb_move = NULL;
   this->first_tile_subrect = NULL;
}

      AnimSprite::AnimSprite(   const sf::Image& img, const unsigned int nb_anim, const unsigned int* nb_move, const sf::IntRect* first_tile_subrect, const sf::Vector2f& pos, const sf::Vector2f& scale, float rotation, const sf::Color& col)
      : sf::Sprite(img, pos, scale, rotation, col)
{
   this->init_animStuff();
   this->setAnim(nb_anim, nb_move, first_tile_subrect);
}

void   AnimSprite::setAnim(const unsigned int nb_anim, const unsigned int* nb_move, const sf::IntRect* first_tile_subrect)
{
   if (this->nb_anim != 0)
   {
      delete this->nb_move;
      delete this->first_tile_subrect;
   }
   this->nb_anim = nb_anim;
   this->nb_move = new unsigned int[nb_anim];
   this->first_tile_subrect = new sf::IntRect[nb_anim];
   for (unsigned int i = 0; i < nb_anim; i++)
   {
      this->first_tile_subrect[i] = first_tile_subrect[i];
      this->nb_move[i] = nb_move[i];
   }
}

   AnimSprite::~AnimSprite()
{
   if (this->nb_anim != 0)
   {
      delete this->nb_move;
      delete this->first_tile_subrect;
   }
}

void   AnimSprite::setStaticFrame(const unsigned int stat_frame)
{
   this->static_frame = (stat_frame % this->nb_move[this->current_anim]);
}

void   AnimSprite::setStaticAnim(const unsigned int stat_anim)
{
   this->static_anim = (stat_anim % this->nb_anim);
}

void   AnimSprite::setStaticStuff(const unsigned int stat_anim, const unsigned int stat_frame)
{
   this->setStaticFrame(stat_frame);
   this->setStaticAnim(stat_anim);
}

const bool   AnimSprite::is_anim() const
{
   return (this->anim);
}


/*
** ************************** FUNCTION ANIM **************************
*/

void   AnimSprite::startAnim(const unsigned int id_anim, const unsigned int nb_repeat)
{
   if (id_anim < this->nb_anim)
   {
      this->nb_repeat = nb_repeat;
      this->current_anim = id_anim;
      this->current_frame = 0;
      this->anim = true;
      this->updateAnim();
   }
}

void   AnimSprite::stopAnim(const bool end_turn)
{
   if (end_turn == true)
      this->nb_anim = 1;
   else
   {
      this->anim = false;
      this->current_anim = this->static_anim;
      this->current_frame = this->static_frame;
      this->updateAnim();
   }
}

void   AnimSprite::setNewSubRectByAnimAndFrame(unsigned int anim, unsigned int frame)
{
   sf::IntRect         new_sub;

   anim = anim % this->nb_anim;
   frame = (frame % this->nb_move[anim]);
   new_sub.Top = this->first_tile_subrect[anim].Top;
   new_sub.Bottom = this->first_tile_subrect[anim].Bottom;
   new_sub.Left = this->first_tile_subrect[anim].Left + (frame * this->first_tile_subrect[anim].GetWidth());
   new_sub.Right = this->first_tile_subrect[anim].Right + (frame * this->first_tile_subrect[anim].GetWidth());
   this->SetSubRect(new_sub);
}

void   AnimSprite::updateAnim()
{
   if (this->anim && (this->current_frame = (this->current_frame+ 1) % this->nb_move[this->current_anim]) == 0 && this->nb_repeat != 0)
   {
      this->nb_repeat --;
      if (this->nb_repeat == 0)
         this->stopAnim();
   }

   if (this->anim)
   {
      this->setNewSubRectByAnimAndFrame(this->current_anim, this->current_frame);
   }
   else
      this->setNewSubRectByAnimAndFrame(this->static_anim, this->static_frame);

}

L'idée était donc de rajouter des fonctionalitées à la classe sf::Sprite pour pouvoir gérer une animation (nottament dans le cadre d'un personnage pour un jeu 2D).

Les animations fonctionnent sur une image, vous pouvez définir autant d'animation que vous voulez, il n'y a que deux contraintes : chaque frame d'une même animation doivent faire la même taille et être placé à la suite dans l'image.

Ma première question sera donc simple, que pensez vous de mon code ? Je suis à la recherche de toute amélioration possible. En faite je prépare le terrain pour ensuite facilement créer des jeux 2D, et j'ai besoin de votre avis afin de ne pas partir sur une structure mal conçue.

Ensuite, j'ai choisi d'hérité de Sprite pour pouvoir utiliser les fonctions tels que Rotate(), FlipX() ou Scale(). Et celà m'amène à ma seconde question concernant ces trois fonctions :
ralentissent t'elles beaucoup mon affichage ? Dans cette optique ne serait-il pas mieux de les blitter dans une image créée en mémoire ?

Merci beaucoup de votre lecture, et d'avance pour vos réponses.

damjuve

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Besoin de conseils
« Réponse #1 le: Juin 03, 2012, 10:18:18 pm »
Rapidement :

- L'héritage c'est mal, car tu hérites de fonctions qui ne sont plus adaptées à la classe finale, voire qui cassent son fonctionnement (setTextureRect)

- SDL et cette façon d'aborder le graphisme, c'était il y a 20 ans ; aujourd'hui les opérations telles que rotate, scale, flip, etc. sont totalement gratuites -- vraiment
Laurent Gomila - SFML developer

Bigz

  • Full Member
  • ***
  • Messages: 154
    • Voir le profil
    • Bigz.fr
Re : Besoin de conseils
« Réponse #2 le: Juin 04, 2012, 09:36:21 am »
Laurent, peux tu en dire plus sur les méfaits appliqués à une méthode comme setTextureRect dans le cas d'un héritage de sf::Sprite ?

Je voyais pourtant une utilisation "pratique" d'un héritage à sf::Sprite pour faire une classe d'animation avec un setTextureRect se décalant au fil du temps.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Besoin de conseils
« Réponse #3 le: Juin 04, 2012, 09:43:10 am »
Citer
Laurent, peux tu en dire plus sur les méfaits appliqués à une méthode comme setTextureRect dans le cas d'un héritage de sf::Sprite ?

Je voyais pourtant une utilisation "pratique" d'un héritage à sf::Sprite pour faire une classe d'animation avec un setTextureRect se décalant au fil du temps.
Justement, c'est la classe d'animation qui gère le texture rect comme un détail interne, et plus l'utilisateur. L'utilisateur quant à lui ne doit plus avoir à faire qu'à des animations et des numéros de trames. S'il appelle setTextureRect directement il casse toute la mécanique interne de la classe, qui est censée le calculer automatiquement.

C'est un peu comme l'exemple typique qu'on te donne à l'école : Carré ne doit pas dériver de Rectangle bien qu'il en soit un cas particulier, car alors l'utilisateur pourra toujours changer la largeur indépendamment de la longueur (fonction héritées de Rectangle) et il sera impossible pour la classe dérivée (Carré) de remplir son contrat (longueur == largeur) en toute circonstance.

Il ne faut pas oublier que l'héritage public est la plus forte des relations qu'on peut établir entre deux classes en C++. La classe dérivée doit pouvoir se comporter exactement comme la classe de base, car elle en hérite toutes les fonctions et tous les comportements. Les gens utilisent beaucoup trop l'héritage public.
« Modifié: Juin 04, 2012, 09:47:56 am par Laurent »
Laurent Gomila - SFML developer

Bigz

  • Full Member
  • ***
  • Messages: 154
    • Voir le profil
    • Bigz.fr
Re : Besoin de conseils
« Réponse #4 le: Juin 04, 2012, 09:52:04 am »
Hm ok je vois. Du coup, l'idée serait plutôt d'avoir un nouveau sprite correspondant uniquement au subrect voulu de sorte à pas tout péter si on utilise un setTextureRect dessus ?

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Besoin de conseils
« Réponse #5 le: Juin 04, 2012, 10:13:30 am »
L'idée c'est de créer une classe AnimatedSprite qui ne dérive pas de sf::Sprite et qui ne contient pas de setTextureRect :)
Laurent Gomila - SFML developer

Bigz

  • Full Member
  • ***
  • Messages: 154
    • Voir le profil
    • Bigz.fr
Re : Besoin de conseils
« Réponse #6 le: Juin 04, 2012, 10:23:49 am »
Ca implique donc de construire une liste ordonnée de sprites que posséderait la classe AnimatedSprite, liste construite par un "manager" qui s'occuperait de récupérer dans le "bon gros sprite" tous les subsprites qui composent l'anim ?

Ouais jfais un peu le noob avec mes questions mais comme je bosse là dessus en ce moment, au temps partir sur la bonne voie :)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Besoin de conseils
« Réponse #7 le: Juin 04, 2012, 10:29:48 am »
Non, tu peux garder la stratégie initiale (changer le texture rect pour chaque frame d'animation), pas besoin de faire un découpage préliminaire en plusieurs sprites.

Ici on parle de conception de classe, de la façade que va voir et manipuler l'utilisateur. Les détails d'implémentation, ça c'est autre chose et ça n'est pas impacté par les choix de conception.
Laurent Gomila - SFML developer

damjuve

  • Newbie
  • *
  • Messages: 48
    • Voir le profil
Re : Besoin de conseils
« Réponse #8 le: Juin 04, 2012, 10:44:19 am »
Bonjours tout le monde, merci Laurent pour ta réponse.

J'avais pas pensé que le TextureRect puisse être modifié ailleurs, seulement en y repensant ça ne pose pas de problème, au prochain appel ma fonction updateAnim remodifira ce TextureRect si un animation a été lancé.

D'autre part tu dis qu'une class héritant doit pouvoir proposer les même fonctions sans bugger, or avec cette class, les fonctions tels que Flip() Rotate() SetPosition() SetScale() restent utilisables (et ça fonctionne bien, par exemple pour créer toute l'animation vers la droite d'un perso, chargez l'animation à gauche et aplliquez lui un FlipY()). D'autre part, celà me permet d'utiliser le polymorphisme à certain endroit de mon code.
Si on considère que la modification de TextureRect ne  pose pas de problème, je ne vois pas trop pourquoi je ne devrais pas hériter de sf::Sprite, des informations supplémentaire pour un débutant en POO ? :)

Si non je suis allé jetter un oeil sur le wiki et j'ai vu au moins trois projet de class héritant de sf::Sprite. J'ai pas réussi à y accéder je ne sais pas trop pourquoi.

Encore merci de votre lecture,
damjuve.
« Modifié: Juin 04, 2012, 10:46:06 am par damjuve »

Bigz

  • Full Member
  • ***
  • Messages: 154
    • Voir le profil
    • Bigz.fr
Re : Besoin de conseils
« Réponse #9 le: Juin 04, 2012, 10:45:27 am »
Hm, donc si je comprend bien, on veut juste que notre AnimatedSprite soit composé du sprite d'animation (celui englobant toutes les frames) et qu'on puisse "récupérer" le sub sprite (frame) courant de cet AnimatedSprite. Derrière ça, la dynamique d'update du sprite courant se faisant en interne de la classe AnimatedSprite.

Mais du coup c'est ce que j'entendais dans mon 2e post avec :
Citer
Du coup, l'idée serait plutôt d'avoir un nouveau sprite correspondant uniquement au subrect voulu de sorte à pas tout péter si on utilise un setTextureRect dessus ?

Donc soit chuis perdu, soit jme suis mal faire compris :D

damjuve

  • Newbie
  • *
  • Messages: 48
    • Voir le profil
Re : Besoin de conseils
« Réponse #10 le: Juin 04, 2012, 10:50:56 am »
Ah et pendant que j'y pense, j'avais vu sur le forum un tuto permettant d'installer plus ou moins bien la SFML avec eclipse CDT, en cherchant un peu j'ai trouvé comment le faire de façon traditionnel (configurer le linker), donc je sais pas si ça t'interesse que j'écrive un tuto (vu que tu as un tuto d’installation pour les autres IDE).

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Besoin de conseils
« Réponse #11 le: Juin 04, 2012, 11:25:14 am »
Citer
J'avais pas pensé que le TextureRect puisse être modifié ailleurs, seulement en y repensant ça ne pose pas de problème, au prochain appel ma fonction updateAnim remodifira ce TextureRect si un animation a été lancé.
Le texture rect modifié par l'utilisateur restera actif jusqu'à ce que l'animation passe à la prochaine trame. Ou alors, tu changes explicitement le texture rect (même si la trame d'animation n'a pas changé), comme ça tu écrases un éventuel texture rect changé par l'utilisateur. Techniquement ça marche mais ça reste sale : ta classe fournit une fonction qui n'est pas prise en compte ; pire : tu es obligé d'écrire du code qui annule l'effet d'une fonction qui est fournie dans l'interface publique de la classe. Conceptuellement, la solution la plus propre est de ne pas fournir la fonction.

Citer
D'autre part tu dis qu'une class héritant doit pouvoir proposer les même fonctions sans bugger, or avec cette class, les fonctions tels que Flip() Rotate() SetPosition() SetScale() restent utilisables (et ça fonctionne bien, par exemple pour créer toute l'animation vers la droite d'un perso, chargez l'animation à gauche et aplliquez lui un FlipY()). D'autre part, celà me permet d'utiliser le polymorphisme à certain endroit de mon code.
Si on considère que la modification de TextureRect ne  pose pas de problème, je ne vois pas trop pourquoi je ne devrais pas hériter de sf::Sprite, des informations supplémentaire pour un débutant en POO ?
Non, le reste marche bien en effet. Seule setTextureRect pose problème dans ce cas.

Citer
Si non je suis allé jetter un oeil sur le wiki et j'ai vu au moins trois projet de class héritant de sf::Sprite. J'ai pas réussi à y accéder je ne sais pas trop pourquoi.
Quels sont les liens que tu essayes de consulter ? Ca fait quoi quand tu essayes d'y aller ?

Citer
Hm, donc si je comprend bien, on veut juste que notre AnimatedSprite soit composé du sprite d'animation (celui englobant toutes les frames) et qu'on puisse "récupérer" le sub sprite (frame) courant de cet AnimatedSprite. Derrière ça, la dynamique d'update du sprite courant se faisant en interne de la classe AnimatedSprite.
En gros :
class AnimatedSprite
{
public:

    void update()
    {
        sf::IntRect currentFrameRect = ...;
        m_sprite.setTextureRect(currentFrameRect);
    }

private:

    sf::Sprite m_sprite;
};

Citer
Mais du coup c'est ce que j'entendais dans mon 2e post
Sans doute ;D

Citer
Ah et pendant que j'y pense, j'avais vu sur le forum un tuto permettant d'installer plus ou moins bien la SFML avec eclipse CDT, en cherchant un peu j'ai trouvé comment le faire de façon traditionnel (configurer le linker), donc je sais pas si ça t'interesse que j'écrive un tuto (vu que tu as un tuto d’installation pour les autres IDE).
Non, en fait je ne veux pas ajouter de tutos pour les autres EDIs.
J'ai fait les plus courants pour éviter que le forum ne soit spammé par les débutants, mais normalement les gens sont censés savoir utiliser leur EDI avant d'attaquer l'utilisation d'une bibliothèque. Je n'ai pas à expliquer ça dans les tutos SFML.
Laurent Gomila - SFML developer

damjuve

  • Newbie
  • *
  • Messages: 48
    • Voir le profil
Re : Re : Besoin de conseils
« Réponse #12 le: Juin 04, 2012, 12:00:09 pm »
Citer
J'avais pas pensé que le TextureRect puisse être modifié ailleurs, seulement en y repensant ça ne pose pas de problème, au prochain appel ma fonction updateAnim remodifira ce TextureRect si un animation a été lancé.
Le texture rect modifié par l'utilisateur restera actif jusqu'à ce que l'animation passe à la prochaine trame. Ou alors, tu changes explicitement le texture rect (même si la trame d'animation n'a pas changé), comme ça tu écrases un éventuel texture rect changé par l'utilisateur. Techniquement ça marche mais ça reste sale : ta classe fournit une fonction qui n'est pas prise en compte ; pire : tu es obligé d'écrire du code qui annule l'effet d'une fonction qui est fournie dans l'interface publique de la classe. Conceptuellement, la solution la plus propre est de ne pas fournir la fonction.
Bah je trouve pas ça si sale que ça :
L'utilisateur peux choisir d'utiliser l'AnimSprite comme un Sprite normal (d'où l'héritage), et il peux en plus lancer des animations qu'il a préenregistré.
Dans la mesure où si l'utilisateur change le TextureRect celui-ci ne sera réactualisé par AnimSprite que lors de l'appel à UpdateAnim(), c'est à l'utilisateur de savoir ce qu'il fait. Si il appel UpdateAnim c'est qu'il ne souhaite pas se servir de SetTextureRect, et dans le cas contraire il peux très bien s'en servir sans poser problème.

Désolé d'insister mais je ne vois pas ce que tu trouve si salle dans le cas présent.

Citer
Citer
Si non je suis allé jetter un oeil sur le wiki et j'ai vu au moins trois projet de class héritant de sf::Sprite. J'ai pas réussi à y accéder je ne sais pas trop pourquoi.
Quels sont les liens que tu essayes de consulter ? Ca fait quoi quand tu essayes d'y aller ?
Autant pour moi, je ne devait pas être connécte, enfin c'était bizare je n'avais acces qu'à certaine partie du wiki. Enfin là c'est bon je peux accéder aux autre codes sources. D'ailleurs j'en vois donc plusieurs héritant de sf::Sprite, y-a-t-il une différence d'organisation qui justifie un tel choix (et rendrais le code moins salle) ?

Citer
Citer
Ah et pendant que j'y pense, j'avais vu sur le forum un tuto permettant d'installer plus ou moins bien la SFML avec eclipse CDT, en cherchant un peu j'ai trouvé comment le faire de façon traditionnel (configurer le linker), donc je sais pas si ça t'interesse que j'écrive un tuto (vu que tu as un tuto d’installation pour les autres IDE).
Non, en fait je ne veux pas ajouter de tutos pour les autres EDIs.
J'ai fait les plus courants pour éviter que le forum ne soit spammé par les débutants, mais normalement les gens sont censés savoir utiliser leur EDI avant d'attaquer l'utilisation d'une bibliothèque. Je n'ai pas à expliquer ça dans les tutos SFML.
Okey, je penses que tu as raison, d'ailleurs pour configurer le projet sous Eclipse je me suis servis du tutto pour C::B :D

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : Besoin de conseils
« Réponse #13 le: Juin 04, 2012, 12:11:26 pm »
Citer
Désolé d'insister mais je ne vois pas ce que tu trouve si salle dans le cas présent.
C'est ça que je trouve sale : "c'est à l'utilisateur de savoir ce qu'il fait".
Je trouve plus propre un "l'interface de la classe ne permet pas de faire de choses qui ne fonctionnent pas".

Ceci-dit, vu le nombre de personnes qui tentaient de faire ça, j'ai essayé de solutionner le problème dans SFML 2 : la classe sf::Sprite ne définit plus que setTexture et setTextureRect, le reste est mis à part dans une classe de base dont tu peux toi-même dériver (sf::Transformable). Ca devrait mettre tout le monde d'accord.

Citer
D'ailleurs j'en vois donc plusieurs héritant de sf::Sprite, y-a-t-il une différence d'organisation qui justifie un tel choix (et rendrais le code moins salle) ?
Je n'ai jamais regardé en détail les codes du wiki. Il est très probable que j'aurais également quelque chose à redire si j'y jettais un oeil :)
Laurent Gomila - SFML developer

damjuve

  • Newbie
  • *
  • Messages: 48
    • Voir le profil
Re : Besoin de conseils
« Réponse #14 le: Juin 04, 2012, 01:57:17 pm »
Ok alors dernière idée :

Je peux créer une fonction dérivée de SetTextureRect qui fait l'équivalent de mes fonctions setStatique.
Ainsi si l'utilisateur l'utilise il définie une zone statique qui correspond à ce qui est affiché lorsqu'aucune animation n'est lancé.

Comme ça l'appel à setTextureRect reste une fonction utile et fonctionnel.