Je te rassure, ce n'est pas le cas, ta critique �tait l�gitime et j'ai simplement tenu � m'expliquer sur au moins un des points.
Version imprimable
Tu as peut �tre raison :)
En fait je crois que je commence � comprendre cette histoire de s�mantique de responsabilit�s :
Quand je fais ca dans la classe World, pour moi c'est World qui avait la responsabilit� de d�placer et de mettre � jour les animations. Apparemment c'est faux :DCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14 bool World::update(int direction, int buttons) { bool bOk = true; std::vector<IEntity*>::const_iterator it; for (it = entities.begin(); it != entities.end(); ++it) { bOk &= (*it)->move(direction); bOk &= (*it)->update(direction, buttons); } return bOk; }
Donc je dirais que en fait vu que la m�thode move de Entity appelle la m�thode onMove du IMoveBehaviour:
Code:
1
2
3
4
5
6
7
8 .... IMoveBehaviour* pMoveBehaviour; // pointeur sur son type de déplacement .... bool Entity::move(int directions) { return pMoveBehaviour->onMove(*pSprite, directions); }
Je suppose que c'est donc IMoveBehaviour qui a la responsabilit� de d�placer les Entit�s ? Est ce correct ou pas ?Code:
1
2
3
4
5 class IMoveBehaviour { public: virtual bool onMove(Core::ISprite& sprite, int directions) = 0; };
De m�me pour le dessin dans la classe World :
On fait appel � la m�thode draw() de Entity :Code:
1
2
3
4
5
6
7
8
9
10
11
12 bool World::draw(const Core::IRenderer& r) { bool bOk = true; std::vector<IEntity*>::const_iterator it; for (it = entities.begin(); it != entities.end(); ++it) { bOk &= (*it)->draw(r); } return bOk; }
Et cette m�thode fait aussi appelle � la m�thode draw() du sprite qui fait elle m�me appelle � la m�thode drawSurface() du Renderer.Code:
1
2
3
4 bool Entity::draw(const Core::IRenderer& r) { return pSprite->draw(r); }
Donc au final, c'est bien Renderer qui est responsable de l'affichaga des Entity ?
Yop,
En ayant juste lu rapidement de fil de discussion, tu te prend la t�te pour des truc simple.
Tu as une classe World, qui contient toutes tes entit�s (d'une fa�on ou d'un autre)
Tes entit�s peuvent �tre de plusieurs types, mais ils ont tous un point commun, ils peuvent etre mis a jour et affich�
Donc, ton "world", lui se contente de parcourir tes entit�s, et de les m�tre a jour l'un apr�s l'autre avec "update", puis les affich� avec "draw"
Pour les d�placements, g�re �a directement dans ta classe,
imaginons que player h�rite de unit qui herite de entity, tu surcharge "update" dans player et tu code ton comportement "si fl�che gauche et pas collision alors je me d�place a gauche"
pour Enemy, tu surcharge "update" et tu code ton comportement "si cible a droite et pas collision alors je me d�place a droite"
Pour le dessin, pareil, tu g�res �a dans ta classe
un "enemy" a un nom affich� au dessus de sa tete ? bah tu surcharge "draw" pour afficher le nom en plus de ce que fait d�j� de "draw" de "entity"
un "enemy_quifaittresmal" qui h�rite de "enemy" bah lui c'est pareil sauf que en plus de dessiner le nom, tu lui dessine une t�te de mort a cot� du nom
Apr�s a toi de d�cider ce qui fait d'une classe qu'elle m�rite d��tre une classe (player est controll� par le clavier) et ce qui peut �tre un simple param�tre (unit� se d�place a une vitesse x, pour player x=10, pour enemy x=8)
Salut,
Le probl�me n'est pas l�... ca j'ai bien compris comment utiliser un simple polymorphisme :P
Par contre, j'aimerais bien savoir si j'ai bien compris cette histoire de responsabilit� (cf mon post pr�c�dent) :)
En attendant, je vais continuer � �tudier le code de Koala01 ;)
Bonjour Aspic.
Sur le d�but, tu as tout � fait raison, c'est bien MoveBehaviour qui d�tient dans ce cas la responsabilit� du d�placement. Sur le draw, c'est un peu moins net et on pourrait ergoter mais cela reviendrait � d�battre du nombre d'anges sur une t�te d'�pingle. Pour ma part je m'y serais pris un peu diff�remment mais peu importe.
Par conte, sur le movebehaviour, il y a quand m�me une chose assez laide : tu passe � toutes tes entit�s l'�tat du contr�leur alors que seul le joueur va avoir besoin de ces informations, c'est assez tordu. Les diverses propositions qui ont �t� fa�tes pour �viter cela (utiliser des membres statiques pour exposer certaines informations ou passer une instance d'une classe contenant des r�f�rences vers tous les services importants) valent � mon avis un coup d'oeil.
Utiliser des membres statiques c'est comme des variables globales et pour moi ce n'est pas mieux du tout ;)
Utiliser une instance d'une classe contenant tout ce qu'il faut revient � faire une God Class et la passer partout dans les fonctions, c'est pas top non plus :(
Mais effectivement, tu as raison la direction n'est utilis�e que par Le PlayerBehaviour et pas les autres, comment r�soudre ce probl�me ? Je n'en ai aucune id�e :aie:
Autre chose, je dois g�rer le Scroll (changement d'�cran comme dans un zelda classique), pendez vous qu'il faut faire une classe � part et y mettre une r�f�rence dans ma classe World ? Ou alors directement g�rer dans World (mais ce n'est pas son r�le je pense...) ...
Au fait, concernant le MoveBehaviour...
Certains types d'entit�s (en fait, celles qui sont d�pla�ables dans mon exemple) ont effectivement un comportement de d�placement...
Mais il faut �tre clair : non seulement, c'est une relation AS UN (donc, nous sommes plus proche de la composition ou de l'aggr�gation que de l'h�ritage, mais, en plus, ce n'est pas le cas de n'importe quelle entit�...
Il n'y a en effet aucune raison pour qu'un �l�ment (immobile) du d�cors n'aie besoin d'un quelconque comportement de d�placement ;)
Par contre, on peut parfaitement envisager le fait qu'il puisse exister diff�rents type de comportement de d�placement !
L'exemple simple est qu'un ennemi va se d�placer sur base des d�cisions de l'IA (par exemple, en utilisant l'algorithme A* ;) ), alors que le joueur va se d�placer sur base des boutons ou touches enfonc�es par celui qui est derri�re son �cran ou qu'un sprite se d�placera "en droite ligne" selon une vitesse et une direction donn�e ;)
Nous pourrions donc parfaitement avoir une hi�rarchie de comportement de mouvement proche de
La classe MovableEntity sera donc sans doute intelligemment modifi�e enCode:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 class MoveBehaviour /* c'est une classe de base qui n'hérite de rien d'autre ;) */ { public: virtual ~MoveBehaviour(){} /* on sait que l'on doit permettre de calculer la prochaine position */ virtual computeNextPosition(Coordinate const & ) = 0; /* et qu'on doit pouvoir appliquer le déplacement à l'objet */ void updatePosition(MovableEntity & entity) { entity.moveTo(nexPos_); } protected: void setNextPos(Coordinate const & toset){nextPos_=toset;} private: Coordinate nextPos_; }; /* par exemple, pour le mouvement des spries */ class SpriteMovingBehaviour : public MoveBehaviour { public: SpriteMovingBehaviour(int time, int speed, double angle): time_(time), speed_(speed), angle_(angle){} virtual void computeNextCoordinate(Coordinate const &ActualPosion) { Coordinate temp = /* calcule de la position suivante par rapport à AcutalPosition, * en fonction de la vitesse et de l'angle indiquant la direction ;) */ setNextPosition(temp); } }; /* d'autres classes héritées de MoveBehaviour, adaptées pour le joueur, * les ennemis et les éléments de décors mobiles ;) */
et ce sont les classes qui d�rivent de MovableEntity qui fournissent le pointeur vers le comportement adapt�:Code:
1
2
3
4
5
6
7
8
9
10
11
12 class MovableEntity { public: MovableEntity(MoveBehaviour * behav,int xpos, int ypos, bool visible =false):Entity(xpos, ypos, visible), move_(behav){} void computeNextPosition() { move_->computeNextPosition(Coordinate(xpos(),ypos()); } /* comme précédemment :D */ private: MoveBehaviour * move_; };
Il semble en effet "logique" de se dire que l'utilisation du comportement qui consiste � se d�placer soit effectu�e par... l'entit� qui est susceptible de se d�placer, et ce meme si le comportement de d�placement vient � �tre adapt� par rapport au type r�el de l'entit� qui doit en profiter ;)Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 class Sprite : public MovableEntity { public: Sprite(int xpos, int ypos, bool visible =false):MovableEntity(new SpriteMovingBehaviour,xpos, ypos, visible){} }; class Ennemy : public MovableEntity { public: Ennemy(int xpos, int ypos, bool visible =false):MovableEntity(new EnnemyMovingBehaviour,xpos, ypos, visible){} }; class Gamer : public MovableEntity { public: Gamer(int xpos, int ypos, bool visible =false):MovableEntity(new GamerMovingBehaviour,xpos, ypos, visible){} };
Si besoin est, tu peux en outre parfaitement regrouper toutes les entit�s susceptibles de se d�placer dans une seule collection de mani�re � pouvoir provoquer le calcul de la prochaine position depuis un endroit unique, ce qui participera en outre au respect du sacrosaint principe de la responsabilit� unique ;) :D
Maintenant, il y a sans doute d'autre comportements, et l'on peut parfaitement les envisager de mani�re similaires (bien qu'ils n'h�ritent tr�s certainement pas de MoveBehaviour ;) )
As-tu des arguments � avancer qui s'appliquent au cas pr�sent ou s'agit-il d'une doctrine religieuse ? :mrgreen:
Pardon, je te taquine mais ma question reste plus que pertinente.
Au passage, variable globale != membre statique. Pas de pollution d'espace des noms, initialisation diff�rente, etc.
Si la classe en question est extr�mement simple et se contente d'exposer les services, je ne crois vraiment pas que ce soit un probl�me. D'autant que ton alternative actuelle entra�ne un couplage plus fort : si l'on d�cide de changer la gestion des �tats du contr�leur, il faut modifier toutes les entit�s et comportements. Dans les solutions qui t'ont �t� propos�e tu as au pire deux ou trois classes � modifier.Citation:
Utiliser une instance d'une classe contenant tout ce qu'il faut revient � faire une God Class et la passer partout dans les fonctions, c'est pas top non plus :(
Qui a la responsabilit� de d�cider quelles entit�s doivent �tre cr��es ou d�truites ? Si tu r�ponds � cela, tu r�ponds � ta question.Citation:
Autre chose, je dois g�rer le Scroll (changement d'�cran comme dans un zelda classique), pendez vous qu'il faut faire une classe � part et y mettre une r�f�rence dans ma classe World ? Ou alors directement g�rer dans World (mais ce n'est pas son r�le je pense...) ...
Note qu'il te faudra aussi assigner � une classe la responsabilit� de lire la map pour en d�duire quelles entit�s s'y trouvent. Au vu du scrolling, ce seront deux responsabilit�s distinctes.
@koaka01 :
Je suis d'accord avec toi, pas de raison qu'une entit� qui ne se d�place pas ait un comportement de d�placement. Le probl�me est qu'avec ta solution, tu as �norm�ment de classes rien que pour g�rer le d�placement avec 3 types de d�placements possibles (Gamer, Enemy et Sprite).
Imagine pour la gestion des collisions, comment vas tu g�rer les collisions entre tous les types d'entit�s d'un jeu par exemple ?
On a plus ou moins la m�me vision de la chose, la seule diff�rence est que je consid�re que toutes les entit�s peuvent se d�placer. De ce fait pas d'h�ritage du tout, que de la composition. J'ai modifi� un peu mon code, maintenant j'utilise une structure pour d�finir une entit� :
Et donc pour une entit� qui n'a pas de d�placement, il suffit de lui coller un NoMoveBehaviour qui ne fera rien, certes je suis d'accord c'est pas tr�s logique ^^ mais au moins pour ajouter un nouveau type de d�placement, il suffit de cr�er une classe qui d�rive de l'interface IMoveBehaviour et de l'impl�menter. Pour modifier un d�placement, il suffit de modifier la classe en question.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 struct Entity { Core::ISprite* pSprite; // pointeur sur son sprite IVect2D pos; // position courante USize2D size; // taille Type type; // type d'entité bool bVisible; // visibilite bool bAlive; // vivante ou pas // behaviours IMoveBehaviour* pMoveBehaviour; // pointeur sur son type de déplacement IHealthBehaviour* pHealthBehaviour; ICollisionBehaviour* pCollisionBehaviour; };
Donc je trouve que c'est facilement maintenable non ?
@DonQuiche :
M�me si les membres statiques sont mieux que des variables globales, pour y acc�der on a pas besoin d'objet donc elles sont accessibles partout ;)
Alors peut �tre que tu as raison, mettre les touches du clavier/joystick en static est peut �tre une solution, au moins je n'aurais pas � le trimbaler en arguments partout ^^ mais pour moi, je ne trouve pas que ca respecte les principes OO.
La je ne vois pas ce que tu veux dire, as tu un exemple d'une telle classe ?Citation:
Si la classe en question est extr�mement simple et se contente d'exposer les services, je ne crois vraiment pas que ce soit un probl�me. D'autant que ton alternative actuelle entra�ne un couplage plus fort : si l'on d�cide de changer la gestion des �tats du contr�leur, il faut modifier toutes les entit�s et comportements. Dans les solutions qui t'ont �t� propos�e tu as au pire deux ou trois classes � modifier.
Enfin, pour la responsabilit� de Scroll, pour moi c'est le World qui est en charge de loader/detruire les entit�s de la map et de les "g�rer" donc le Scroll devrait se trouver dans la classe World. :P
@Aspic
Plut�t que de directement mettre les �tats du contr�leur (clavier ou pad) en membre statique, tu peux aussi envisager d'exposer l'instance repr�sentant les �tats du contr�leur via un membre statique. Par exemple tu pourrais avoir une classe de ce genre, avec des membres statiques, ou des membres d'instance si tu souhaites la passer en argument � chaque update() :
CStatesAndServices
* getPlayerEntity() // N�cessaire pour les ennemis qui veulent suivre Link
* getControlerState() // N�cessaire pour la mise � jour de Link
* getSoundMixer() // N�cessaire pour jouer un son en r�action � un coup d'�p�e
* getInventory() // N�cessaire si Link ramasse un coeur (collisions)
// J'ai utilis� des m�thodes plut�t que des champs mais il y a peu de chances que l'on en ait vraiment besoin.
Tu pourrais aussi la d�couper en plusieurs morceaux si tu restes sur l'id�e d'une instance � passer � chaque appel de update() : avoir un UpdateArgs, CollisionArgs, etc... Ou mixer le tout pour avoir les services expos�s par des membres statiques et les �tats par des *Args.
Maintenant, si tu pr�f�res la m�thode statique, tu peux aussi fourrer tout �a dans World (ou Game) en sachant que �a n'accro�t le couplage que sur le papier puisque cette partie-ci de World changerait rarement. Oui, �a va � l'encontre du SRP mais le SRP est une aide � la conduite, pas un dogme religieux. Parfois on peut s'en affranchir si �a ne cr�e pas de probl�me. Et si tu es certain que World (ou Game) existera toujours et que ce sera toujours lui qui contiendra ces services et �tats, �a ne cr�e pas de probl�me.
Tout ceci �tant dit, deux remarques :
* Si tu souhaites mettre en place des tests unitaires, la version � base de UpdateArgs et CollisionArgs est nettement plus sympathique puisqu'on peut l'adapter ais�ment pour se donner la possibilit� de cr�er des mocks. Mais la m�me chose peut �tre fa�te avec les membres statiques en pr�voyant des setters.
* Inversement, l'avantage des membres statiques est que, si jamais tu as besoin � un moment d'un �tat que jusqu'� pr�sent tu ne relayais pas jusqu'� un niveau si profond dans la pile des appels, tu vas devoir modifier tous tes callers pour ce faire. Mais les *Args compensent cette faiblesse, rendant les modifications � faire moins nombreuses.
Au final, c'est aussi une question d'esth�tisme. Tu sembles par exemple affecter un certain purisme, peut-�tre parce que tu as ainsi l'impression de ne pas pouvoir faire d'erreurs. Dans tous les cas, toutes ces solutions sont meilleures que ta solution actuelle, laide et peu maintenable.
Et alors :question: le mouvement et la mani�re dont il est g�r� n'a, tout simplement rien � voir avec le reste :D
Tu peux tr�s bien consid�rer le fait que seules les entit�s qui bougent (MovableEntity dans mon exemple) sont susceptibles d'avoir un d�placement, dont le mode est adap� � leur type r�el (ennemy, sprite, gamer, que sais-je :question:)
"Tout ce qu'il faut", c'est, effectivement, que le comportement de d�placement soit d�l�gu� � une classe particuli�re ;)
Bien que tu aies deux type d'entit�s diff�rents (celles qui bougent et celles qui ne bougent pas), tu n'as que deux cas de collisions : une entit� qui bouge avec une entit� qui ne bouge pas, et une entit� qui bouge avec une entit� qui bouge (tu ne verra jamais deux entit�s qui ne bougent pas entrer en collision :D )Citation:
Imagine pour la gestion des collisions, comment vas tu g�rer les collisions entre tous les types d'entit�s d'un jeu par exemple ?
Par contre, tu devras de toutes mani�re mettre en place une certaine "priorit� de r�action" en cas de collision, d�pendant peut etre du type r�el de l'entit�, voir de l'entit� qui est "active" par rapport � celle qui est "passive" dans la collision ;)
Tu donnes, de nouveau, trop de responsabilit� � une entit�, lorsque tu ne sais pas exactement de quel type elle est !!!Citation:
On a plus ou moins la m�me vision de la chose, la seule diff�rence est que je consid�re que toutes les entit�s peuvent se d�placer. De ce fait pas d'h�ritage du tout, que de la composition. J'ai modifi� un peu mon code, maintenant j'utilise une structure pour d�finir une entit� :
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 struct Entity { Core::ISprite* pSprite; // pointeur sur son sprite IVect2D pos; // position courante USize2D size; // taille Type type; // type d'entité bool bVisible; // visibilite bool bAlive; // vivante ou pas // behaviours IMoveBehaviour* pMoveBehaviour; // pointeur sur son type de déplacement IHealthBehaviour* pHealthBehaviour; ICollisionBehaviour* pCollisionBehaviour; };
Tant que tu ne parles que d'une entit�, sans pr�cision, elle ne doit avoir qu'une seule responsabilit� (par exemple, celle de fournir les informations permettant de la placer sur ta carte, et/ou celle de s'afficher ;) )
Ce n'est qu'une fois que tu sp�cialise ta classe (en MovableEntity ou NonMovableEntity) que tu peux d�terminer que l'une est susceptible de se d�placer et l'autre pas...
Il ne servira donc � rien d'avoir un "NoMoveBehaviour" ;)
Ton "IMoveBehaviour" sera, effectivement, sp�cialis� en fonction du type r�el de l'entit� (qui peut se d�placer), mais c'est ce que nous faisons tous les deux, si ce n'est que je sais d'office qu'il y a tout un pan de la hi�rarchie "Entity" qui n'en aura pas besoin ;)
Comme tu le dis, ce n'est pas logique :DCitation:
Et donc pour une entit� qui n'a pas de d�placement, il suffit de lui coller un NoMoveBehaviour qui ne fera rien, certes je suis d'accord c'est pas tr�s logique ^^
D�s lors, pourquoi le faire :question:
Si tu fais la distinction entre les entit�s qui peuvent bouger et celles qui ne peuvent pas bouger, tu as la certitude que seules les premi�re devront disposer d'un comportement de d�placement adapt� :D
Mais, tu remarqueras que c'est ce que je fais :DCitation:
mais au moins pour ajouter un nouveau type de d�placement, il suffit de cr�er une classe qui d�rive de l'interface IMoveBehaviour et de l'impl�menter. Pour modifier un d�placement, il suffit de modifier la classe en question.
La seule diff�rence, c'est que je m'assure qu'un entit� ne devant pas se d�placer n'aura en aucun cas besoin d'un comportement de d�placement ;)
Mais, r�fl�chis un peu!!!!Citation:
@DonQuiche :
M�me si les membres statiques sont mieux que des variables globales, pour y acc�der on a pas besoin d'objet donc elles sont accessibles partout ;)
Alors peut �tre que tu as raison, mettre les touches du clavier/joystick en static est peut �tre une solution, au moins je n'aurais pas � le trimbaler en arguments partout ^^ mais pour moi, je ne trouve pas que ca respecte les principes OO.
O� vas tu avoir besoin du clavier et du joystick :question:
Exclusivement au niveau du gestionnaire d'�v�nement du joueur ;)
De l� � dire qu'il peut, d'une mani�re ou d'une autre, n'exister qu'au travers de l'existence du joueur (ou de son syst�me de gestion d'�v�nements), il n'y a qu'un pas all�grement franchi :D
C'est d'autant plus vrai que tu n'en as besoin qu'au moment o� tu vas cr�er l'�v�nement (l'appui sur une touche ou le basculement du joystick dans une direction va provoquer la cr�ation d'un �v�nement qui sera "propag�" l� o� n�cessaire ;) )
Des arguments, il y en a � la pelle :D
Probl�me de r�entrance, de gestion de thread, de "puret�" des fonctions...
Tu devrais t'int�resser � cette discussion, essentiellement � partir de l'intervention num�ro 5, pour �viter d'avoir � tout r��crire ;)
Une "GodClass" ne sera jamais simple!!!Citation:
Si la classe en question est extr�mement simple et se contente d'exposer les services, je ne crois vraiment pas que ce soit un probl�me. D'autant que ton alternative actuelle entra�ne un couplage plus fort : si l'on d�cide de changer la gestion des �tats du contr�leur, il faut modifier toutes les entit�s et comportements. Dans les solutions qui t'ont �t� propos�e tu as au pire deux ou trois classes � modifier.
Il est bien plus facile et maintenable de garder des petites classes ayant des responsabilit�s limit�es qu'une seule classes dont on s'attendrait presque � ce qu'elle nous fasse le caf�, tant elle a de responsabilit�s ;)
�a commence mal...:roll:
* Sur les �tats du contr�leur :
Tu pars du principe qu'il va utiliser ton syst�me � base d'�v�nements, ce qui n'est pas dit. Depuis le d�but je m'efforce de rester � un niveau g�n�ral quand toi tu d�veloppes *ton* impl�mentation.
* Sur les variables statiques
** Si une instance mutable est partag�e par plusieurs threads, elle ne pose ni plus ni moins de probl�me que des membres statiques.
** Code r�entrant : voir ci-dessus.
** Puret� des fonctions : voir ci-dessus.
Maintenant si tu prends la peine de regarder ce qui serait partag�, que vois-tu ? Soit des donn�es modifi�es une fois et lues par le reste du code (�tat du contr�leur), soit des instances mutables qui seront partag�es (entit� repr�sentant Link, service sonore, etc).
* Sur la GodClass jamais simple :
Nous ne parlions pas d'une classe regroupant des pellet�es de responsabilit�s. Nous parlions d'une classe ne fournissant aucune service et se contentant d'exposer quelques singletons (pas le pattern, l'unicit�) en lecture seule (initialis�s au d�marrage).
Exact vu comme ca ;)
Je ne comprends pas tr�s bien.
Dans le cas de ton impl�mentation, comment vas tu g�rer les collisions de tes deux types d'entit�s (Movable et NonMovable) ?
Si tu cr��s un ICollisionBehaviour et que tu l'associes aux classes MoveEntity et NoMoveEntity, comment vas tu g�rer les collisions au cas par cas, c'est � dire :
- Enemy (Movable) VS Player (Movable) => faudra d�clencher un "Hit" sur le Player
- Enemy (Movable) VS Hole (NoMovable) => Enemy va changer de direction pour �viter le trou (d'ailleurs le d�placement des ennemies est al�atoire dans Zelda :D pas d'algo de type A* ou autre)
- Player (Movable) VS Door (NoMovable) => D�clencher une t�l�portation vers une autre zone de la map
En fait ton impl�mentation me plait bien :ccool:, j'ai juste peur d'�tre coinc� au niveau des collisions entre toutes les entit�s :(
Derni�re chose, tu as des entit�s qui ont un Sprite qui s'anime quand il se d�place (Enemy et Player), d'autres entit�s qui s'animent ind�finiment (des bougies, des �l�ments du d�cor pour rendre la map "vivante"), et d'autre qui sont fixes (une pancarte, une maison...) et d'autres qui s'animent lors d'un �v�nement (ouverture d'une porte par exemple, apparition d'un objet...).
Comment vas tu g�rer ca ? Tu ne vas quand m�me pas cr�er des nouveaux types d'entit�s qui d�rivent de Entity ? :D
PS : Je crois que le "Ah mais r�fl�chie un peu !!!" �tait destin� � moi m�me :mrgreen:
Merci :)
EDIT :
En essayant d'impl�menter la solution de koala01, je me suis rendu compte qu'il y a un petit probl�me :
La fonction suivante dans la classe MovableEntity ne pourra jamais �tre appel�e car le World manipule un vector de Entity, Or cette fonction est sp�cialis�e � un MovableEntity donc je ne pourrais pas l'appeler � partir de World... (ou alors comme d'hab, j'ai pas compris :aie:)Code:
1
2
3
4 void computeNextPosition() { move_->computeNextPosition(Coordinate(xpos(),ypos()); }
En clair:
De m�me dans ce design, qui est en charge de v�rifier si le mouvement est valide ou pas ?Code:
1
2
3
4
5
6
7
8 // je crée un player en position (100,100) Entity* player = new Gamer(100, 100); //Je l'ajoute aux entités du monde world->addEntity(player); // et maintenant comment le World va t-il appeler la fonction spécialisée // computeNextPosition() de MovableEntity ?
Le mais r�fl�chis un peu �tait adress� � aspic, en fait :aie:
Je pars surtout du principe qu'il faut absolument faire en sorte de d�l�guer les responsabilit�s...Citation:
* Sur les �tats du contr�leur :
Tu pars du principe qu'il va utiliser ton syst�me � base d'�v�nements, ce qui n'est pas dit. Depuis le d�but je m'efforce de rester � un niveau g�n�ral quand toi tu d�veloppes *ton* impl�mentation.
Il faut, bien sur, prendre les inputs de l'utilisateur en compte, et, le fait que l'utilisateur d�cide d'appuyer sur la barre d'espace, sur o ou sur la fleche montante est, quoi que tu en dise, un �v�nement ;)
La seule inconnue, c'est la r�action que le syst�me devra avoir face � cet �v�nement ;)
Comme on travaille sur une application qui suit une "ligne de temps" ponctu�e par des �v�nements, il est logique que l'on se base sur ces �v�nements pour mettre un syst�me de r�action au point ;)
Maintenant, la hi�rarchie "�v�nement" peut clairement prendre un grand nombre de cas en compte tels que inputs utilisateur, collision entre entit�s, arriv�e � un point de scrolling, d�cision "hors du jeu" de la part de l'utilisateur, timer �coul� ou que sais-je ;)
Chaque �v�nement contient son propre contexte et seules les classes susceptibles � un type d'�v�nement particulier en tiennent compte ;)
Ce n'est pas *mon* impl�mentation (je n'ai d'ailleurs quasiment pas donn� de code en ce qui concerne les �v�nement :D ), c'est juste le moyen le moins mauvais de faire en sorte que tout le monde communique de mani�re correcte et coordonn�e ;)
H� bien, il y a cependant une diff�rence flagrante :Citation:
* Sur les variables statiques
** Si une instance mutable est partag�e par plusieurs threads, elle ne pose ni plus ni moins de probl�me que des membres statiques.
** Code r�entrant : voir ci-dessus.
** Puret� des fonctions : voir ci-dessus.
Un membre (ou une instance) mutable ne va agir que sur elle-m�me ou sur l'objet dont il est membre, alors qu'une variable statique (ou une variable globale) va agir sur toutes les instances qui la manipulent:
si tu as une classe Machin (disons : Ennemy pour rester dans le cadre de la discussion :D ) qui dispose d'un membre statique brol, et que tu as deux deux instances de Ennemy (et tu risques vraiment d'en avoir encore plus :D ), mettons E1 et E2, la modification que tu pourras effectuer sur E1.brol se r�percutera immanquablement sur E2.brol, alors que cela ne doit, a priori, pas arriver ;)
Si brol est, non plus statique, mais mutable, et que tu as deux threads qui utilsent E1, (et deux autres qui utilisent E2), "tout ce qu'il convient de faire", c'est de s'assurer qu'un des thread (manipulant E1 ou E2) prendra le pas sur l'autre, mais les modifications apport�es � E1.brol n'influeront que... E1 et "foutra la paix" � E2 ;)
Ce que tu sembles oublier, c'est que ton service sonore peut parfaitement �tre totalement ind�pendant de tout le reste!!!Citation:
Maintenant si tu prends la peine de regarder ce qui serait partag�, que vois-tu ? Soit des donn�es modifi�es une fois et lues par le reste du code (�tat du contr�leur), soit des instances mutables qui seront partag�es (entit� repr�sentant Link, service sonore, etc).
Tout ce qu'il faut, c'est un moyen de lui faire savoir quels sons jouer et dans quel ordre...
Encore une fois, un syst�me d'�v�nements semble �tre la meilleure des solutions pour y parvenir: il re�oit d'office tous les �v�nements et, en fonction de ceux-ci, d�termine quel son doit etre jou�.
Il place alors les sons dans une queue d'attente, et joue les sons "un � un" ;)
Tout ce qu'il faut, encore une fois, c'est que chaque �v�nement se fasse connaitre du service sonore au moment de sa cr�ation ;) (et que le service sonore soit en mesure de mettre les �v�nements en attente de gestion dans une file d'attente ;))
Et tu crois que le fait de fournir une pellet� d'instances uniques ne va pas occasionner une pellet�e de responsabilit�, sans doute :question:Citation:
* Sur la GodClass jamais simple :
Nous ne parlions pas d'une classe regroupant des pellet�es de responsabilit�s. Nous parlions d'une classe ne fournissant aucune service et se contentant d'exposer quelques singletons (pas le pattern, l'unicit�) en lecture seule (initialis�s au d�marrage).
Si tu d�l�gue correctement les responsabilit�s, il est tout � fait possible que chaque "module" du programme puisse fonctionner de mani�re ind�pendante en n'�tant, en gros, pilot� qu'en fonction des �v�nements qui surviennent...
Il n'y a aucune raison que le syst�me de sons soit connu (ou connaisse) le syst�me de d�tection de collisions, le syst�me d'affichage ou le syst�me de gestion des ennemis.
Le seul syst�me plus ou moins central qu'il faut avoir est... le syst�me de g�n�ration d'�v�nements, et encore, la g�n�ration d'�v�nement peut parfaitement etre d�centralis�e en fonction du type d'�v�nement � g�n�rer, car, de toutes fa�ons, l'�v�nement est destin� � �tre r�cup�r� par... le moteur de jeu de mani�re � etre transmis � "qui de droit" ;)
Le cas de la collision entre une entit� Mobile et une entit� immobile est le cas le plus simple � vrai dire : l'entit� active (celle qui entre en collision avec l'autre :D ) est l'entit� mobile, alors que l'entit� passive (celle qui subit la collision) est l'entit� immobile :D
Les choses deviennent certainement plus compliqu�es au niveau des collisions entre entit�s mobile :D
Le fait est qu'une collision provoque un syst�me de r�action de la part des deux intervenants...Citation:
Si tu cr��s un ICollisionBehaviour et que tu l'associes aux classes MoveEntity et NoMoveEntity, comment vas tu g�rer les collisions au cas par cas, c'est � dire :
- Enemy (Movable) VS Player (Movable) => faudra d�clencher un "Hit" sur le Player
- Enemy (Movable) VS Hole (NoMovable) => Enemy va changer de direction pour �viter le trou (d'ailleurs le d�placement des ennemies est al�atoire dans Zelda :D pas d'algo de type A* ou autre)
- Player (Movable) VS Door (NoMovable) => D�clencher une t�l�portation vers une autre zone de la map
En fait ton impl�mentation me plait bien :ccool:, j'ai juste peur d'�tre coinc� au niveau des collisions entre toutes les entit�s :(
L'entit� qui entre en collision avec une autre va r�agir � sa mani�re d'un cot� et celle qui subit la collision va r�agir � sa mani�re de l'autre ;)
Le tout est de savoir qui va prendre la priorit� dans l'ordre de la r�action ;)
Mais, tu prend l'exemple d'une porte, sa r�action en cas de collision sera de forcer l'entit� qui est entr�e en collision avec elle (si elle existe encore apr�s la collision :D ) � se d�placer instantan�ment vers une autre position ;)
En fait, je crois que l'on ne se comprend pas bien sur ce qui pourrait etre un sprite :aie:Citation:
Derni�re chose, tu as des entit�s qui ont un Sprite qui s'anime quand il se d�place (Enemy et Player), d'autres entit�s qui s'animent ind�finiment (des bougies, des �l�ments du d�cor pour rendre la map "vivante"), et d'autre qui sont fixes (une pancarte, une maison...) et d'autres qui s'animent lors d'un �v�nement (ouverture d'une porte par exemple, apparition d'un objet...).
Comment vas tu g�rer ca ? Tu ne vas quand m�me pas cr�er des nouveaux types d'entit�s qui d�rivent de Entity ? :D
Pour moi, un sprite est, simplement, une entit� qui a sa vie propre mais qui n'est ni un �l�ment du d�cors, ni un objet d'inventaire, ni un ennemi, ni le joueur...
Un sort lanc� par un ennemi ou un joueur ou un objet n'attendant qu'� etre ramass� pourraient, par exemple, etre des sprite ;)
Le fait qu'une bougie, par exemple, puisse utiliser plusieurs images pour illustrer le mouvement de sa flamme, je veut pas forc�ment dire que la flamme doive �tre un sprite : la bougie est, simplement, compos�es de plusieurs images utilis�es dans un ordre donn� ;)
Le fait qu'une porte change d'aspect lorsqu'on l'ouvre n'implique absolument pas que l'on ait besoin d'un sprite pour y arriver : on a simplement deux �tats (ouverte et ferm�e) qui correspondent � deux repr�sentations graphiques diff�rentes ;)
Tu auras d'ailleurs remarqu� que la classe Sprite que je fournis h�rite, tout simplement, de MovableEntity, et dispose d'informations susceptible de lui permettre d'avoir sa vie propre (vitesse et direction ;) )
Ce qu'il peut manquer, �ventuellement, c'est une information sur le son � jouer � sa cr�ation, � sa destruction et durant sa dur�e de vie ;)
Il ne s'agirait, en effet, pas de cr�er une classe sprite par image que tu veux afficher pour celui-ci, il "suffirait" que le sprite dispose de l'ensemble des images qu'il doit faire afficher les unes apr�s les autres ;)
Par contre, si cela a une utilit� quelconque, nous pourrions envisager de sp�cialiser la classe Sprite en diff�rentes cat�gories telles que "armes", "aliments" (ou nous trouverions des pommes, des potions ou des bout de gigot :D ) et "sorts" ;)
Je ne dis pas que cela doit se faire, hein, je dis juste que, si cela pr�sente un int�r�t quelconque, il peut etre utile de l'envisager ;)
@koala01
Le fait que la remarque �tait adress�e � Aspic ne la rend pas moins grossi�re.
*Sur les �tats du contr�leur:
Laisse-moi r�sumer : dans ton premier post tu me faisais une remarque qui ne s'appliquait qu'au cas o� l'�tat du joueur serait mis � jour par les �v�nements du contr�leur. Apr�s que j'ai point� cette restrictions, tu m'expliques donc que, oui, mais bon, de toute fa�on il faut faire comme �a et que c'est beaucoup plus naturel ainsi. D'abord, �a me fait un peu penser � l'expression "noyer le poisson".
Maintenant, je reviens tout de m�me un instant sur cette conception. Quand vas-tu devoir changer l'�tat de Link ? A chaque collision. A chaque pression des touches du contr�leur. A chaque fois qu'une animation bloquante se termine. Etc, etc, etc... Et � chaque fois tu vas devoir modifier plusieurs �tats en cons�quence : l'animation, le mode d'interaction avec le monde (pendant l'anim qui suit un coup le perso devient invincible), avec le contr�leur (certaines animations ne peuvent pas �tre interrompues), etc. Qu'est-ce qui te semble le plus simple � �crire, lire et maintenir ? D'exploser cette gestion d'�tats conflictuels sur cinq ou six �v�nements avec du code redondant (v�rifier que les �tats de plus hautes priorit�s autorisent l'ex�cution) et dont on ne sait pas dans quel ordre ils s'ex�cutent, ou bien d'�crire une proc�dure unifi�e appel� une seule fois par frame ?
Toujours sur cette conception, il ne faudrait pas confondre les choses : on peut tr�s bien avoir un scheduler bas� sur des �v�nements pour ordonner par exemple "ex�cute tel code dans x millisecondes", ou un syst�me �v�nementiel � un plus haut niveau (UI). Mais il n'y a pas besoin pour autant que le coeur soit bas� sur des �v�nements. Personnellement, de mon exp�rience, ce n'est pas l'architecture la plus ais�e pour le coeur du jeu et il est plus simple de mettre chaque entit� � jour � chaque frame.
*Sur les membres statiques:
Le fait que E1 et E2 soient tous deux affect�s par le changement de la variable statique n'est pas un probl�me, c'est le but recherch� par la d�claration en statique (du moins dans le probl�me que tu exposais, pas dans ce que je d�crivais � Aspic : il n'y a dans ce cas aucun probl�me de ce genre).
J'insiste : il n'y a aucune diff�rence entre une variable statique et une instance mutable partag�e du point de vue de tous les probl�mes que tu as �nonc�s et il serait honn�te de le reconna�tre. Les variables statiques ne sont pas � prohiber comme tu le pensais, voil� tout.
Concernant le syst�me sonore, il est bien mutable, point barre. Accessoirement, non, tu vas pas mettre en file les sons. Un son peut soit en �craser un autre, soit se superposer � ceux en cours mais il ne se met pas en file.
*Sur le regroupement des services:
Non, qu'une classe contienne une r�f�rence vers une instance ne lui donne pas les responsabilit�s de cette instance. Et il n'a jamais �t� question que ce syst�me soit fait pour permettre au gestionnaire de collisions d'acc�der au syst�me sonore ou quoi que ce soit de ce genre. Je t'invite � relire les �changes successifs.
Elle �tait peut etre un peu rude, mais n'�tait pas grossi�re, ou, du moins, ne voulait pas l'�tre ;)
Il n'en demeure pas moins qu'il est beaucoup plus coh�rent de faire en sorte que tout ce qui correspond � un input issu du joueur soit "centralis�" en un point (ou dans un module particulier), que ce module se charge de traiter l'information ainsi re�ue et de transmettre l'information partout, sans qu'il soit besoin, hors du module concern�, de de voir s'int�resser � la touche qui a effectivement �t� enfonc�e.
Tu n'as donc absolument aucun besoin d'avoir un acc�s global aux inputs issus du joueur car � la r�ception de chaque input ne doit correspondre qu'un "signal" donn�, qui pourra etre compris comme tel par l'ensemble des "modules" susceptibles d'y r�agir...
Cela permettra en outre, par exemple, au joueur de modifier la touche qui a pour effet de te faire avancer ou d'aller � droite: il n'y a qu'une table de correspondance � mettre � jour entre la touche enfonc�e et le "signal" envoy�, et il n'y a meme plus besoin d'avoir acc�s � la configuration actuelle pour d�terminer si le joueur voulait avancer, reculer, sauter ou aller � droite ;)
Tu as tr�s mal interpr�t� ce que j'ai dit...Citation:
*Sur les �tats du contr�leur:
Laisse-moi r�sumer : dans ton premier post tu me faisais une remarque qui ne s'appliquait qu'au cas o� l'�tat du joueur serait mis � jour par les �v�nements du contr�leur. Apr�s que j'ai point� cette restrictions, tu m'expliques donc que, oui, mais bon, de toute fa�on il faut faire comme �a et que c'est beaucoup plus naturel ainsi. D'abord, �a me fait un peu penser � l'expression "noyer le poisson".
Je te fais un copier coller de ma premi�re intervention pour ce qui concerne le joueur:Autrement dit :Citation:
Envoy� par moi meme
Par la suite, j'ai effectivement introduit la notion de syst�me d'�v�nements, parce que la grosse majorit� des r�actions se fera sur un d�nominateur commun qui est : la survenue d'un �v�nement.
- Par moment, on pourra parfaitement se contenter de consid�rer le joueur comme �tant une entit� "quelconque"
- A d'autre moments, il faudra consid�rer le joueur comme �tant du type d'entit� particulier :joueur, et le fait que joueur h�rite (de mani�re indirecte) de Entit� n'interviendra sans doute pas dans la gestion qui en sera faite, car nous ne nous int�resseront exclusivement � ce qui fait que notre entit� est un joueur
- Parmi tout ce dont le "module" qui s'occupe de la gestion du joueur aura � s'occuper, on trouvera, entre autres, une partie qui s'occupera de g�rer les inputs issus du joueurs et de g�n�rer les �v�nements qui vont bien en fonction de ces inputs.
Je ne parle pas ici uniquement des �v�nements issus de l'appui sur une touche par l'utilisateur!!!
Je dis que, lorsque deux entit�s entre en collision, qu' un ennemi d�cide de frapper quelque chose ou de lancer un sort, qu'un sort touche quelque chose, ou que sais-je, nous observons la survenue d'un �v�nement, et que c'est ce qui jalonne litt�ralement la ligne de temps de l'application.
Je dis, enfin, que, dans la liste de tous les �v�nements susceptibles de survenir, il y aura, entre autres provoqu�s par l'appuis d'une touche de la part de l'utilisateur ;)
Tu aurais donc une classe de base Event, qui correspond � un �v�nement dont "on ne sait rien", qui sera sp�cialis� en "CollisionEvent", en "NpcEvent", en "GamerEvent" ou en que sais-je, pour pouvoir d�terminer l'origine des �v�nements et qui seront eux meme sp�cialis�es en d'autres �v�nements plus sp�cifiques de mani�re � provoquer la r�action appropri�es dans les autres modules.
Le tout en sachant qu'il est tout � fait possible de faire en sorte qu'un module particulier ignore carr�ment un type particulier d'�v�nement, parce que sans objet pour le module en question (par exemple, le syst�me qui s'occupe de g�rer le joueur n'aura sans doute que faire des �v�nements provoqu�s par les ennemis, mais devra g�rer un grand nombre des �v�nements susceptibles de survenir en cas de collision)
Je suis d�sol� si cela contredit ton approche, mais il me semble que cela correspond � l'approche "logique" d�s le moment o� l'on envisage de s�parer clairement les responsabilit�s en cr�ant, au final une s�rie de modules ind�pendants les un des autres : chaque module se charge de cr�er les �v�nements qui lui sont propres pour qu'ils soient r�cup�r�s par le moteur de jeu et "dispatch�s" vers les modules susceptibles d'y r�agir ;)
Tu as bien utilis� le terme : �tat...Citation:
Maintenant, je reviens tout de m�me un instant sur cette conception. Quand vas-tu devoir changer l'�tat de Link ? A chaque collision. A chaque pression des touches du contr�leur. A chaque fois qu'une animation bloquante se termine. Etc, etc, etc... Et � chaque fois tu vas devoir modifier plusieurs �tats en cons�quence : l'animation, le mode d'interaction avec le monde (pendant l'anim qui suit un coup le perso devient invincible), avec le contr�leur (certaines animations ne peuvent pas �tre interrompues), etc.
Beaucoup de choses agiront au final comme des "mini machines � �tats"...
Pour chaque �tat donn�, il y aura une s�rie d'�v�nement autoris�s ou non...
En Cr�ant une hi�rarchie d'�v�nement coh�rente et correcte, il te sera parfaitement possible de faire en sorte que la grosse majorit� des �v�nements refus�s par un �tat donn� soit purement et simplement envoy�s vers une fonction "qui ne fait rien" pour n'avoir, au final que quelques �v�nements susceptibles de provoquer une transition vers un nombre limit� d'�tats suivants
en g�rant correctement tes �tats et tes �v�nements, tu n'auras meme pas � t'en inqui�ter : chaque �tat ne pouvant, de toutes mani�res, permettre la transition vers un nombre limit� d'�tats suivants, cela se fera de mani�re syst�matique, et sans qu'il ne soit besoin pour la cause d'avoir du code redondant ;)Citation:
Qu'est-ce qui te semble le plus simple � �crire, lire et maintenir ? D'exploser cette gestion d'�tats conflictuels sur cinq ou six �v�nements avec du code redondant (v�rifier que les �tats de plus hautes priorit�s autorisent l'ex�cution) et dont on ne sait pas dans quel ordre ils s'ex�cutent,
Elle ne sera peut etre pas appel�e une seule fois par frame, mais la proc�dure restera unifi�e malgr� tout...Citation:
ou bien d'�crire une proc�dure unifi�e appel� une seule fois par frame ?
Si tu te place au niveau du game engine(qui, rappelons le, r�cup�re tous les �v�nements g�n�r�s par les diff�rents modules :D ) cela revient � faire
avec la fonction transmitEvent qui ressemble �Code:
1
2
3 transmitEvent( event) update() draww()
la fonction update() qui ressemble �Code:
1
2
3
4
5
6
7
8 void GameEngine::transmitEvent(Event * event) { ennemiesManager_.setNextEvent(event); gamerManager_.setNextEvent(event); entitiesManager_.setNextEvent(event); /* ... * tout vers quoi il faut envoyer l'événement ;) */ }
et la fonction draw() qui ressemble �Code:
1
2
3
4
5
6
7
8 void GameEngine::update() { ennemiesManager_.update(); gamerManager_.update(); entitiesManager_.update(); /* ... * tout ce qui doit etre mis à jour ;) */ }
Code:
1
2
3
4 void GameEngine::draw() { entitiesManager_.draw(); }
Pourquoi pas, �tant donn� que tout est susceptible de provoquer survenue ou de r�agir � la survenue d'un �v�nement, et que c'est quand meme ce qui jalonne la ligne de temps de ton application :question:Citation:
Toujours sur cette conception, il ne faudrait pas confondre les choses : on peut tr�s bien avoir un scheduler bas� sur des �v�nements pour ordonner par exemple "ex�cute tel code dans x millisecondes", ou un syst�me �v�nementiel � un plus haut niveau (UI). Mais il n'y a pas besoin pour autant que le coeur soit bas� sur des �v�nements.
Et tu mets ton entit� � jour de quelle mani�re :question: sur base de l'air du temps :question: sur base d'un comportement qui n'a rien � faire de ce qui a pu se passer � cot� d'elle :question: ou sur base des �v�nements qui sont survenus entre la frame pr�c�dente et celle que l'on va devoir afficher (et qui ont eu un impact sur elle ou sur sa r�action ) :question:Citation:
Personnellement, de mon exp�rience, ce n'est pas l'architecture la plus ais�e pour le coeur du jeu et il est plus simple de mettre chaque entit� � jour � chaque frame.
C'est, justement, le probl�me...Citation:
*Sur les membres statiques:
Le fait que E1 et E2 soient tous deux affect�s par le changement de la variable statique n'est pas un probl�me, c'est le but recherch� par la d�claration en statique (du moins dans le probl�me que tu exposais, pas dans ce que je d�crivais � Aspic : il n'y a dans ce cas aucun probl�me de ce genre).
Tu ne peux pas garantir que, dans un contexte identique, l'appel d'une fonction en passant en param�tre E1 ou E2 aura un comportement identique si un membre est partag� par les deux objets (et risque d'�tre modifi� "par ailleurs"!!!
Que tu d�clares une constante statique passe encore, vu que, par d�finition, sa valeur ne changera pas!!!
Mais si tu utilises une variable statique, tu n'a aucun contr�le sur la valeur qu'elle pourra avoir � un instant T pour un objet X, vu que tous les objets de m�me types sont susceptibles d'y avoir chipot�.
Les constantes statiques ne sont pas � prohiber!!!Citation:
J'insiste : il n'y a aucune diff�rence entre une variable statique et une instance mutable partag�e du point de vue de tous les probl�mes que tu as �nonc�s et il serait honn�te de le reconna�tre. Les variables statiques ne sont pas � prohiber comme tu le pensais, voil� tout.
Les variables statiques sont le meilleur moyen de "foutre le bordel" en te retrouvant avec un objet dont le comportement est incoh�rent du seul fait que tu perds tout contr�le de la valeur de la variable!!!
Il n'a meme pas � �tre mutable : il a, purement et simplement, � etre ind�pendant et � �tre "pilot�" (par envois d'�v�nement) par le Game Engine;)Citation:
Concernant le syst�me sonore, il est bien mutable, point barre.
Tu n'as aucun besoin d'y faire appel depuis ailleurs que... depuis le game engine ;)
ca, je suis d'accord, j'aurais pu etre plus explicte quant � mon explication ;)Citation:
Accessoirement, non, tu vas pas mettre en file les sons. Un son peut soit en �craser un autre, soit se superposer � ceux en cours mais il ne se met pas en file.
Le probl�me est que, si cette instance se balade partout, elle prend, fatalement, la responsabilit� de fournir l'acc�s aux diff�rents gestionnaires, et que, de ce seul fait, elle fournira n'importe o� l'acc�s � n'importe quel gestionnaire!!!Citation:
*Sur le regroupement des services:
Non, qu'une classe contienne une r�f�rence vers une instance ne lui donne pas les responsabilit�s de cette instance. Et il n'a jamais �t� question que ce syst�me soit fait pour permettre au gestionnaire de collisions d'acc�der au syst�me sonore ou quoi que ce soit de ce genre. Je t'invite � relire les �changes successifs.
De l� � se retrouver dans une situation dans laquelle le module qui s'occupe de g�rer les collisions fasse directement appel au syst�me de gestion des sons, il n'y a qu'un pas qui sera bien trop all�grement franchi uniquement parce que "il est possible de le faire"!!!
Pourquoi diable faudrait il passer une instance qui donne acc�s "� tout" alors qu'on n'a de toutes mani�res besoin que d'une infime partie de ce � quoi cette instance donne acc�s :question:
En tout cas moi je ne comprends plus rien du tout :aie:
Tout se disperse et au final tout m'embrouille.
Je vois un ennemiesManager mais c'est quoi ? D'un cot� le World met � jour toutes les entit�s mais il y a quand m�me un Manager par type d'entit�, je suis paum� sans compter des �v�nements � transmettre � tout le monde :calim2: 8O
Je pense qu'un exemple complet serait le bienvenue ;)
Bon, reprenons...
Je te conseille, depuis le d�part, de d�l�guer au maximum les responsabilit�s en cr�ant ce que j'appelais au d�part des "syst�mes de gestion", mais dont le terme correct est en fait beaucoup plus proche de "module".
Tu cr�erais donc une s�rie de modules g�rant le "cycle de vie" des diff�rents types d'entit�s en les consid�rant comme tels.
Cela te donne (cf le code de cette r�ponse) des modules tels que:Chaque module tournant, entre autres, autour d'une classe dont la responsabilit� est de garder une trace de toutes les entit�s du type concern�es par le module qui sont cr��es, entre le moment de leur cr�ation et celui de leur destruction.
- un module de gestion des sprites
- un module de gestion des ennemis
- un module de gestion des �l�ments de d�cors
- un module de gestion des objets d'inventaire
- ...
Tous ces modules sont "mis en relation" entre eux gr�ce au game engine qui dispose, d'une (et une seule) instance de cette fameuse classe dont la responsabilit� est la gestion des entit�s d'un type particulier: ce que j'ai nomm� (dans ma derni�re intervention, mais aussi dans le message auquel j'ai d�j� fait r�f�rence plus haut :D ) sous les noms de ennemiesManager_ , gamerManager_ , ou encore entitiesManager_ .
Les gros avantages de travailler de la sorte sont:
- De nous permettre, pour chaque entit� existante, de disposer d'un moyen de l'utiliser en fonction de son type r�el
- De nous permettre de g�rer "� la chaine" l'ensemble des entit�s d'un type particulier ( comprend : dont le type r�el correspond au type d'entit� dont un module particulier a la charge)
- De permettre de travailler sur un type d'entit�s particulier sans "s'inqui�ter du reste"
Parall�lement � cela, il faut mettre en place un syst�me permettant aux diff�rents modules de r�agir les uns par rapport aux autres...
Le meilleur moyen d'y arriver est de travailler sur les �v�nements qui peuvent survenir: Chaque module va g�n�rer un nombre "restreint" d'�v�nement en fonction du type d'entit� dont il a la responsabilit�.
Chaque fois qu'un �v�nement sera g�n�r� par un module particulier, il devra �tre "r�cup�r�" par le game engine de mani�re � �tre transmis aux autres modules afin de leur donner l'occasion d'y r�agir, ou non, selon l'int�r�t que l'�v�nement peut avoir pour un module donn�.
Le monde quant � lui interviendra dans un module qui connait l'ensemble des entit�s existantes, quel que soit leur type r�el, mais qui ne peut donc les manipuler que... en tant que Entity et qui r�agira essentiellement aux �v�nement susceptibles de provoquer le "scrolling" vers une position donn�e de la carte ;)
En restant dans les modules ou types particuliers, nous avons �galement le sound player, qui n'a que faire des entit�s, mais qui r�agit exclusivement aux �v�nements (potentiellement � tous les �v�nements), bien qu'ayant (si besoin) �galement sa propre vie propre (ex: pour la musique de fond), ou le render qui aura pour responsabilit� d'afficher l'ensemble des entit�s consid�r�es par le monde comme �tant � afficher ;)
Si je trouve un peu de courage pour le faire, je te placerai (peut etre) un diagramme de classe et (qui sait :D ) un diagramme de communication pour te rendre les choses un peu moins abstraites ;)
Oui je crois comprendre ce que tu veux faire mais encore une fois, je n'arrive pas � voir comment les �v�nements vont �tre transmis par le moteur de jeu aux diff�rents "manager".
Oui je pense qu'un diagramme de classe serait cool :ccool:
Un diagramme de communication, je ne sais pas ce que c'est je connais le diagramme de s�quence mais ca doit �tre assez proche ;)
Je reviens sur les sprites, tu as dis que pour toi un sprite c'�tait par exemple un coeur a ramasser. Or apr�s tu dis que ta classe Sprite d�rive de MovableEntity. Or un coeur ne se d�place pas...
Donc je vois mal ce que tu appelles "Sprites" car pour moi, un sprite est simplement une image qui peut s'animer (plusieurs images) ou pas (une seule image). Une entit� est alors compos� d'un Sprite, ainsi que d'autres attributs comme la position, la taille, la visibilit�...
Le moteur de jeu est, finalement, le seul point o� l'ensemble des modules utilis�s est connu, et donc d'o� il sera possible d'acc�der au manager propre � chaque module.
Or, la plupart des modules vont g�n�rer une s�rie d'�v�nements li�s aux entit�s dont ils ont la charge:
Le module de d�tection de collisions, par exemple, pourrait g�n�rer un �v�nement (d�riv� du) type CollisionEvent qui d�rive quant � lui (de mani�re plus ou moins directe) de la classe anc�tre Event.
Le moteur de jeu va r�cup�rer tous les �v�nements g�n�r�s (dont certains lui seront d'ailleurs sans doute exclusivement destin�s, pour permettre, par exemple de passer en mode "modification des options"), et, comme il a acces � l'ensemble des modules, il est en mesure de renvoyer tous les �v�nements qu'il re�oit vers une classe qui, en fonction du module dans lequel elle se trouve, r�agira de mani�re adapt�e � l'�v�nement.
Si tu cr�es une hi�rarchie suffisamment pr�cise d'�v�nement (par exemple, le lancement d'un sort par quelqu'un g�n�re un �v�nement de type SpriteCreationEvent qui h�rite de SpriteEvent qui h�rite de Event), il sera particuli�rement facile de faire en sorte que cette classe "laisse tomber" tout un pan de la hi�rarchie Event, parce qu'elle n'a pas � s'en occuper ;)
Rien n'emp�che une MovableEntity d'avoir une direction et une vitesse nulle, ce qui la r�duirait de facto �... rester sur place :DCitation:
Je reviens sur les sprites, tu as dis que pour toi un sprite c'�tait par exemple un coeur a ramasser. Or apr�s tu dis que ta classe Sprite d�rive de MovableEntity. Or un coeur ne se d�place pas...
C'est, peut etre, sans effet sur un jeu 2D, mais les objets qui attendent d'�tre ramass�s pourraient parfaitement �tre soumis � la pesenteur et ne peuvent, en aucun cas, �tre consid�r�s comme �tant aussi immobiles (meme s'il le sont de facto du fait de leur vitesse et leur direction nulle) que l'arbre ou la pierre qui fait partie du d�cors :aie:
De plus, et, malgr� les apparences, un objet d'inventaire est beaucoup plus mobile qu'il ne peut y paraitre au premier abord:
Tu me diras sans doute que j'ergote ou que je joue sur les mots, mais, comprend tu pourquoi il est important qu'un objet d'inventaire soit consid�r� comme une entit� susceptible de se d�placer ?
- Lorsqu'il sera ramass�, il passera du monde � l'inventaire
- Si le joueur le tiens en main, il subira les mouvement du bras auquel est rattach�e la main qui le tiens
- S'il y a un "bandeau d'inventaire", il peut se trouver (ou non) � diff�rentes positions dans ce bandeau, et le bandeau lui-m�me peut se trouver � diff�rentes positions dans l'�cran de jeu
Le probl�me est alors que tout est sprite, car, meme s'il n'y a qu'une image � afficher, cela peut etre consid�r� comme un sprite :aie:Citation:
Donc je vois mal ce que tu appelles "Sprites" car pour moi, un sprite est simplement une image qui peut s'animer (plusieurs images) ou pas (une seule image). Une entit� est alors compos� d'un Sprite, ainsi que d'autres attributs comme la position, la taille, la visibilit�...
Mais, dans ce cas, quelle diff�rence fait on entre le sprite et l'entit� :question: � moins qu'il n'y ait, tout simplement, qu'une relation d'aggr�gation entre les deux, et que le sprite participe au comportement d'affichage :question:
Ce n'est pas exclu, c'est une mani�re d'envisager les choses ;)