Binôme 16
- PandaLunatique
- LeMeuble
Pour la lecture de ce rapport, il est préférable de le lire sur Github afin d'avoir les accès rapides aux classes et méthodes.
Dans ce compte-rendu, nous allons expliquer la direction qu'a pris le projet au cours de son développement. Nous allons présenter les différentes étapes du développement, les choix d'implémentations qui ont été réalisées, les difficultés rencontrées et les solutions apportées. De plus, nous allons expliquer les bonus du projet qui ont été réalisés ainsi que les éléments du squelette qui ont été modifiés.
Afin de pouvoir travailler en binôme sur le projet de façon efficace et organiser, nous avons décidé d'utiliser l'outil de versioning git, à travers un dépôt github. Il est donc possible de voir l'évolution du projet à travers les différents commits réalisés. Le dépôt est accessible à l'adresse suivante : Lien du Github
Pour permettre une visualisation globale de l'ensemble du projet, nous avons réalisé un diagramme UML avec les différentes classes et leurs relations.
Pour un diagramme plus détaillé, il est possible de le trouver à l'adresse suivante : Diagramme UML détaillé
Le plateau de jeu est représenté par une matrice à deux dimensions encapsulée dans la
classe Grid
. Cette dernière
permet
une utilisation simple de la liste à deux dimensions interne de Case
. Chaque case contient
nécessairement un Terrain
et
une potentielle Unit
. Une instance de Grid
est créée en
début de chaque partie selon la fr.istic.map sélectionnée. Le tableau
à
deux dimensions est rempli grâce au parseur qui permet la conversion d'un fichier texte (au format ASCII) en une matrice
de Case
.
L'implémentation du parseur a été changé pour les besoins du projet : Bonus | Parseur de carte.
Les Terrain
sont contenus dans une Case
de
la Grid
. Pour cette
implémentation, nous avons décidé de créer une
classe abstraite
Terrain
qui est étendues par toutes les sous-classes. Certains particuliers ont une
classe mère abstraite
intermédiaire : la classe Property
Voici la liste des terrains implémentés dans le jeu :
Concernant les unités, nous avons dû faire une structure avec plusieurs classes abstraites. Ainsi, nous avons une classe
mère abstraite Unit
qui est étendue par les
classes Naval
, OnFoot
, Flying
et Motorized
. Ces dernières sont
elles-mêmes
étendues par des classes les classes propres à chaque type d'unité.
Voici la liste des unités implémentées dans le jeu :
Toutes ces unités sont déclinées en 5 couleurs, pour les 5 joueurs différents ( voir Bonus | Choix d'ajouts)
Pour les transports, il s'agit d'un cas particulier. En effet, les transports ont une classe abstraite intermédiaire par
type de d'unité.
Par exemple, les transports à chenille ont une classe
abstraite MotorizedTransport
. Chacune des classes abstraites
intermédiaires de transport implémentent
l'interface Transport
qui permet de définir les méthodes communes à tous les
transports.
Nous avons créé une classe Movement
, qui contient 2 classes
internes : Weapon.Direction
(énumération des directions
possibles : up, left, begin, etc...) et Movement.Arrow
. Cette dernière
représente une flèche dans une case, par son bord d'entrée et son bord de sortie. Le système de flèche est complètement
différent de celui demandé dans le sujet. (voir Bonus | Choix d'ajouts)
Pour les armes, nous avons créé une classe abstraite Weapon
, et nous avons distingué
les armes ayant une portée d'une
case (classe abstraite Weapon
,
étendant Weapon
) et celles ayant plus d'une case de portée (classe abstraite
Weapon
, étendant aussi Weapon
). Enfin, nous
avons fait une classe par arme devant être implémentée
(ex : Weapon
)
Dans chacune de ces classes, nous avons ajouté une énumération du multiplicateur de dégâts en fonction du type d'unité cible.
La capture d'une propriété est implémentée dans la classe abstraite Unit
. La
méthode Unit#attack
permet de faire
baisser la défense d'une propriété ennemie, et de changer son propriétaire vers le joueur courant si sa vie descend en
dessous de 0.
Nous avons cependant choisi de permettre à la capture d'être effectuée par plusieurs unités différentes, ainsi que de
faire regagner 5 points de santé par tour à la propriété, plutôt que 20 d'un seul coup.
Les propriétés sont représentées par la classe abstraite Property
. Cependant, il
peut y avoir plus de 2 QG, pour
faire des parties jusqu'à 5 joueurs, voir Bonus | Choix d'ajouts. Un joueur qui capture
un QG en devient ainsi le
propriétaire. De ce fait, un joueur est considéré comme éliminé s'il n'a plus aucun QG disponible.
Pour implémenter les usines, nous avons créé une classe abstraite Factory
, qui
étend Property
. Ainsi, nous pouvons
avoir des terrains qui sont des usines (peuvent produire des unités) mais également des propriétés (peuvent être
possédées par
un joueur).
Puis, nous avons créé le type de fr.istic.terrain FactoryTerrain
, représentant
une
usine terrestre. (En anticipation des ports
et des aéroports, voir Bonus | Choix d'ajouts.)
Pour les crédits, nous avons ajouté 1000 crédits à chaque joueur pour chaque propriété qu'il possède, à chaque fois que tous les joueurs de la partie ont joué leur tour (passage au jour suivant).
Pour le parseur de carte, nous avons décidé d'apporter quelques modifications par rapport au sujet. En effet, nous avons
modifié dans un premier temps la syntaxe ASCII pour inclure la possibilité d'ajouter des variations de textures.
La création de la carte se fait à partir de deux fichiers textes, un fichier de carte carte.adwcmap
qui contient les
données du plateau de jeu (de la grille)
au format ASCII et un fichier de métadonnées carte.meta
qui contient les données concernant la fr.istic.map (taille, nom,
nombre de joueurs, etc...).
Afin d'implémentation des variations de textures Changement | Texture, il a fallu créer un nouveau
parseur pour la fr.istic.map MapParser
qui s'occupe de transformer le fichier de la fr.istic.map,
en MapParser
. Ainsi, nous avons dans le fichier de carte :
- Ligne impaire : information de l'unité sur la case (format:
[caractère unité;propriétaire]
) - Ligne paire : information du fr.istic.terrain (format:
{caractère fr.istic.terrain;variation texture;propriétaire}
)
Concernant les déplacements, nous avions dans un premier temps implémenté un système de flèche qui se basait sur le système complet indiqué dans le sujet. Par la suite, voyant le projet évoluer, nous avons décidé d'opter pour un nouveau système de déplacement qui ne permettrait plus les nœuds, et qui choisirait (comme dans la version officielle du jeu) automatiquement le chemin le plus court selon les coûts de déplacement de chaque fr.istic.terrain, les cases inaccessibles, etc. Pour ce faire, nous avons utilisé l'algorithme Dijkstra pour trouver le chemin le plus court entre deux cases. Pour cet algorithme, nous nous sommes basés sur l'implémentation connue du site Rosetta Code. En se basant sur l'algorithme présenté, nous avons créé une version adaptée au projet.
Nous avons réalisé le bonus de la météo. Pour cela, nous avons créé dans un premier temps une énumération des météos
possibles Weather
.
La classe WeatherManager
permet les transitions entre les météos de manière
fluide. Les changements de météo peuvent être aléatoires ou statiques
selon les paramètres sélectionnés en début de partie. En mode aléatoire, la météo peut changer à chaque tour avec une
probabilité de 30%, tout en ayant prévenu le joueur
un tour en avance. Pour éviter les transitions trop brutales,
le WeatherManager
détermine la météo suivante en fonction de la météo
actuelle avec des
probabilités variables.
Pour l'implémentation des unités navales, nous avons créé une nouvelle classe
abstraite Naval
, qui étend Unit
.
Pour gérer les déplacements de ces nouvelles unités, nous avons simplement ajouté
l'énumération UnitMovementCost.Naval
,
contenant le coût de mouvement pour les unités navales.
Nous avons décidé d'ajouter des menus au jeu pour le rendre plus intuitif et interactif. Pour cela nous avons une classe
abstraite Menu
qui donne les directives d'implémentation des menus.
Un fr.istic.menu en bas de l'écran permet également de donner des indications sur le gameplay.
- Vie de l'unité
- Energie de l'unité
- Munitions arme secondaire
- Munitions arme principale
- Couverture du fr.istic.terrain
- Argent du joueur courant
- Icone du joueur courant
Afin d'animer les textures du jeu, il a été nécessaire de paralléliser le jeu en deux parties : la boucle d'écoute des touches et la boucle d'affichage.
La première thread permet l'écoute asynchrone des touches tout en passant les frappes de clavier à la
méthode ActionHandler#handle
La deuxième thread (GameLoop
) s'occupe de l'affichage du jeu.
- Touches pour lister les unités encore utilisables
- Affichage des déplacements et attaques possibles d'une unité
- Armes multiples
- Attaques à distance
- Artillerie
- Mortier
- Lance-missile sol-air
- Ravitaillement et réparations
- Transport d'unités à pied
- Fin de tour automatique
- Couverture de fr.istic.terrain
- Unités navales
- Croiseur
- Corvette
- Barge
- Cuirasser
- Porte-avion
- Sous-marin
- Brouillard de guerre
- Basique
- Avancé
- Météo
- Refonte complète des textures du jeu
- Textures des unités
- Textures des bâtiments
- Textures du fr.istic.terrain
- Changement des textures du fr.istic.terrain en fonction de la météo/du brouillard de guerre
- Animation des éléments du jeu
- Redesign des popups
- Ajouts de menus en tous genres (écran d'accueil, sélection de cartes, fr.istic.menu pause...)
- Ajout d'une nouvelle arme : le missile anti-navire. Utilisé par les croiseurs, il permet d'infliger énormément de dégâts aux autres navires.
- Le chemin le plus court vers une destination est maintenant automatiquement calculé à l'aide d'un algorithme de pathfinding de type Dijkstra
Concernant les textures, nous avons décidé de changer les textures fournies avec le squelette du projet car nous préférions les graphismes du jeu Advance Wars II : Black Hole Rising. Nous avons donc réorganisé les textures dans le dossier textures. Les textures sont tirées du site Spriters Resource. La partie texture du projet étant secondaire, nous avons fait appel à une aide extérieure (voir Crédits) qui nous a permis d'extraire l'ensemble des textures et de les organiser. L'ensemble des textures utilisées sont libres de droit pour tout projet à but non lucratif. Pour plus d'informations, voir directement sur le site : FAQ Copyright Spriters Ressource
Nous avons ajouté quelques fr.istic.map supplémentaires au jeu. Pour cela, nous avons utilisé un outil de création de fr.istic.map
(Tiled
) qui permet de créer des maps à partir de tuiles. Il permet d'exporter les maps
sous forme d'un fichier CSV, que nous avons
ensuite converti en fichier .awdcmap
à l'aide d'un script python.
Quelques images du logiciel :
Il s'agit ici d'un projet qui est difficile à tester. La plupart des méthodes étant lié plus ou moins à l'affichage, il
nous est difficile
de les tester. Cependant, certaines classes/méthodes ont le droit à quelques tests unitaires. Les tests sont disponibles
dans le dossier
src/test
du projet.
- maYayoh@github / maYayoh@gitea: Extraction complète des textures de Spriters Resource et création de quelques textures supplémentaires et l'apport de maps supplémentaires.