Bonjour,
Cette question porte sur les meilleures pratiques et l'organisation des classes pour un jeu (indépendemment du langage).
Navré si elle n'est pas dans la bonne catégorie, j'ai eu du mal à choisir.
Considérons que je souhaite développer un jeu d'échec. Je vais avoir un modèle représentant mon jeu, l'échiquier, les différents pions tout cela dans organisés dans plusieurs classes. Je vais certainement avoir une classe Piece, qui représentera une pièce sur l'échiquier, et qui aura entre autres les attributs :
Ces attributs représentent la position de la pièce sur l'échiquier, dans le système de coordonnées de l'échiquier (case (0,0) à (7,7)). D'un point de vue modélisation, une pièce est forcément sur une case (et non à cheval entre deux).
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 int boardX int boardY
Quand le controlleur de jeu va vouloir opérer une action sur le jeu, il va probablement appeler une ou lpusieurs fonctions de notre modèle de jeu qui va immédiatement changer, entre autres, les coordonnées d'une pièce.
Ca c'est pour le point de vue modèle de données. Voyons maintenant d'un point de vue Vue (dans le pattern MVC)
La vue va faire le rendu de l'échiquier et des pièces qu'il contient. Elle va certainement avoir une référence vers les classes du modèle de jeu, va éventuellement s'enregistrer à des évènements du modèle, puis obtenir les positions des pièces dont elle a besoin. Pour dessiner la scène, la vue va donc itérer à travers le modèle de jeu pour obtenir les coordonnées des pièces (et convertir du système de case en pixels). Jusqu'ici tout va bien.
Maintenant supposons que je veuille ajouter des animations, et qu'une pièce se déplace en 1 seconde.
La vue a une référence vers le modèle de jeu, mais le modèle de jeu n'a pas l'information de la vraie position en pixel des pièces pendant leurs mouvement. Alors on peut imaginer une nouvelle classe pour gérer ces informations, disons une classe GraphicPiece, contenant une référence vers la Piece sous-jacente et deux attributs :
Avant de poser les questions, dans cet exemple, j'ai utilisé un jeu d'échec et un exemple trivial, mais le cas se pose pour un modèle de donnée bien plus complexe, composé de plusieurs éléments différents, avec des interconnections entre eux, et qui évoluent au fil du jeu.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 int pixelX int pixelY
Q1 : Ou est-ce que les instances de GraphicPiece devraient-elles être stockées ? Doit-on privilégier un modèle orienté-vue comme étant un duplicata du modèle de jeu mais contenant uniquement les informations de niveau vue ? Si oui cela lève d'autres problèmes comme la synchronisation du modèle orienté-vue quand le omdèle de jeu évolue. De plus, si la vue utilise des informations à la fois des deux modèles, il pourrait subvenir des incohérences (le modèle orienté-vue a des évolution progressives dans le temps, quand le modèle de jeu voit ses états modifiés instantanément).
Q2 : Quand la vue fait son rendu, elle va utiliser le modèle de jeu pour itérer sur les pièces qui doivent être affichées. Mais la classe Piece n'a pas de référence vers la classe GraphicPiece donc la vue n'a pas de moyen de trouver les coordonnées de la pièce. Utiliser une map<Piece,GraphicPiece> est à écarter (over-killed et peu performant)
Q3 : La classe Piece ne peut pas avoir une référence vers une GraphicPiece sinon cela casserait le principe d'isolation de la logique métier de la vue. Au pire, une Piece peut avoir un pointeur générique ou Object qui contiendra une instance de GraphicPiece plus tard downcastée, mais ce n'est vraiment pas une solution élégante.
Q4 : Si j'essaie de résumer les problèmes levés : Quel design et organisation de classes est adapté pour qu'une vue puisse puisse accéder efficacement aux informations d'un modèle de jeu (potentiellement complexe) et à des informations additionnelles de niveau vue ? Sur quel objet ou modèle la vue devraient itérer pour faire le rendu des Piece en ayant accès à toutes ces informations ?
J'espère avoir réussi à énnoncer le plus clairement possible la problèmatique à laquelle je fais face.
Merci en tout cas d'avoir lu jusqu'ici.
Stéphane
Partager