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
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.
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.
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 ?
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;
};
Mais du coup c'est ce que j'entendais dans mon 2e post
Sans doute ;D
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.
L'idéal serait de proposé à ceux qui font le c++ de créer un nouvel attribut en plus de public, protected, private.
"hidden" par exemple , suivi des méthodes que l'on veut cacher à l'utilisateur final.
class AnimSprite : public sf::Sprite
{
public:
/* mes méthodes publique... */
hidden: /* on redefini les méthode dérivé , pas forcement virtuelle, elle deviennent inutilisable par une instance de AnimSprite */
setTextureRect(...)
};
Reste à savoir qui contacté pour soumettre cette idée qui résoudrais le problème d'héritage. :-X
non ? :)