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

Auteur Sujet: classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]  (Lu 3672 fois)

0 Membres et 1 Invité sur ce sujet

DrPapino

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« le: Mars 05, 2013, 02:54:50 pm »
Bonjour !

Alors voilà, je viens de faire ma propre classe Anim, pour gérer les animations à l'écran. Il n'y a pour l'instant aucune fonction de pause ou même de déplacement. Considérez donc que ce code marche pour quelque chose comme une fontaine. Dans les grandes lignes, on va demander à la classe de faire un vector de textures ( chaque texture contiendra un fichier png, soit une étape du mouvement ). Ensuite, selon le temps écoulé, on va charger un élément x du vector dans un sprite, sprite qu'on va ensuite dessiner à l'écran. Ma classe est une dérivée de la classe sf::Drawable, du coup je sais pas trop si c'est bien d'utiliser des sprite à l'intérieur de ma classe, sachant que les sprites sont eux mêmes dérivés de la classe sf::Drawable.

Enfi bref, voici la bête :

Anim.cpp :

#include "Anim.h"
#include <SFML/Graphics.hpp>

/* À chaque appel de cette fonction, on charge un nouveau fichier dans m_texture, puis on place une copie de m_texture dans un nouvel
élément de Tableau. i compte le nombre de fois que l'on répète cette action, soit le nombre d'éléments de Tableau */

void Anim::addFrame(std::string chemin)
{
    sf::Texture m_texture;
    m_texture.loadFromFile(chemin);
    Tableau.push_back(m_texture);
    i++;
}

/* Simple réutilisation de la fonction setPosition de la classe sf::Sprite */
void Anim::setPosition(int x, int y)
{
    m_sprite.setPosition(x, y);
}

/* À chaque passage de la boucle while, on regarde le rapport suivant : temps écoulé/temps d'affichage de chaque image. Ce rapport,
tronqué à la première décimale grace à une pseudo conversion en entier, nous permet de nous déplacer dans Tableau. Chaque texture,
chaque élément du tableau est successivement chargé dans m_sprite, m_sprite étant ensuite affiché à l'écran par la fonction
virtuelle draw, présente dans le header de cette classe.
On remarque un décalage de 1 : juste après le lancement de clock, le rapport, encore inférieur à 1, est tronqué à sa première décimale
et vaut donc 0. Or, la première case de Tableau n'est pas la case [0] mais la case [1] puisque la première fois qu'on a modifié le
Tableau c'était après un push_back. L'erreur est ensuite corrigée dans la fonction setTexture, par a-1. Notons enfin le clock.restart() :
la fonction marche en boucle, il est donc normal de réinitialiser l'horloge une fois que l'on a dépassé le temps total d'affichage d'une
boucle */

void Anim::update()
{
    int a=((clock.getElapsedTime().asSeconds())/framerate)+1;          
    if (a>i)
    {
        clock.restart();
    }
    else if (a<=i)
    {
        m_sprite.setTexture(Tableau[a-1]);
    }
}

/* x est le temps d'affichage de chaque frame, framerate représente donc le nombre de frame par seconde */
void Anim::setFrameRate(float x)
{
    x=1/x;
    framerate=x;
}
 

Anim.h : 

#ifndef Anim_h
#define Anim_h

#include <SFML/Graphics.hpp>

class Anim : public sf::Drawable
{
public:
   
    virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const
    {
        target.draw(m_sprite, states);
    }
    void addFrame(std::string chemin);
    void setPosition(int x, int y);
    void update();
    void setFrameRate(float x);
   
private:
   
    std::vector<sf::Texture>Tableau;
    sf::Sprite m_sprite;
    sf::Clock clock;
    unsigned int i;
    float framerate;
};

#endif
 

main.cpp :

#include <SFML/Graphics.hpp>
#include "Anim.h"

int main()

    Anim fontaine;
   
    fontaine.addFrame("/Users/blabla/0.png");
    fontaine.addFrame("/Users/blabla/1.png");
    fontaine.addFrame("/Users/blabla/2.png");
    fontaine.addFrame("/Users/blabla/3.png");
    fontaine.addFrame("/Users/blabla/4.png");

    fontaine.setFrameRate(20);
    fontaine.setPosition(300, 200);
     
    sf::RenderWindow window(sf::VideoMode(800, 600), "Fenetre");
   
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }
        window.clear();
        fontaine.update();
        window.draw(fontaine);
        window.display();
    }
    return 0;
}
 

