OVH Cloud OVH Cloud

Faire moins bavard que ça

7 réponses
Avatar
Zouplaz
Bonjour, toujours avec mes sprites je cherche une solution propre au
problème suivant.

classe Sprite2D d'un côté
classe Sprite2DAnimated de l'autre

Une instance de Sprite2DAnimated dispose une std::map qui contient
plusieurs instances de classes SpriteFrameSequence.

La classe SpriteFrameSequence contient plusieurs Sprite2D

En clair, j'ai Sprite2DAnimated qui est un conteneur de
SpriteFrameSequence qui elle même est un conteneur de Sprite2D.

Il m'a semblé logique de dire qu'une sprite animée n'était qu'une
succession de sprites simples. Ainsi si j'améliore Sprite2D j'améliore
aussi Sprite2DAnimated.

Le problème est le suivant, pour modifier une propriété de Sprite2DAnimated
(exemple ci dessous, sa position) je dois retransmettre l'appel à
l'ensemble des séquences et ensuite des sprites contenus dans les
séquences, ce qui donne :

void Sprite2DAnimated::setDestRect(Rect rect)
{
frameSeqIterator it;

Stuff2D::setDestRect(rect);
for(it=m_frameSequences.begin();it!=m_frameSequences.end();it++)
{
SpriteFrameSequence* spfs;

spfs = (*it).second;
int spfs_size = spfs->getSize();
for(int i=0;i<spfs_size;i++)
spfs->getSpriteAt(i)->setDestRect(m_destRect);
}
}

Là où c'est moche moche c'est que je vais devoir implémenter setDestRect,
setSourceRect(Rect), setVisible (bool), setPosXY(int int), setMachin
(Type1), setBidule(Type2), etc...

Bref, je cherche une solution pour ne pas recopier le code ci-dessus dans
chaque méthode setXXX puisqu'il n'y a que trois lignes qui varient de l'une
à l'autre :

La déclaration de la méthode (ici setPos(Uint16 X,Uint16 Y))
L'appel à la méthode ancêtre (Stuff2D::setPos(X,Y);)
Et spfs->getSpriteAt(i)->setDestRect(m_destRect);
(en encore dans cette dernière ligne, seul setDestRect(m_destRect);
changera)

Comment faire ? Je manque cruellement d'imagination !

Merci de votre aide !

7 réponses

Avatar
Benoit Rousseau
Zouplaz wrote:

void Sprite2DAnimated::setDestRect(Rect rect)
{
frameSeqIterator it;

Stuff2D::setDestRect(rect);
for(it=m_frameSequences.begin();it!=m_frameSequences.end();it++)
{
SpriteFrameSequence* spfs;

spfs = (*it).second;
int spfs_size = spfs->getSize();
for(int i=0;i<spfs_size;i++)
spfs->getSpriteAt(i)->setDestRect(m_destRect);
}
}

Là où c'est moche moche c'est que je vais devoir implémenter setDestRect,
setSourceRect(Rect), setVisible (bool), setPosXY(int int), setMachin
(Type1), setBidule(Type2), etc...

Bref, je cherche une solution pour ne pas recopier le code ci-dessus dans
chaque méthode setXXX puisqu'il n'y a que trois lignes qui varient de l'une
à l'autre :

La déclaration de la méthode (ici setPos(Uint16 X,Uint16 Y))
L'appel à la méthode ancêtre (Stuff2D::setPos(X,Y);)
Et spfs->getSpriteAt(i)->setDestRect(m_destRect);
(en encore dans cette dernière ligne, seul setDestRect(m_destRect);
changera)

Comment faire ? Je manque cruellement d'imagination !

Merci de votre aide !


Tu as pensé à quelquechose qui ressemblerait au Visitor Pattern ?
Ou bien un Functor qui s'appliquerait à chacune des instances ?

--
--------------------------------------------
Benoît Rousseau : roussebe at spray dot se
Jouez en programmant : http://realtimebattle.sourceforge.net/

