On a voulu commencer en écrivant le code le plus simple et efficace qui permettait de réaliser un pac-man. Celui-ci n’utilisait que très peu de classes ou patrons de conceptions, il était simple et efficace mais aussi très spécifique et inflexible. On a donc corrigé le tir en passant à une architecture de moteur de jeu entité-composant. Le moteur de jeu est entièrement séparé du jeu lui-même et d’autre jeu pourraient être implémentés sur le même moteur sans le changer ou presque. Le système entité-composant se base principalement sur l’idée de favoriser la composition par rapport à l’héritage. Son principe est simple : chaque objet dans une scène d’un jeu (une scène étant un « écran » de jeu ou une phase, comme un niveau mais aussi un menu…) est une entité. Une entité consiste d’un ou plusieurs composants qui lui ajoutent une fonctionalité ou un comportement. Cela permet de simplifier la hiérarchie de classe, mais également de mettre en place certaines optimisations du domaine de la programmation orientée données. Avec l’entité et le composant, la troisième brique élémentaire de cette architecture est le Système, aussi appelé Serveur ou Moteur. Ceux-ci fonctionnent indépendamment et effectuent un traitement sur sur toutes les entités qui possèdent un composant qui touche un aspect similaire au serveur. Plus concrètement, sur l’exemple de notre jeu pac-man : le pac-man, les fantômes, le labyrinthe et les pac-dots sont des entités. Ils ont tous un composant « représentation graphique » entre autres qui permet de les afficher à l’écran et contient les données nécessaire pour cela (leur image, mais aussi leur niveau/hauteur pour savoir lesquels afficher au-dessus des autres). Le moteur dispose d’un serveur graphique qui, à chaque itération de la boucle principale de jeu, itère sur tous les composants graphiques et en effectue le rendu pour finalement l’afficher dans la fenêtre du jeu. Un deuxième composant que beaucoup d’entités vont posséder est lui lié à la gestion de la physique. Le serveur physique associé va à chaque tour de boucle calculer les nouvelles position des entités (pour celles qui doivent/peuvent se déplacer) mais aussi calculer et résoudre les collisions, éventuellement en envoyant un signal aux entités concernées en cas de collision. Finalement, chaque entité peut avoir un comportement personalisé sous forme d’une fonction appelée à chaque itération. Le niveau lui est lu depuis une image basse résolution où chaque pixel défini une case, est génère sa représentation graphique à partir de celle-ci. Il créé également des composants physique de collision pour chaque mur solide et les entités des pac-dots. Pacman |- comportement personalisé (appelé à chaque itération) : | entrées = lire_entrées | si entrée[gauche]: | aller à gauche | … |- sprite (image : pacman.png) |- boîte de collision (taille) Niveau |- sprite (image: le niveau, généré à partir d’une description) |- boîte de collision mur 1 |- boîte de collision mur 2 |- … Fantôme |- comportement personalisé : | déplacement automatisé (IA) |- sprite (image: fantôme.png) |- boîte de collision Le moteur contient donc la définition d’une entité, des différents composants et serveurs et de la boucle principale. Le jeu lui est séparé du moteur et n’est qu’un ensemble de scènes, qui sont une simple collection d’entitées avec des composants pré-établis et des comportements personalisés. En termes de patrons de conception utilisés : - le système entité-composant est lui-même un patron (d’architecture plus que de conception), - le décorateur est utilisé à divers endroits, par exemple pour ajouter diverse responsabilité à une boîte de collision et la rendre traversable (simple zone de détection « trigger » comme pour les pac-dots), solide statique (un mur), solide dynamique (pac-man, les fantômes), - le singleton, chaque serveur ne peut être instancié qu’une fois et le patron singleton permet également de retrouver cette instance de n’importe où dans le code plutôt que d’avoir à passer des références de partout, - observateur, pour synchroniser les propriétés des composants. Évolutions futures possibles : - système de gestion des entrées, chaque entité qui veut recevoir des entrées (clavier, manettes) doit posséder un composant qui décrit quelles actions l’intéresse et le comportement à adopter lorsqu’elles sont reçues, - système d’animation, celles-ci sont pour l’instant gérées manuellement dans le comportement personalisé des entités mais devraient être un composant spécialisé (le lecteur d’animation) qui lit des animations qui seraient alors un nouveau type de resource qui modifient les propriétés d’une entité (et ses composants) au fil du temps, par exemple changer l’image d’un pac-man pour utiliser alternativement celle avec bouche ouverte et celle avec bouche fermée (waka-waka). On peut également penser à une machine à état qui gère les états et transitions entre ces états (dans un jeu 3D, passage de l’état « debout » à l’état « courrir » qui ont chacun leur animation, tout en effectuant une transition entre les deux animations pour éviter les changements brutaux), - gestion spécifique des resources, pour l’instant chaque composant stocke les resources dont il a besoin, principalement des images. un moteur de jeu plus complexe peut avoir une gestion des resources spécialisée pour optimiser l’utilisation mémoire gérer automatiquement les conversions entre différents formats, - de manière globale, généraliser tous ce qui peut être généralisé dans les fonctions personalisées de chaque entitée sous la forme de composants.