Voilà voilà… Et donc je me demandais si vous aviez des suggestions d'améliorations à faire, enfin ma classe marche plutôt bien, mais je suis ouvert aux critiques donc je viens vous demander votre avis !

Mr Pchoun.
« Modifié: Mars 05, 2013, 03:01:48 pm par MrPchoun »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #1 le: Mars 05, 2013, 03:20:35 pm »
Pêle-mêle :

  • La variable "i" est redondante, utilise Tableau.size()
  • Tes conventions de nommage sont pour le moins étranges, et surtout complètement hétérogènes ; la rigueur est ela première des bonnes habitudes à prendre
  • Même si ça a peu d'importance au final, essaye de baser ta classe d'animations sur une seule texture contenant toutes les poses, plutôt qu'une texture différente pour chaque pose ; du coup le paramètre de addFrame devient un sf::IntRect plutôt qu'un nom de fichier
  • Tu peux dériver de sf::Transformable si tu veux hériter automatiquement de toutes les fonctions de transformation (du coup pas besoin de redéfinir setPosition) -- pour que ça marche il faut juste ajouter dans le draw : states.transform *= getTransform();
  • Laisse l'appelant donner à ta classe le temps écoulé, ne le gère pas directement
  • Ton histoire de +1 et -1 c'est pas clair, et à mon avis pas utile
  • Tu stockes ton framerate comme étant 1/x, puis tu divises par la suite par framerate ; pourquoi ne pas stocker x directement puis faire "temps * framerate" ? (ça change pas grand chose, mais pourquoi faire compliqué quand on peut faire simple ?)
  • "framerate" est incorrect, soit dans le nom de la fonction (setFramerate) soit le nom du membre -- selon ce que tu stockes x ou bien 1/x
  • Trop de parenthèses inutiles dans tes calculs :)
  • Après "clock.restart()" tu ne remets pas la texture 0 ? tu laisses ton anim à la dernière frame ?
Laurent Gomila - SFML developer

DrPapino

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #2 le: Mars 05, 2013, 06:41:05 pm »
Citer
La variable "i" est redondante, utilise Tableau.size()

Check ! Au début j'avais mis sizeof(Tableau), ça marchait pas vraiment  :o, du coup j'ai mis cette histoire de i mais Tableau.size() marche très bien, merci.

Citer
Tes conventions de nommage sont pour le moins étranges, et surtout complètement hétérogènes ; la rigueur est ela première des bonnes habitudes à prendre

Ben ça pour le coup je vois pas trop ce que tu me reproches, toutes mes variables sont en minuscules, et le nom des fonctions commence par une minuscule puis les autres mots par des majuscules.

Citer
Même si ça a peu d'importance au final, essaye de baser ta classe d'animations sur une seule texture contenant toutes les poses, plutôt qu'une texture différente pour chaque pose ; du coup le paramètre de addFrame devient un sf::IntRect plutôt qu'un nom de fichier

Je suis pas trop pour : imaginons que j'ai besoin d'afficher une grosse animation à l'écran, une animation qui prenne quelque chose du genre 900x900, et que j'ai besoin de 50 étapes de mouvement par exemple. Tu me conseilles de faire une feuille de sprite si j'ai bien compris, mais j'avais vu sur un autre sujet que le chargement d'image est limité par un poids limite, fixé par la carte graphique. Si ma feuille de sprite a des dimensions trop grandes, j'ai peur qu'elle soit trop lourde que la carte graphique ( pas forcément la mienne, mais celle des éventuels autres utilisateurs ) n'accepte pas. Tu peux me dire ce que tu en penses ?

Citer
Tu peux dériver de sf::Transformable si tu veux hériter automatiquement de toutes les fonctions de transformation (du coup pas besoin de redéfinir setPosition) -- pour que ça marche il faut juste ajouter dans le draw : states.transform *= getTransform();

Check !

Citer
Laisse l'appelant donner à ta classe le temps écoulé, ne le gère pas directement