Avatar
Zouplaz
Benoit Rousseau - :

Tu as pensé à quelquechose qui ressemblerait au Visitor Pattern ?
Ou bien un Functor qui s'appliquerait à chacune des instances ?


Heu, si tu as quelques liens sur le sujet je suis preneur, je ne sais pas
du tout ce quoi il s'agit ! (peut-être est-ce dans la FAQ ??)

Avatar
Benoit Rousseau
Zouplaz wrote:
Benoit Rousseau - :


Tu as pensé à quelquechose qui ressemblerait au Visitor Pattern ?
Ou bien un Functor qui s'appliquerait à chacune des instances ?



Heu, si tu as quelques liens sur le sujet je suis preneur, je ne sais pas
du tout ce quoi il s'agit ! (peut-être est-ce dans la FAQ ??)
Désolé, j'avais pas le temps de repondre en entier, alors j'ai juste

donné une piste...

Je ne sais pas si la nomenclature est la bonne, alors n'hésitez pas à
corriger sur ce point (Functor ou Visitor ?).

Tu commences par créer un functor de base qui sera prendre pour argument
tes Frames :

class FrameFunctor {
public:
virtual void exec( SpriteFrameSequence* ) = 0;
};

puis tu le dérives pour chacune des fonctions que tu veux implanter :

class SetDestRect : public FrameFunctor {
public:
setDestRect( Rect rect ) : rect( rect ) {}
void exec( SpriteFrameSequence* spfs ) {
spfs->setDestRect( rect );
}
protected:
Rect rect;
};


puis, quand tu veux faire visiter à chacune de tes Frames :

un_fonction_appelant_setDest() {
Sprite2DAnimated s2Da;
...
SetDestRect sdr( rect );
s2Da.accept( &sdr );
}

void Sprite2DAnimated::accept( Functor* ft ) {
frameSeqIterator it;

//Stuff2D::setDestRect(rect); J'avais pas vu cette ligne, mais tu peux
//changer le functor pour qu'il s'applique à Stuff2D....

for(it=m_frameSequences.begin();it!=m_frameSequences.end();it++)
{
SpriteFrameSequence* spfs;

spfs = (*it).second;
int spfs_size = spfs->getSize();
for(int i=0;i<spfs_size;i++)
ft->accept( spfs->getSpriteAt( i ) );
//Applique setDest a chaque getSpriteAt...
}
}

Bon, aux erreurs de syntaxe et de type près, ca doit marcher...
(Y a aussi celles d'orthographe, mais vous ne m'en voudrez pas :-)

--
--------------------------------------------
Benoît Rousseau : roussebe at spray dot se
Jouez en programmant : http://realtimebattle.sourceforge.net/


Avatar
Zouplaz
Benoit Rousseau - :

Zouplaz wrote:
Benoit Rousseau - :


Tu as pensé à quelquechose qui ressemblerait au Visitor Pattern ?
Ou bien un Functor qui s'appliquerait à chacune des instances ?



Heu, si tu as quelques liens sur le sujet je suis preneur, je ne sais
pas du tout ce quoi il s'agit ! (peut-être est-ce dans la FAQ ??)
Désolé, j'avais pas le temps de repondre en entier, alors j'ai juste

donné une piste...

Je ne sais pas si la nomenclature est la bonne, alors n'hésitez pas à
corriger sur ce point (Functor ou Visitor ?).



Je crois avoir compris le principe mais dans ce cas je suis obligé de
dériver un nouveau "functor" pour chaque type d'action (setXXXmachin), s'il
y a beaucoup d'actions différentes ça fait beaucoup de functors alors que
la différence de l'un à l'autre n'est pas toujours énorme.



Avatar
Benoit Rousseau
Zouplaz wrote:
Benoit Rousseau - :


Zouplaz wrote:

Benoit Rousseau - :



Tu as pensé à quelquechose qui ressemblerait au Visitor Pattern ?
Ou bien un Functor qui s'appliquerait à chacune des instances ?




