From 86383155cdf7bb792d29101e4d37167e0a4069eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20GUEZO?= Date: Fri, 19 Dec 2025 18:46:27 +0100 Subject: [PATCH] feat(Game): ajout commentaire et ajout fonction setup --- src/model/Game.java | 245 ++++++++++++++++++++++++++++---- src/model/car/BasicCar.java | 124 ++++++++-------- src/model/car/CarDecorator.java | 9 +- src/visual/GameView.java | 7 +- src/visual/RankboardView.java | 7 +- 5 files changed, 303 insertions(+), 89 deletions(-) diff --git a/src/model/Game.java b/src/model/Game.java index c37c2bd..22c916c 100644 --- a/src/model/Game.java +++ b/src/model/Game.java @@ -2,75 +2,188 @@ package model; import java.util.ArrayList; import java.util.List; -import java.util.function.Consumer; import model.car.Car; import model.map.Map; import visual.*; +/** + * {@code Game} représente le cœur du moteur de jeu. + */ public class Game { - public static interface Observer extends Consumer { + /** + * {@code Observer} représente une entité réagissant au déroulement + * du jeu : voiture, vue graphique, tableau de scores, etc. + * + *

+ * Les fonctions disponible dans l'interface sont les suivantes: + *

+ *

+ */ + public static interface Observer { /** + * Méthode appelée à chaque tick du jeu. * - * @return si False le programme s'arrete, sinon il continue + * @return {@code true} si le jeu doit continuer, + * {@code false} si le jeu doit s'arrêter */ public boolean apply(); + + /** + * Méthode appelée lors de la création du jeu. Très + * utile si on veut récupérer des informations pas + * encore initialisée. + * + * @param game l'instance du jeu associée à cet observer + */ + public void setup(Game game); + + /** + * Méthode appelée lorsque le jeu se termine. Utile + * comme Destructor de classe ou pour information de + * fin. + */ + public void end(); } + /** + * {@code Builder} est responsable de la construction contrôlée + * d'une instance de {@link Game}. + *

+ * Il permet de configurer l'ensemble des éléments du jeu avant son lancement : + *

+ *

+ */ public static class Builder { + /** + * {@code DashboardConfig} encapsule les paramètres communs + * nécessaires à la création automatique de plusieurs dashboards. + *

+ */ private static record DashboardConfig(int width, int height, int x, int y) { + /** + * Initialise un dashboard pour une voiture donnée. + * + * @param builder le builder utilisé pour ajouter la vue + * @param car la voiture associée au dashboard + * @param index l'indice de la voiture (utilisé pour le décalage vertical) + */ public void initDashboard(Builder builder, Car car, int index) { - builder.dashboard(car, car.getName(), width, height, x, y + (height * index)); + builder.dashboard( + car, + car.getName(), + width, height, + x, y + (height * index)); } } + /** Liste des voitures participant à la partie */ private final List cars = new ArrayList<>(); + + /** Liste des vues graphiques observant le jeu */ private final List views = new ArrayList<>(); + /** Configuration globale des dashboards automatiques */ private DashboardConfig dashboardConfig = null; + + /** Temps (en millisecondes) entre deux ticks du jeu */ private int time = 500; + + /** La classe Map */ private Map map = null; + /** + * Ajoute une voiture au jeu. + * + * @param car la voiture à ajouter + * @return le builder courant (chaînage fluide) + */ public Builder car(Car car) { cars.add(car); return this; } + /** + * Définit la carte du jeu. + * + * @param map la carte du circuit + * @return le builder courant + */ public Builder map(Map map) { this.map = map; return this; } + /** + * Définit le temps entre chaque tick. + * + * @param time durée en millisecondes + * @return le builder courant + */ public Builder time(int time) { this.time = time; return this; } + /** + * Ajoute une vue de classement. + */ public Builder rankboard(String title, int width, int height, int x, int y) { views.add(new RankboardView(null, title, width, height, x, y)); return this; } + /** + * Ajoute la vue principale du circuit. + */ public Builder track(String title, int width, int height, int x, int y) { views.add(new TrackView(null, title, width, height, x, y)); return this; } + /** + * Ajoute un dashboard lié à une voiture. + */ public Builder dashboard(Car car, String title, int width, int height, int x, int y) { views.add(new DashboardView(null, car, title, width, height, x, y)); return this; } + /** + * Configure la création automatique d'un dashboard par voiture. + */ public Builder dashboards(int width, int height, int x, int y) { dashboardConfig = new DashboardConfig(width, height, x, y); return this; } + /** + * Construit et initialise le jeu. + *

+ * Cette méthode : + *

    + *
  1. crée automatiquement les dashboards si configurés
  2. + *
  3. regroupe toutes les voitures et vues comme observateurs
  4. + *
  5. instancie le {@link Game}
  6. + *
  7. appelle {@link Game.Observer#setup(Game)} sur chaque observateur
  8. + *
+ *

+ * + * @return une instance de {@link Game} prête à être lancée + */ public Game build() { if (dashboardConfig != null) { - int index = 0; - for (Car car : new ArrayList<>(cars)) { - dashboardConfig.initDashboard(this, car, index++); + for (int i = 0; i < cars.size(); i++) { + dashboardConfig.initDashboard(this, cars.get(i), i); } } @@ -81,78 +194,143 @@ public class Game { Game game = new Game(map, time, observers); for (Game.Observer obs : new ArrayList<>(observers)) { - obs.accept(game); + obs.setup(game); } return game; } } + /** Carte du jeu (circuit, environnement, etc.) */ private Map map; + + /** Temps (en millisecondes) entre deux ticks du moteur */ private int time; + + /** Liste des observateurs du jeu (voitures, vues, tableaux, etc.) */ private List observers; + /** Indique si le jeu est actuellement en pause */ private boolean isPaused; - private Game() { - } - + /** + * Constructeur principal du moteur de jeu. + * + * @param map la carte du jeu + * @param time le temps entre chaque tick + * @param observer la liste des observateurs initialisés + */ private Game(Map map, int time, List observer) { this.map = map; this.time = time; this.observers = observer; } + /** + * Ajoute dynamiquement un observateur au jeu. + * + * @param o l'observateur à ajouter + * @return l'instance courante du jeu + */ public Game addObserver(Observer o) { observers.add(o); return this; } + /** + * Supprime un observateur du jeu. + * + * @param o l'observateur à retirer + * @return l'instance courante du jeu + */ public Game removeObserver(Observer o) { observers.remove(o); return this; } - private boolean isFinish() { + /** + * Détermine si la partie est terminée. + *

+ * La partie est considérée comme finie lorsque + * toutes les voitures n'ont plus de carburant. + * + * @return {@code true} si la partie est terminée + */ + private boolean hasEnoughFuel() { for (Game.Observer observer : observers) { - switch (observer) { - case Car car -> { - if (car.getFuel() > 0) - return false; - } - default -> { - } + if (observer instanceof Car car && car.getFuel() > 0) { + return true; } } + return false; + } + /** + * Notifie tous les observers pour un tick. + * + * @return {@code true} si le jeu peut continuer + */ + public boolean notifyObservers() { + for (Observer o : observers) { + if (!o.apply()) { + return false; + } + } return true; } - public void notifyObservers() { - for (Observer o : observers) { - if (!o.apply()) { - System.exit(0); - } - } + /** + * Indique si la partie est terminée. + * + * @return {@code true} si le jeu est terminé + */ + // DOIT ETRE MODIFIÉE SI AJOUT CONDITION DE FIN + private boolean isGameOver() { + return !(hasEnoughFuel()); } + /** + * Notifie tous les observers pour la fin de partie. + */ + public void notifyEnd() { + for (Observer o : observers) { + o.end(); + } + System.exit(0); + } + + /** + * Lance la boucle principale du moteur de jeu. + *

+ * La boucle s'exécute tant que : + *

    + *
  • la partie n'est pas terminée
  • + *
  • aucun observateur ne demande l'arrêt
  • + *
+ * + * La boucle respecte également l'état de pause. + */ public void run() { try { - while (!isFinish()) { + while (isGameOver() && notifyObservers()) { synchronized (this) { while (isPaused) wait(); } - notifyObservers(); Thread.sleep(time); } } catch (InterruptedException e) { e.printStackTrace(); System.exit(1); } - + notifyEnd(); } + /** + * Active ou désactive la pause du jeu. + * + * @return l'état de pause après modification + */ public synchronized boolean togglePause() { if (isPaused) notifyAll(); @@ -160,6 +338,11 @@ public class Game { return isPaused; } + /** + * Retourne la liste des voitures participant au jeu. + * + * @return une liste de {@link Car} + */ public List getCars() { return observers.stream() .filter(o -> o instanceof Car) @@ -167,10 +350,16 @@ public class Game { .toList(); } + /** + * Retourne la carte du jeu. + */ public Map getMap() { return map; } + /** + * Indique si le jeu est actuellement en pause. + */ public boolean getPause() { return isPaused; } diff --git a/src/model/car/BasicCar.java b/src/model/car/BasicCar.java index 6cada1f..b88f407 100644 --- a/src/model/car/BasicCar.java +++ b/src/model/car/BasicCar.java @@ -123,7 +123,7 @@ public class BasicCar implements Car { state = next; return ""; } - + /** * Fait avancer la voiture d'un certain nombre de positions. *

@@ -131,78 +131,78 @@ public class BasicCar implements Car { * incrémenté et * la position revient à zéro. *

- * - * @param move nombre de positions à avancer - * @return cette même instance (pour chaînage fluide) - */ - private void move() { - int jump = RANDOM.nextInt(state.MIN, state.MAX); - - for (int i = 0; i < jump; i++) { - pos = state.move(pos, movement); - - Point point = map.getPath(pos); - Circuit element = map.getElement(point.x, point.y); - - if (hasAccident(element, jump)) { - setDamage(); - return; + * + * @param move nombre de positions à avancer + * @return cette même instance (pour chaînage fluide) + */ + private void move() { + int jump = RANDOM.nextInt(state.MIN, state.MAX); + + for (int i = 0; i < jump; i++) { + pos = state.move(pos, movement); + + Point point = map.getPath(pos); + Circuit element = map.getElement(point.x, point.y); + + if (hasAccident(element, jump)) { + setDamage(); + return; } round = pos / map.getPathSize(); } } - + private boolean hasAccident(Circuit element, int jump) { return element.isYRoad() && element.getValue() <= jump; } - + /** * Consomme du carburant en fonction de l'état du jeu. - * - * @return cette même instance pour chaînage - */ - public void consumeFuel() { - fuel = state.fuelConsumption(fuel); - if (fuel < 0) - fuel = 0; // sécurité -} - -public boolean hasFinished() { - return 3 < round; -} - -/** - * Exécute une "étape" de la voiture : avance d'une position aléatoire et - * consomme du carburant. - *

- * La progression est déterminée par un intervalle aléatoire fourni par l'état - * du jeu. - *

-*/ -@Override -public boolean apply() { - if (state.isDamaged()) { - decreaseDamage(); - } else if (fuel > 0) { - move(); - if (isConsuming) - consumeFuel(); + * + * @return cette même instance pour chaînage + */ + public void consumeFuel() { + fuel = state.fuelConsumption(fuel); + if (fuel < 0) + fuel = 0; // sécurité } - return !hasFinished(); -} -@Override -public void consumption(boolean active) { - isConsuming = active; -} + public boolean finished() { + return 3 < round; + } + + /** + * Exécute une "étape" de la voiture : avance d'une position aléatoire et + * consomme du carburant. + *

+ * La progression est déterminée par un intervalle aléatoire fourni par l'état + * du jeu. + *

+ */ + @Override + public boolean apply() { + if (state.isDamaged()) { + decreaseDamage(); + } else if (fuel > 0) { + move(); + if (isConsuming) + consumeFuel(); + } + return !finished(); + } + + @Override + public void consumption(boolean active) { + isConsuming = active; + } @Override public Car remove() { return this; } -@Override -public void reverse(boolean active) { + @Override + public void reverse(boolean active) { movement = (active) ? -1 : 1; } @@ -255,7 +255,17 @@ public void reverse(boolean active) { } @Override - public void accept(Game game) { + public void setup(Game game) { this.map = game.getMap(); } + + @Override + public String toString() { + return "nom: " + NAME + " score: " + getScore(); + } + + @Override + public void end() { + System.out.println(this); + } } diff --git a/src/model/car/CarDecorator.java b/src/model/car/CarDecorator.java index ea985a5..f72cd26 100644 --- a/src/model/car/CarDecorator.java +++ b/src/model/car/CarDecorator.java @@ -77,7 +77,12 @@ public abstract class CarDecorator implements Car { } @Override - public void accept(Game game) { - car.accept(game); + public void setup(Game game) { + car.setup(game); + } + + @Override + public void end() { + car.end(); } } \ No newline at end of file diff --git a/src/visual/GameView.java b/src/visual/GameView.java index 3156c51..edada9f 100644 --- a/src/visual/GameView.java +++ b/src/visual/GameView.java @@ -32,7 +32,7 @@ public abstract class GameView extends JComponent implements Game.Observer { } } - public void accept(Game game) { + public void setup(Game game) { this.game = game; init(game); } @@ -85,4 +85,9 @@ public abstract class GameView extends JComponent implements Game.Observer { public boolean apply() { return (game != null); } + + @Override + public void end() { + frame.dispose(); + } } \ No newline at end of file diff --git a/src/visual/RankboardView.java b/src/visual/RankboardView.java index ab7a426..bfe5ae8 100644 --- a/src/visual/RankboardView.java +++ b/src/visual/RankboardView.java @@ -57,7 +57,8 @@ public class RankboardView extends GameView { *

*/ private void updateRankText() { - if (cars == null) return; + if (cars == null) + return; // cloner pour de modifier la classe principale List cars_clone = new ArrayList<>(cars); cars_clone.sort(Comparator.comparingInt(Car::getScore).reversed()); @@ -84,4 +85,8 @@ public class RankboardView extends GameView { updateRankText(); return true; } + + @Override + public void end() { + } }