C'est à dire ? Il faudrait que je déclare un sf::Clock dans mon main, et que je l'envoie en argument de ma classe, lorsque j'initialise ma fontaine ? Ça me parait pas très propre.. À moins que ça m'évite, ensuite, d'avoir à écrire un fontaine.update() à la fin ? Parce que justement, ce update me parait pas très propre non plus  ;D

Citer
Ton histoire de +1 et -1 c'est pas clair, et à mon avis pas utile

Faut croire que si.. Je l'ai pas bien expliqué dans le Anim.cpp mais en tous cas, si on enlève ces +1 et -1, un des frame est vide, du coup une de mes images est blanches. C'est pas très joli ! Je vais essayer de retravailler ça.

Citer
Tu stockes ton framerate comme étant 1/x, puis tu divises par la suite par framerate ; pourquoi ne pas stocker x directement puis faire "temps * framerate" ? (ça change pas grand chose, mais pourquoi faire compliqué quand on peut faire simple ?)

Check ! C'était juste pour la lisibilité du code en fait, mais j'aurais qu'à expliquer ça dans un " // ".

Citer
Trop de parenthèses inutiles dans tes calculs

Check.

Citer
Après "clock.restart()" tu ne remets pas la texture 0 ? tu laisses ton anim à la dernière frame ?

Bien sûr, on est dans une loop, ce clock.restart() n'est là que pour marquer la fin du séquençage d'un certain nombre d'images, et pas la fin du séquençage de toutes les images chargées .

Merci encore pour tes conseils !  ;D ;D

« Modifié: Mars 05, 2013, 07:41:14 pm par MrPchoun »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #3 le: Mars 05, 2013, 08:26:30 pm »
Citer
Ben ça pour le coup je vois pas trop ce que tu me reproches, toutes mes variables sont en minuscules, et le nom des fonctions commence par une minuscule puis les autres mots par des majuscules.
Rien de te choque dans le nommage de ces trois membres ?
Tableau
m_sprite
clock

Citer
Je suis pas trop pour : imaginons que j'ai besoin d'afficher une grosse animation à l'écran, une animation qui prenne quelque chose du genre 900x900, et que j'ai besoin de 50 étapes de mouvement par exemple. Tu me conseilles de faire une feuille de sprite si j'ai bien compris, mais j'avais vu sur un autre sujet que le chargement d'image est limité par un poids limite, fixé par la carte graphique. Si ma feuille de sprite a des dimensions trop grandes, j'ai peur qu'elle soit trop lourde que la carte graphique ( pas forcément la mienne, mais celle des éventuels autres utilisateurs ) n'accepte pas. Tu peux me dire ce que tu en penses ?
C'est un bon argument. Ceci-dit généralement on anime des "petites" choses, pas des entités de 900x900. La plupart des classes d'animation fonctionnent comme ça, et je n'ai encore jamais vu personne s'en plaindre ;)

Citer
C'est à dire ? Il faudrait que je déclare un sf::Clock dans mon main, et que je l'envoie en argument de ma classe, lorsque j'initialise ma fontaine ? Ça me parait pas très propre.. À moins que ça m'évite, ensuite, d'avoir à écrire un fontaine.update() à la fin ? Parce que justement, ce update me parait pas très propre non plus
Dans une application complète, le code de plus haut niveau va forcément gérer le temps, il n'y a pas que ton animation qui a besoin du temps. En fait toute la logique de l'application dépend en théorie du temps, et si chaque classe s'amuse à gérer sa propre horloge, ça ce n'est pas très propre. Imagine que l'utilisateur implémente un algorithme de gestion du timestep, ou bien veuille ralentir/accélérer le temps, ou bien encore mettre en pause le jeu. Dans tous ces cas ta classe ne marche pas.
Quant à l'update, où voudrais-tu le mettre ? Typiquement, les classes vont avoir une fonction d'update (pour faire tous les calculs) et de dessin (qui elle est const !). Encore une fois, il faut voir plus loin que simplement ta classe, il faut la concevoir de manière à ce qu'elle puisse s'intégrer sans mal dans un squelette typique d'application.