Je crois avoir compris le principe mais dans ce cas je suis obligé de
dériver un nouveau "functor" pour chaque type d'action (setXXXmachin), s'il
y a beaucoup d'actions différentes ça fait beaucoup de functors alors que
la différence de l'un à l'autre n'est pas toujours énorme.


Ce n'est pas vraiment un problème... Tu crées bien un nouvelle fonction
à chaque fois que tu veux ajouter une action...
Les visiteurs (ou functor, en fait ce principe se trouve entre les deux)
peuvent être placés dans le même fichier et se déclarent en quelques
lignes dans un .h et les fonctions dans un .cc ne prends pas trop de
place non plus.

Et ca t'évites de redéclarer cette boucle un peu compliquée à chaque
fois (boucle qui est surement plus longue que la déclaration du
visiteur). Et je suis sûr qu'une fois familiarisé avec le principe, tu
creeras les visiteurs très rapidement.

Q : Le problème du visiteur (le pur, pas celui là), c'est qu'il faut que
la hierarchie visitée soit assez stable, sinon c'est dur à maintenir,
n'est ce pas ?

--------------------------------------------
Benoît Rousseau : roussebe at spray dot se
Jouez en programmant : http://realtimebattle.sourceforge.net/




Avatar
Christophe Lephay
Benoit Rousseau wrote:
Q : Le problème du visiteur, c'est qu'il faut
que la hierarchie visitée soit assez stable, sinon c'est dur à
maintenir, n'est ce pas ?


Oui, car chaque nouvelle classe peut potentiellement rajouter une fonction
membre qui doit l'être aussi dans la classe de base, puisque le visiteur
fait l'appel sur une référence (ou un pointeur) sur la classe de base...

Chris

Avatar
Zouplaz
Benoit Rousseau - :

Zouplaz wrote:
Benoit Rousseau - :


Zouplaz wrote:

Benoit Rousseau - :



Tu as pensé à quelquechose qui ressemblerait au Visitor Pattern ?
Ou bien un Functor qui s'appliquerait à chacune des instances ?




Je crois avoir compris le principe mais dans ce cas je suis obligé de
dériver un nouveau "functor" pour chaque type d'action
(setXXXmachin), s'il y a beaucoup d'actions différentes ça fait
beaucoup de functors alors que la différence de l'un à l'autre n'est
pas toujours énorme.


Ce n'est pas vraiment un problème... Tu crées bien un nouvelle
fonction à chaque fois que tu veux ajouter une action...
Les visiteurs (ou functor, en fait ce principe se trouve entre les
deux) peuvent être placés dans le même fichier et se déclarent en
quelques lignes dans un .h et les fonctions dans un .cc ne prends pas
trop de place non plus.

Et ca t'évites de redéclarer cette boucle un peu compliquée à chaque
fois (boucle qui est surement plus longue que la déclaration du
visiteur). Et je suis sûr qu'une fois familiarisé avec le principe, tu
creeras les visiteurs très rapidement.



C'est vrai que c'est sympa,je viens de l'implémenter en utilisant (à juste
titre je ne sais pas) des noms plus explicites pour moi : la classe
"functor" devient Property et ensuite je dérive prop_Visible,
prop_DestRect, etc etc

Et du coup, pour les éléments simples (Sprite2D par ex) j'ai une méthode
setProperty(Property& prop)
redefinie dans SpriteAnimated

Le tout fonctionne donc de manière transparente pour les deux (la manière
de modifier une propriété est la même).

Reste les méthodes finales (je veux dire, setVisible, setDestRect, etc etc)
, celles appellées par les "functors". Le mieux serait d'en interdire
l'accès direct (qu'elle ne soient plus publiques mais protected) et que
tous les "fonctors" soient déclarés friend de Stuff2D, Sprite2D ou
SpriteAnimated. Peut être même qu'elles pourraient disparaitre et que les
functors tripatouillent les données membres directement, je sais pas...

En tout cas merci c'est vraiment bien comme système !! (houra j'ai appris
un truc !)