Introduction à la conception du jeu
Ce document explore la conception technique d'un petit jeu d'action 2D nommé "Le Héros et ses Quêtes", développé avec les technologies Java Swing et AWT. Le jeu simule l'aventure d'un héros combattant des monstres, intégrant des mécaniques de déplacement, de combat, de gestion d'état et de détection de victoire ou de défaite. Les fonctionnalités clés reposent sur l'écoute d'événements clavier pour les interactions joueur, des algorithmes de détection de collision pour les interactions entre entités, et l'utilisation de minuteurs (Timer) pour une mise à jour dynamique du jeu et un rafraîchissement fluide de l'interface graphique.
Fonctionnalités principales du système
Le jeu intègre un ensemble de fonctionnalités essentielles pour offrir une expérience interactive complète :
- Déplacement du personnage principal : Le joueur peut contrôler le héros pour se déplacer horizontalement, sauter et effectuer un double saut. Des contrôles fluides et une détection des limites de l'écran sont implémentés.
- Système de compétences : Le héros dispose de capacités offensives. Une première compétence (20 points de dégâts) est disponible dès le début, et une seconde compétence plus puissante (40 points de dégâts) se débloque après avoir vaincu un monstre.
- Gestion de l'état du héros : Les attributs tels que la santé, le niveau et le nombre de monstres vaincus sont mis à jour en temps réel et affichés via une barre de vie visuelle. Ces états influencent le déblocage de nouvelles compétences.
- Initialisation et comportement des monstres : Trois monstres sont générés aléatoirement et répartis sur la carte. Ils se déplacent de manière imprévisible avec des contraintes de limites d'écran.
- Détection des interactions : Une mécanique de détection de collision basée sur des boîtes englobantes rectangulaires gère les interactions entre le héros et les monstres, ainsi qu'entre le héros et les potions de vie. Les monstres attaquent le héros 0,5 seconde après une collision.
- Loot de potions de vie : À la mort d'un monstre, une potion de vie apparaît à proximité de sa position, offrant une régénération de 30 points de vie au héros. Les potions sont rendues visibles à l'écran.
- Gestion de l'état des monstres : La santé, le statut de vie et l'état d'attaque des monstres sont suivis. Un monstre décédé cesse tout mouvement et attaque.
- Récupération de vie : Le héros peut ramasser des potions de vie en entrant en collision avec elles, récupérant 30 points de vie sans dépasser son maximum de 100. Une potion ramassée devient inactive.
- Conditions de fin de partie : La victoire est déclarée lorsque tous les monstres sont vaincus. La défaite survient si la santé du héros atteint zéro. Un bouton de redémarrage est disponible après une défaite.
- Configuration de l'interface : L'arrière-plan s'adapte à la taille de la fenêtre. Des indicateurs de statut (niveau, santé, éliminations) et des barres de vie pour le héros et les monstres sont affichés en surimpression.
Architecture Orientée Objet
La conception du jeu repose sur une architecture orientée objet pour garantir modularité et maintenabilité. Les relations entre les principales classes sont définies comme suit :
GameLauncher: Cette classe sert de point d'entrée pour l'application. Elle intsancie et configure la fenêtre principale (JFrame) et y intègre le panneau de jeu (GamePanel).GamePanel: Héritant deJPanel, cette classe est le cœur visuel et logique du jeu. Elle est responsable de l'initialisation de tous les objets du jeu (le héros, les monstres, les potions), de la gestion des interactions logiques (déplacements, attaques, ramassage) et du rendu graphique de tous les éléments.Hero,Monster,BloodBottle: Ces classes représentent les entités principales du jeu.- Le
GamePaneldépend de ces classes pour créer, gérer et dessiner les objets correspondants. - Les classes
HeroetMonsterinteragissent via une méthode de détection de collision pour gérer les dégâts mutuels. - La classe
BloodBottleinteragit avec la classeHeropour le ramassage et la régénération de vie.
- Le
Mécaniques de jeu détaillées
1. Le Héros : Mouvement, Saut et Compétences
1.1. Mouvement Horizontal
Le contrôle des déplacements horizontaux repose sur le suivi de l'état des touches pressées. Des variables booléennes (deplacementVersGaucheActif, deplacementVersDroiteActif) enregistrent si le joueur maintient une direction. Les déplacements sont mutuellement exclusifs pour éviter les conflits d'entrée.
public void definirDeplacementGauche(boolean actif) {
this.deplacementVersGaucheActif = actif;
if (actif) this.deplacementVersDroiteActif = false;
}
public void definirDeplacementDroite(boolean actif) {
this.deplacementVersDroiteActif = actif;
if (actif) this.deplacementVersGaucheActif = false;
}
La position du héros est mise à jour à chaque trame de jeu selon le pas de déplacement et est bornée par les limites de la fenêtre de jeu.
public void actualiserPositionHorizontale(int largeurPanneau) {
if (deplacementVersGaucheActif) {
posX -= pasDeplacement;
posX = Math.max(0, posX); // Ne pas sortir à gauche
} else if (deplacementVersDroiteActif) {
posX += pasDeplacement;
posX = Math.min(largeurPanneau - tailleEntite, posX); // Ne pas sortir à droite
}
}
1.2. Mécanisme de Saut
Le héros peut effectuer un saut initial et un double saut en l'air. Une vitesse verticale (vitesseVerticale) est appliquée, puis une constante de gravité est progressivement ajoutée pour simuler une trajectoire naturelle de chute.
public void initierSaut() {
if (!estEnSaut) { // Premier saut (depuis le sol)
vitesseVerticale = -16; // Impulsion initiale vers le haut
estEnSaut = true;
peutDoubleSauter = true;
} else if (peutDoubleSauter) { // Second saut (en l'air)
vitesseVerticale = -16;
peutDoubleSauter = false;
}
}
L'état du saut est mis à jour à chaque cycle de jeu, en appliquant la gravité et en détectant le retour au sol.
public void actualiserEtatSaut(int niveauSol) {
if (estEnSaut) {
posY += vitesseVerticale;
vitesseVerticale += GRAVITE; // Augmente la vitesse de chute
if (posY + tailleEntite >= niveauSol) { // Détection d'atterrissage
posY = niveauSol - tailleEntite; // Positionne précisément au sol
vitesseVerticale = 0;
estEnSaut = false;
peutDoubleSauter = false;
}
}
}
1.3. Lancement des Compétences
Le héros dispose de deux compétences :
- Compétence 1 (touche Z) : Inflige 20 points de dégâts. Elle est disponible dès le début du jeu.
- Compétence 2 (touche X) : Inflige 40 points de dégâts. Elle est débloquée après avoir vaincu au moins un monstre. Un message informatif s'affiche si la compétence est tentée avant d'être débloquée.
2. Les Monstres : Mouvement, Attaque et Collisions
2.1. Déplacement Aléatoire des Monstres
Les monstres qui sont vivants et non en train d'attaqure se déplacent de manière aléatoire vers la gauche ou la droite à chaque trame. Leur mouvement est également contraint par les bords de l'écran.
import java.util.List;
import java.util.Random;
// Dans la boucle de jeu de GamePanel par exemple
private void mettreAJourMouvementsMonstres(List<Monster> listeMonstres, int largeurPanneau) {
Random r = new Random();
int pasDeplacementMonstre = 4;
for (Monster m : listeMonstres) {
if (m.estVivant() && !m.estEnAttaque()) {
int direction = r.nextInt(2); // 0 pour gauche, 1 pour droite
if (direction == 0) {
m.setPositionX(Math.max(0, m.getPositionX() - pasDeplacementMonstre));
} else {
m.setPositionX(Math.min(largeurPanneau - m.getTaille(), m.getPositionX() + pasDeplacementMonstre));
}
}
}
}
2.2. Détection de Collisions (AABB)
La détection de collision utilise la technique des boîtes englobantes alignées sur les axes (AABB), implémentée via la classe java.awt.Rectangle. Chaque entité (héros, monstre, potion) est modélisée comme un rectangle, et la méthode intersects() est utilisée pour vérifier les superpositions.
import java.awt.Rectangle;
public boolean detecterCollisionAvec(Hero heros) {
if (!estVivant) return false; // Un monstre mort ne peut pas entrer en collision
Rectangle rectMonstre = new Rectangle(this.posX, this.posY, this.tailleEntite, this.tailleEntite);
Rectangle rectHeros = new Rectangle(heros.getPosX(), heros.getPosY(), heros.getTaille(), heros.getTaille());
return rectMonstre.intersects(rectHeros);
}
Un mécanisme similaire est utilisé pour détecter si le héros ramasse une potion.
2.3. Comportement d'Attaque des Monstres
Lorsqu'un monstre entre en collision avec le héros, il passe en état d'attaque. Un minuteur interne au monstre déclenche des dégâts (15 points) au héros toutes les 0,5 secondes tant que la collision persiste.
3. Panneau de Jeu et Rendu Graphique
3.1. Construction du Panneau de Jeu
La classe GamePanel étend JPanel. Elle est configurée pour adapter la taille de l'image de fond, acquérir le focus pour écouter les événements clavier et utiliser une disposition absolue pour un positionnement précis des composants (comme le bouton de redémarrage). L'initialisation inclut le héros, les monstres, les potions, le gestionnaire d'événements clavier et le minuteur de jeu.
3.2. Méthode de Rendu (paintComponent)
La méthode paintComponent est surchargée pour gérer le rendu de tous les éléments du jeu dans un ordre spécifique afin d'éviter les problèmes de chevauchement :
- Arrière-plan du jeu.
- Objets interactifs (potions de vie).
- Monstres.
- Héros.
- Barres de vie des personnages.
- Messages d'information et d'état (conseils de compétences, score, etc.).
Pour le rendu des personnages, des images sont chargées par défaut. En cas d'échec de chargement, des formes colorées de remplacement (carré bleu pour le héros, carré rouge pour les monstres) sont utilisées. Les barres de vie sont dessinées comme deux rectangles superposés, le rectangle supérieur ajustant sa largeur en fonction de la santé actuelle.
Lorsqu'une condition de fin de partie est remplie (victoire ou défaite), un voile semi-transparent est dessiné sur l'écran, affichant le résultat de manière centrale. En cas de défaite, un message invitant à redémarrer est également affiché.
4. Boucle de Jeu et Gestion des États
4.1. Le Cycle de Jeu (Game Loop)
La boucle de jeu est orchestrée par un javax.swing.Timer, réglé pour un rafraîchissement à 60 images par seconde (environ toutes les 16 millisecondes). Chaque cycle exécute les opérations suivantes dans un ordre précis :
- Mise à jour des positions et états de saut du héros.
- Mouvement aléatoire des monstres.
- Détection de toutes les collisions (héros/monstres, héros/potions).
- Application des effets de collision (dégâts, régénération de vie, apparition de potions).
- Vérification des conditions de victoire ou de défaite.
- Redessin de tous les éléments à l'écran via
repaint().
4.2. Contrôle Global des États du Jeu
Des drapeaux globaux comme partieTerminee et partieGagnee sont utilisés pour gérer l'état général du jeu. Toutes les logiques de jeu principales (mouvements, attaques, collecte) vérifient ces drapeaux et s'interrompent si le jeu est terminé. Cela empêche les interactions indésirables après la fin de la partie.
En cas de redémarrage du jeu, tous les objets et états sont entièrement réinitialisés : une nouvelle liste de monstres est créée, le héros retrouve sa santé et son niveau initiaux, et toutes les potions sont effacées. Cette réinitialisation complète assure que chaque nouvelle partie commence sans aucun résidu des parties précédentes.