Citer
Faut croire que si.. Je l'ai pas bien expliqué dans le Anim.cpp mais en tous cas, si on enlève ces +1 et -1, un des frame est vide, du coup une de mes images est blanches. C'est pas très joli ! Je vais essayer de retravailler ça.
Citer
Bien sûr, on est dans une loop, ce clock.restart() n'est là que pour marquer la fin du séquençage d'un certain nombre d'images, et pas la fin du séquençage de toutes les images chargées .
Que dis-tu de ça (pas testé) :

void Anim::update()
{
    int frame = int(clock.getElapsedTime().asSeconds() / framerate) % Tableau.size();          
    m_sprite.setTexture(Tableau[frame]);
}

Ca corrige et améliore au passage d'autres trucs que je n'avais pas noté la première fois.
Ca va commencer à merder au bout de quelques heures car on ne redémarre jamais l'horloge, mais c'était plus joli comme ça :D
« Modifié: Mars 05, 2013, 08:28:54 pm par Laurent »
Laurent Gomila - SFML developer

DrPapino

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #4 le: Mars 05, 2013, 09:47:52 pm »
Citer
Rien de te choque dans le nommage de ces trois membres ?
Tableau
m_sprite
clock

À part ces variables, je veux dire ;D Non, effectivement, tableau et sprite iraient mieux, mais pour clock je vois pas le problème.

Citer
C'est un bon argument. Ceci-dit généralement on anime des "petites" choses, pas des entités de 900x900. La plupart des classes d'animation fonctionnent comme ça, et je n'ai encore jamais vu personne s'en plaindre

À voir alors, pour l'instant je vais me pencher sur les autres problèmes que tu as souligné.

Citer
Dans une application complète, le code de plus haut niveau va forcément gérer le temps, il n'y a pas que ton animation qui a besoin du temps. En fait toute la logique de l'application dépend en théorie du temps, et si chaque classe s'amuse à gérer sa propre horloge, ça ce n'est pas très propre. Imagine que l'utilisateur implémente un algorithme de gestion du timestep, ou bien veuille ralentir/accélérer le temps, ou bien encore mettre en pause le jeu. Dans tous ces cas ta classe ne marche pas.
Quant à l'update, où voudrais-tu le mettre ? Typiquement, les classes vont avoir une fonction d'update (pour faire tous les calculs) et de dessin (qui elle est const !). Encore une fois, il faut voir plus loin que simplement ta classe, il faut la concevoir de manière à ce qu'elle puisse s'intégrer sans mal dans un squelette typique d'application.

On peut toujours envoyer un booléen dans la classe pour lui dire d'arrêter le temps. J'avais testé ça il y a quelques jours. Mais je vais essayer "d'externaliser" l'horloge, alors. Pour l'update, je sais pas, ce serait bien d'implanter cette fonction dans la fonction draw, tu vois. Malheureusement ça ne plait pas trop à mon compilateur.

Citer
Que dis-tu de ça (pas testé) :

void Anim::update()
{
    int frame = int(clock.getElapsedTime().asSeconds() / framerate) % Tableau.size();           
    m_sprite.setTexture(Tableau[frame]);
}

Ca corrige et améliore au passage d'autres trucs que je n'avais pas noté la première fois.
Ca va commencer à merder au bout de quelques heures car on ne redémarre jamais l'horloge, mais c'était plus joli comme ça

Je vais tester ça, je te tiens au courant ;)

Mr Pchoun.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #5 le: Mars 05, 2013, 10:06:14 pm »
Citer
Non, effectivement, tableau et sprite iraient mieux, mais pour clock je vois pas le problème.
Je voulais juste souligner le manque de cohérence. Après, tu choisis les conventions de nommage qui te plaisent, l'important étant de s'y tenir.

Citer
On peut toujours envoyer un booléen dans la classe pour lui dire d'arrêter le temps
Ca n'est qu'une rustine pour masquer une petite partie du problème, pas une solution propre.
Mais pour ce genre de choses, mieux vaut que tu fasses selon ce qui te semble le mieux, les "bonnes pratiques" viendront avec le temps et l'expérience ;)

Citer
Pour l'update, je sais pas, ce serait bien d'implanter cette fonction dans la fonction draw, tu vois. Malheureusement ça ne plait pas trop à mon compilateur.
En effet, j'ai justement fait exprès de rendre la fonction draw constante pour éviter ce genre de choses. Conceptuellement, une fonction draw ne doit pas modifier l'objet. Même si parfois ça semblerait pratique, ce n'est pas une bonne idée.
Laurent Gomila - SFML developer

DrPapino

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #6 le: Mars 06, 2013, 02:50:37 pm »
Citer
Mais pour ce genre de choses, mieux vaut que tu fasses selon ce qui te semble le mieux, les "bonnes pratiques" viendront avec le temps et l'expérience

Au contraire, vaut mieux que je parte dans la bonne direction, c'est pour ça que je viens demander ( le coup du modulo d'ailleurs, royal, ça marche impec ;) )

Pour revenir sur l'idée de la feuille de sprite, j'ai une question toute bête : en fait là j'ai chargé une animation un petit peu longue, et le chargement de toutes les images met à peu près une demie seconde. Je me demandais si le chargement serait plus rapide avec une feuille de sprite ? Je veux dire, toutes choses égales par ailleurs, est-il plus long de charger une image de 100x50, ou deux de 50x50 ?

Mr Pchoun.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #7 le: Mars 06, 2013, 03:13:26 pm »
A mon avis, une seule image sera toujours plus rapide à charger. Mais la différence ne sera pas forcément significative, et dépendra sûrement du format de fichier.
Laurent Gomila - SFML developer

DrPapino

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #8 le: Mars 09, 2013, 03:29:24 pm »
D'accord, bon je vais rester sur plusieurs fichiers pour l'instant, puis à la longue si ça devient vraiment trop long je testerai la feuille de sprite, au cas où.

Mais je rebondis sur ta réponse précédente, Laurent : souvent, quand on te demande de l'aide pour une classe d'animation, tu suggères de créer une classe propre, nouvelle, spécialement dédiée à la gestion d'animation, sans dériver de sf::Sprite ou de sf::Drawable. Aurais tu quelques pistes à me donner s'il te plait, pour que je puisse créer une telle classe ?

Enfin, je sais pas trop d'où vient le blocage en fait. D'un côté, les sf::Drawable nécessitent une fonction d'update avant d'être affichés à l'écran, de l'autre, je n'arrive pas à trouver la classe qui contient la méthode draw ( sinon ce serait facile, je dériverais de cette classe, et je ferais une nouvelle fonction draw.. ). L'idéal serait que cette nouvelle fonction draw prenne deux paramètres : &drawable et &clock. Mais comment faire ? :)

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #9 le: Mars 09, 2013, 04:12:11 pm »
Citer
Mais je rebondis sur ta réponse précédente, Laurent : souvent, quand on te demande de l'aide pour une classe d'animation, tu suggères de créer une classe propre, nouvelle, spécialement dédiée à la gestion d'animation, sans dériver de sf::Sprite ou de sf::Drawable. Aurais tu quelques pistes à me donner s'il te plait, pour que je puisse créer une telle classe ?
Bien sûr qu'il faut dériver de sf::Drawable, c'est à ça qu'elle sert. Du coup c'est exactement ce que tu as fait, je n'ai rien d'autre à ajouter que ce que j'ai déjà dit (dériver en plus de sf::Transformable, faire une fonction update).
Laurent Gomila - SFML developer

DrPapino

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #10 le: Mars 09, 2013, 04:26:18 pm »
Oui oui, mais j'aimerais que la méthode d'update soit "contenue" dans la méthode draw, pour ne pas avoir à updater tous mes objets à chaque fin de boucle. Et du coup faudrait que ma classe dérive toujours de sf::Drawable, sauf que ma méthode draw prendrait en paramètre un drawable et une clock. C'est possible ça ? :D Comment qu'on fait ? :D

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #11 le: Mars 09, 2013, 05:01:19 pm »
Non ce n'est pas possible. Note que dériver de sf::Drawable n'est pas une obligation, ne pas le faire changera juste ça

window.draw(entity);

... en ça ...

entity.draw(window);
Laurent Gomila - SFML developer

DrPapino

  • Newbie
  • *
  • Messages: 34
    • Voir le profil
Re : classe Anim ( une autre ! ), des suggestions ? [SFML 2.0]
« Réponse #12 le: Mars 09, 2013, 07:08:20 pm »
D'accord ! Je vais essayer de me débrouiller avec ça, alors.

Merci !

Mr Pchoun