diff --git a/src/Main.java b/src/Main.java
index 16c3a43..b4c05c6 100644
--- a/src/Main.java
+++ b/src/Main.java
@@ -1,12 +1,34 @@
+import java.awt.Color;
import java.util.List;
import model.Game;
+import model.car.BasicCar;
+import model.car.DrunkCar;
import model.map.Map;
public class Main {
public static void main(String[] args) throws InterruptedException {
- Map map = Game.GameFactory.defaultMap();
- Game game = Game.GameFactory.defaultGame(map);
+ Map map = Map.fromInts(new Integer[][] {
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 5, 0 },
+ { 0, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 0, 0, -1, 0, 0, -1, 0 },
+ { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0 },
+ { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0 },
+ { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 2, 0, 0, -1, 0 },
+ { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0 },
+ { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0 },
+ { 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -3, 0 },
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
+ });
+
+ Game game = new Game.Builder()
+ .car(new BasicCar("Luwik", Color.RED))
+ .car(new DrunkCar(new BasicCar("Charazade", Color.PINK)))
+ .track("Piste Formule 1", 1000, 500, 1, 1)
+ .rankboard("Score", 200, 200, 0, 510)
+ .dashboards(300, 200, 1000, 0)
+ .map(map)
+ .build();
game.run();
}
}
\ No newline at end of file
diff --git a/src/model/Game.java b/src/model/Game.java
index 3fafb5f..a0e109f 100644
--- a/src/model/Game.java
+++ b/src/model/Game.java
@@ -1,285 +1,160 @@
package model;
-import java.awt.Color;
import java.util.ArrayList;
+import java.util.List;
import model.car.Car;
import model.map.Map;
+import visual.*;
-/**
- * La classe {@link Game} représente le moteur principal du jeu.
- *
- * Elle contient le modèle (les voitures, l'état du jeu, la carte),
- * la vue (Track, Dashboard, Rankboard) et la logique de contrôle
- * (pause, boucle de jeu, observateurs).
- *
- */
public class Game {
@FunctionalInterface
- /**
- * L'interface utilisée pour Game.
- */
public static interface Observer {
/**
*
- * @return true si la fonction s'est bien passé sinon false (le programme va se
- * stopper)
+ * @return si False le programme s'arrete, sinon il continue
*/
public boolean apply();
}
- /**
- * {@link VisualInfo} est un enregistrement (record) qui décrit une vue
- * graphique
- * à afficher dans le jeu (par exemple un tableau de bord, une piste ou un
- * classement).
- *
- * Chaque instance contient toutes les informations nécessaires pour créer et
- * positionner
- * cette vue à l’écran.
- *
- *
- * @param type le type concret de la vue (classe héritant de {@link Game})
- * @param title le titre de la fenêtre ou du panneau associé
- * @param width la largeur en pixels de la vue
- * @param height la hauteur en pixels de la vue
- * @param x la position horizontale (en pixels) de la vue sur l’écran
- * @param y la position verticale (en pixels) de la vue sur l’écran
- */
- private record VisualInfo(Class extends Game> type,
- String title, int width, int height, int x, int y) {
- }
-
- public static class GameFactory {
- public static Map defaultMap() {
- return Map.fromInts(new Integer[][] {
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 5, 0 },
- { 0, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 2, 0, 0, -1, 0, 0, -1, 0 },
- { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0 },
- { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0 },
- { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -1, -1, 2, 0, 0, -1, 0 },
- { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0 },
- { 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0 },
- { 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -3, 0 },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
- });
- }
-
- public static Game defaultGame(Map map) {
- return new Game.Builder()
- .addCar("Voiture à LUWIK", Color.BLUE)
- .addCar("Voiture à CHARAZADE", Color.PINK)
- .addCar("Voiture de UPEC", Color.RED)
- .addVisual(Dashboard.class, "Voiture à LUWIK", 300, 200, 1000, 0)
- .addVisual(Dashboard.class, "Voiture à CHARAZADE", 300, 200, 1000, 200)
- .addVisual(Dashboard.class, "Voiture de UPEC", 300, 200, 1000, 400)
- .addVisual(Track.class, "Piste Formule 1", 1000, 500, 1, 1)
- .addVisual(Rankboard.class, "Score", 200, 200, 0, 510)
- .setTime(1000)
- .setMap(map)
- .build();
- }
- }
-
- /**
- * Builder pour créer une instance de {@link Game} de façon fluide.
- *
- * Permet d'ajouter des voitures, de définir la carte, l'état initial et
- * le temps entre les étapes du jeu avant de construire l'objet final.
- *
- */
public static class Builder {
- /** Liste des voitures à créer pour le jeu */
- private ArrayList cars = new ArrayList<>();
- /** Liste des voitures à créer pour le jeu */
- private ArrayList visuals = new ArrayList<>();
- /** État initial du jeu */
- private Car.State state = Car.State.NORMAL;
- /** Temps entre chaque step du jeu */
- private int time = 1000;
- /** Carte sur laquelle se déroule le jeu */
+ private final List OBSERVERS = new ArrayList<>();
+ private int time = 500;
private Map map = null;
- /** Ajoute une voiture à la liste */
- public Builder addCar(String name, Color color) {
- cars.add(new CarInfo(name, color));
+ public Builder car(Car car) {
+ this.OBSERVERS.add(car);
return this;
}
- /** Supprime une voiture de la liste */
- public Builder removeCar(String name, Color color) {
- cars.forEach((car) -> {
- if (car.name == name && car.color == color)
- cars.remove(car);
- });
- return this;
- }
-
- /** Définit la carte du jeu */
- public Builder setMap(Map map) {
+ public Builder map(Map map) {
this.map = map;
return this;
}
- /** Définit l'état initial du jeu */
- public Builder setState(Car.State s) {
- this.state = s;
- return this;
- }
-
- /** Définit le temps entre chaque étape du jeu */
- public Builder setTime(int time) {
+ public Builder time(int time) {
this.time = time;
return this;
}
- public Builder addVisual(Class extends Game> type, String title,
- int width, int height, int x, int y) {
- visuals.add(new VisualInfo(type, title, width, height, x, y));
+ public Builder rankboard(String title, int width,
+ int height, int x, int y) {
+ this.OBSERVERS.add(new Rankboard(null, title, width, height, x, y));
return this;
}
- private void buildVisual(Game game) {
- for (VisualInfo visual : visuals) {
- Game view = null;
-
- if (visual.type == Rankboard.class) {
- view = new Rankboard(game, visual.title, visual.width,
- visual.height, visual.x, visual.y);
- } else if (visual.type == Track.class) {
- view = new Track(game, visual.title, visual.width,
- visual.height, visual.x, visual.y);
- } else if (visual.type == Dashboard.class) {
- Car car = game.getCars().stream()
- .filter((e) -> visual.title.equals(e.getName()))
- .findFirst()
- .orElseThrow();
-
- view = new Dashboard(game,
- car,
- visual.title, visual.width,
- visual.height, visual.x, visual.y);
- }
- if (view != null)
- game.addObserver(view);
- }
+ public Builder track(String title, int width,
+ int height, int x, int y) {
+ this.OBSERVERS.add(new Track(null, title, width, height, x, y));
+ return this;
+ }
+
+ public Builder dashboard(Car car, String title, int width,
+ int height, int x, int y) {
+ this.OBSERVERS.add(new Dashboard(null, car, title, width, height, x, y));
+ return this;
+ }
+
+ public Builder dashboards(int width, int height, int x, int y) {
+ List cars = OBSERVERS.stream()
+ .filter(o -> o instanceof Car)
+ .map(o -> (Car) o)
+ .toList();
+
+ int index = 0;
+ for (Car car : cars) {
+ dashboard(car, car.getName(), width, height, x, y + (height * index++));
+ }
+ return this;
}
- /**
- * Construit l'instance de {@link Game} avec les paramètres définis.
- *
- * Si la carte n'a pas été définie, le programme s'arrête.
- *
- */
public Game build() {
- if (map == null) {
- System.err.println("Vous devez définir une carte avant de construire le jeu !");
- System.exit(1);
+ Game game = new Game();
+
+ for (Game.Observer observer : this.OBSERVERS) {
+ switch (observer) {
+ case GameView gameView -> {
+ gameView.setGame(game);
+ }
+ case Car car -> {
+ car.setMap(map);
+ }
+ default -> {
+ }
+ }
}
- Game game = new Game(map, cars, state, time);
- buildVisual(game);
+ game.map = this.map;
+ game.time = this.time;
+ game.observers = this.OBSERVERS;
return game;
}
}
- private final Map map;
- /** État du jeu (par exemple, positions, carburant) */
- private final Car.State state;
- /** Temps entre chaque étape du jeu en millisecondes */
- private final int time;
+ private Map map;
+ private int time;
+ private List observers;
- /** Liste des voitures du jeu */
- private final ArrayList cars = new ArrayList<>();
- /** Liste des observateurs pour la mise à jour des vues */
- private final ArrayList obs = new ArrayList<>();
+ private boolean isPaused;
- /** Indique si le jeu est en pause */
- private boolean isPaused = false;
+ private Game() {
+ }
- /**
- * Constructeur principal.
- *
- * @param map carte du jeu
- * @param carInfos liste des informations des voitures à créer
- * @param state état initial du jeu
- * @param time temps entre chaque étape du jeu
- */
- public Game(Map map, ArrayList carInfos, Car.State state, int time) {
+ private Game(Map map, int time, List observer) {
this.map = map;
- this.state = state;
this.time = time;
-
- init(carInfos);
+ this.observers = observer;
}
- /**
- * Initialise le jeu en créant les vues et les objets {@link Car}.
- *
- * Chaque voiture obtient un Dashboard, la piste est affichée avec Track,
- * et le Rankboard est créé pour afficher le classement.
- *
- *
- * @param carInfos liste des informations des voitures
- * @return l'instance de Game
- */
- private Game init(ArrayList carInfos) {
- // Création de chaque voiture avec son Dashboard
- for (CarInfo ci : carInfos)
- cars.add(new Car(ci.name, ci.color, map)
- .setState(state));
-
- return this;
- }
-
- /**
- * Vérifie si le jeu est terminé.
- *
- * Le jeu est fini si au moins une voiture a épuisé son carburant.
- *
- *
- * @return true si le jeu est terminé
- */
- private boolean isFinish() {
- for (Car car : cars) {
- if (car.getFuel() == 0)
- return true;
- }
- return false;
- }
-
- /**
- * Ajoute un observateur pour recevoir les mises à jour du jeu.
- *
- * @param o observateur
- * @return instance de Game pour chaîner
- */
public Game addObserver(Observer o) {
- obs.add(o);
+ observers.add(o);
return this;
}
- /**
- * Supprime un observateur.
- *
- * @param o observateur
- * @return instance de Game pour chaîner
- */
- public Game remObserver(Observer o) {
- obs.remove(o);
+ public Game removeObserver(Observer o) {
+ observers.remove(o);
return this;
}
- /**
- * Bascule l'état de pause du jeu.
- *
- * Si le jeu était en pause, il est relancé et les threads en attente sont
- * notifiés.
- *
- *
- * @return true si le jeu est maintenant en pause
- */
+ private boolean isFinish() {
+ for (Game.Observer observer : observers) {
+ switch (observer) {
+ case Car car -> {
+ if (car.getFuel() > 0)
+ return false;
+ }
+ default -> {
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public void notifyObservers() {
+ for (Observer o : observers) {
+ if (!o.apply()) {
+ System.exit(0);
+ }
+ }
+ }
+
+ public void run() {
+ try {
+ while (!isFinish()) {
+ synchronized (this) {
+ while (isPaused)
+ wait();
+ }
+ notifyObservers();
+ Thread.sleep(time);
+ }
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ System.exit(1);
+ }
+ }
+
public synchronized boolean togglePause() {
if (isPaused)
notifyAll();
@@ -287,73 +162,17 @@ public class Game {
return isPaused;
}
- public void notifyObservers() {
- for (Observer o : obs) {
- boolean isSuccess = o.apply();
- if (!isSuccess) {
- System.err.println("Une erreur s'est produite pendant le jeu.");
- System.exit(1);
- }
- }
- }
-
- /**
- * Exécute un cycle du jeu
- *
- * Chaque voiture effectue son action, puis les observateurs sont notifiés.
- * La boucle attend si le jeu est en pause.
- *
- *
- * @throws InterruptedException si le thread est interrompu pendant wait()
- */
- private void step() throws InterruptedException {
- for (Car car : cars) {
- synchronized (this) {
- while (isPaused)
- wait();
- }
-
- car.run();
- notifyObservers();
- }
- }
-
- /**
- * Boucle principale du jeu.
- *
- * Tant que le jeu n'est pas terminé, on exécute les étapes et on met à jour
- * les vues toutes les 'time' millisecondes.
- *
- */
- public void run() {
- while (!isFinish()) {
- try {
- step();
- Thread.sleep(time);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
-
- System.out.println("Fini!\nVoici le score :");
- for (Car c : cars) {
- System.out.println(c.getName() + "\t" + c.getScore());
- }
- System.exit(0);
- }
-
- public ArrayList getCars() {
- return cars;
+ public List getCars() {
+ return observers.stream()
+ .filter(o -> o instanceof Car)
+ .map(o -> (Car) o)
+ .toList();
}
public Map getMap() {
return map;
}
- public Car.State getState() {
- return state;
- }
-
public boolean getPause() {
return isPaused;
}
diff --git a/src/model/car/BasicCar.java b/src/model/car/BasicCar.java
index 790ec1a..3369353 100644
--- a/src/model/car/BasicCar.java
+++ b/src/model/car/BasicCar.java
@@ -30,7 +30,7 @@ public class BasicCar implements Car {
/** Nombre de tours complétés */
private int round = 0;
/** Nombre de cases dans une boucle (doit être > 0) */
- private final Map MAP;
+ private Map map;
/** Carburant restant */
private int fuel = 60;
@@ -46,7 +46,12 @@ public class BasicCar implements Car {
public BasicCar(String name, Color color, Map map) {
this.NAME = name;
this.COLOR = color;
- this.MAP = map;
+ this.map = map;
+ }
+
+ public BasicCar(String name, Color color) {
+ this.NAME = name;
+ this.COLOR = color;
}
/**
@@ -77,40 +82,6 @@ public class BasicCar implements Car {
return this;
}
- /**
- * @return la position actuelle dans la boucle
- */
- public int getPosition() {
- return pos;
- }
-
- /**
- * @return le score de la voiture, calculé comme :
- * (nombre de tours + progression du tour) × 100
- */
- public int getScore() {
- return (int) ((round + (float) pos / MAP.getPathSize()) * 100);
- }
-
- /**
- * @return le nombre de tours complétés
- */
- public int getRound() {
- return round;
- }
-
- /**
- * @return le carburant restant
- */
- public int getFuel() {
- return fuel;
- }
-
- /** Retourne l'état courant de la voiture. */
- public State getState() {
- return state;
- }
-
/**
* Clique sur "Accelerer" : change d'état et retourne un message (si
* nécessaire).
@@ -175,15 +146,15 @@ public class BasicCar implements Car {
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);
+ Point point = map.getPath(pos);
+ Circuit element = map.getElement(point.x, point.y);
if (hasAccident(element, jump)) {
System.out.println(NAME + " a un\taccident");
setDamage();
return;
}
- round = pos / MAP.getPathSize();
+ round = pos / map.getPathSize();
}
}
@@ -203,6 +174,10 @@ public class BasicCar implements Car {
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.
@@ -212,11 +187,11 @@ public class BasicCar implements Car {
*
*/
@Override
- public void run() {
+ public boolean apply() {
if (fuel > 0) {
move();
- consumeFuel();
}
+ return !hasFinished();
}
@Override
@@ -225,12 +200,39 @@ public class BasicCar implements Car {
}
/**
- * @return la position actuelle (synonyme de getPosition)
+ * @return la position actuelle dans la boucle
*/
- public int getPos() {
+ public int getPosition() {
return pos;
}
+ /**
+ * @return le score de la voiture, calculé comme :
+ * (nombre de tours + progression du tour) × 100
+ */
+ public int getScore() {
+ return (int) ((round + (float) pos / map.getPathSize()) * 100);
+ }
+
+ /**
+ * @return le nombre de tours complétés
+ */
+ public int getRound() {
+ return round;
+ }
+
+ /**
+ * @return le carburant restant
+ */
+ public int getFuel() {
+ return fuel;
+ }
+
+ /** Retourne l'état courant de la voiture. */
+ public State getState() {
+ return state;
+ }
+
/**
* @return la couleur de la voiture
*/
@@ -244,4 +246,9 @@ public class BasicCar implements Car {
public String getName() {
return NAME;
}
+
+ @Override
+ public void setMap(Map map) {
+ this.map = map;
+ }
}
diff --git a/src/model/car/Car.java b/src/model/car/Car.java
index 1ce5787..2884300 100644
--- a/src/model/car/Car.java
+++ b/src/model/car/Car.java
@@ -2,7 +2,10 @@ package model.car;
import java.awt.Color;
-public interface Car {
+import model.Game.Observer;
+import model.map.Map;
+
+public interface Car extends Observer {
public String accelerate();
public String decelerate();
@@ -11,13 +14,21 @@ public interface Car {
public void consumeFuel();
- public void run();
-
public void reverse(boolean active);
- public int getPos();
-
public Color getColor();
public String getName();
+
+ public int getPosition();
+
+ public int getScore();
+
+ public int getRound();
+
+ public int getFuel();
+
+ public State getState();
+
+ public void setMap(Map map);
}
diff --git a/src/model/car/CarDecorator.java b/src/model/car/CarDecorator.java
new file mode 100644
index 0000000..a6a3ae9
--- /dev/null
+++ b/src/model/car/CarDecorator.java
@@ -0,0 +1,85 @@
+package model.car;
+
+import java.awt.Color;
+
+import model.map.Map;
+
+public abstract class CarDecorator implements Car {
+ protected final Car car;
+
+ public CarDecorator(Car car) {
+ this.car = car;
+ }
+
+ @Override
+ public String accelerate() {
+ return car.accelerate();
+ }
+
+ @Override
+ public String decelerate() {
+ return car.decelerate();
+ }
+
+ @Override
+ public void move() {
+ car.move();
+ }
+
+ @Override
+ public void consumeFuel() {
+ car.consumeFuel();
+ }
+
+ @Override
+ public boolean apply() {
+ boolean response = car.apply();
+ car.consumeFuel();
+ return response;
+ }
+
+ @Override
+ public void reverse(boolean active) {
+ car.reverse(active);
+ }
+
+ @Override
+ public Color getColor() {
+ return car.getColor();
+ }
+
+ @Override
+ public String getName() {
+ return car.getName();
+ }
+
+ @Override
+ public int getPosition() {
+ return car.getPosition();
+ }
+
+ @Override
+ public int getScore() {
+ return car.getScore();
+ }
+
+ @Override
+ public int getRound() {
+ return car.getRound();
+ }
+
+ @Override
+ public int getFuel() {
+ return car.getFuel();
+ }
+
+ @Override
+ public State getState() {
+ return car.getState();
+ }
+
+ @Override
+ public void setMap(Map map) {
+ car.setMap(map);
+ }
+}
\ No newline at end of file
diff --git a/src/model/car/DrunkCar.java b/src/model/car/DrunkCar.java
index 6b699e6..8871a57 100644
--- a/src/model/car/DrunkCar.java
+++ b/src/model/car/DrunkCar.java
@@ -1,6 +1,5 @@
package model.car;
-import java.awt.Color;
import java.util.Random;
/**
@@ -14,14 +13,12 @@ import java.util.Random;
* => On modifie seulement les actions utilisateur (accelerate/decelerate),
* sans modifier la classe Car.
*/
-public class DrunkCar implements Car {
+public class DrunkCar extends CarDecorator {
/** Générateur de nombres aléatoires pour simuler la progression */
protected static final Random RANDOM = new Random();
- private Car car;
-
public DrunkCar(Car car) {
- this.car = car;
+ super(car);
}
@Override
@@ -32,44 +29,4 @@ public class DrunkCar implements Car {
car.move();
car.reverse(false);
}
-
- @Override
- public void run() {
- car.run();
- }
-
- @Override
- public String accelerate() {
- return car.accelerate();
- }
-
- @Override
- public String decelerate() {
- return car.decelerate();
- }
-
- @Override
- public void consumeFuel() {
- car.consumeFuel();
- }
-
- @Override
- public void reverse(boolean active) {
- car.reverse(active);
- }
-
- @Override
- public int getPos() {
- return car.getPos();
- }
-
- @Override
- public Color getColor() {
- return car.getColor();
- }
-
- @Override
- public String getName() {
- return car.getName();
- }
}
\ No newline at end of file
diff --git a/src/model/car/HybridCar.java b/src/model/car/HybridCar.java
index c1c88da..db49a20 100644
--- a/src/model/car/HybridCar.java
+++ b/src/model/car/HybridCar.java
@@ -10,12 +10,11 @@ import java.awt.Color;
* - Mais elle consomme du carburant seulement 1 fois sur 2
* => donc elle économise du carburant.
*/
-public class HybridCar implements Car {
- private Car car;
+public class HybridCar extends CarDecorator {
private int energy = 100; // énergie batterie (0..100)
public HybridCar(Car car) {
- this.car = car;
+ super(car);
}
/** pour afficher l'énergie dans le Dashboard */
@@ -24,68 +23,25 @@ public class HybridCar implements Car {
}
@Override
- public void run() {
- // 1) La voiture avance toujours
- car.move();
+ public boolean apply() {
+ boolean response = car.apply();
- // 2) Gestion énergie : elle perd 10% à chaque boucle
- energy -= 10;
- if (energy < 0)
- energy = 0;
-
- // 3) Consommation :
- // - si on a encore de l'énergie, on économise le fuel (pas de conso)
- // - sinon, on consomme normalement
- if (energy == 0) {
+ if (energy > 0) {
+ energy -= 10;
+ } else {
car.consumeFuel();
}
+
+ return response;
}
@Override
public String decelerate() {
- // 1) On applique le ralentissement normal (State pattern)
String msg = car.decelerate();
- // 2) Recharge +5% quand on ralentit
- energy += 5;
- if (energy > 100)
- energy = 100;
+ if (energy <= 100)
+ energy += 5;
return msg;
}
-
- @Override
- public void consumeFuel() {
- car.consumeFuel();
- }
-
- @Override
- public void move() {
- car.move();
- }
-
- @Override
- public String accelerate() {
- return car.accelerate();
- }
-
- @Override
- public void reverse(boolean active) {
- car.reverse(active);
- }
-
- @Override
- public int getPos() {
- return car.getPos();
- }
-
- @Override
- public Color getColor() {
- return car.getColor();
- }
-
- @Override
- public String getName() {
- return car.getName();
- }
}
diff --git a/src/model/car/SoundCar.java b/src/model/car/SoundCar.java
index 8353fad..234ee1c 100644
--- a/src/model/car/SoundCar.java
+++ b/src/model/car/SoundCar.java
@@ -6,11 +6,9 @@ import java.awt.Color;
* Décorateur Sound :
* affiche un message sonore quand la voiture accélère.
*/
-public class SoundCar implements Car {
- private Car car;
-
+public class SoundCar extends CarDecorator {
public SoundCar(Car car) {
- this.car = car;
+ super(car);
}
@Override
@@ -18,45 +16,4 @@ public class SoundCar implements Car {
System.out.println("VROOOOM VROOOOOOM");
return car.accelerate();
}
-
- @Override
- public void run() {
- car.run();
- }
-
- @Override
- public String decelerate() {
- return car.decelerate();
- }
-
- @Override
- public void move() {
- car.move();
- }
-
- @Override
- public void consumeFuel() {
- car.consumeFuel();
- }
-
- @Override
- public void reverse(boolean active) {
- car.reverse(active);
- }
-
- @Override
- public int getPos() {
- return car.getPos();
- }
-
- @Override
- public Color getColor() {
- return car.getColor();
- }
-
- @Override
- public String getName() {
- // TODO Auto-generated method stub
- throw new UnsupportedOperationException("Unimplemented method 'getName'");
- }
}
diff --git a/src/visual/Dashboard.java b/src/visual/Dashboard.java
index 74c2c79..970a8f3 100644
--- a/src/visual/Dashboard.java
+++ b/src/visual/Dashboard.java
@@ -7,21 +7,21 @@ import javax.swing.JLabel;
import javax.swing.JPanel;
import model.Game;
-import model.car.BasicCar;
+import model.car.Car;
/**
* Dashboard représente une vue graphique pour une voiture spécifique.
*
* Il affiche :
- * - le carburant restant
- * - le nombre de tours complétés
- * - l'état courant de la voiture
- * - un message (info utilisateur)
+ * - le carburant restant
+ * - le nombre de tours complétés
+ * - l'état courant de la voiture
+ * - un message (info utilisateur)
*
* Il fournit :
- * - un bouton Pause/Reprise du jeu
- * - un bouton Accelerer
- * - un bouton Rallentir
+ * - un bouton Pause/Reprise du jeu
+ * - un bouton Accelerer
+ * - un bouton Rallentir
*/
public class Dashboard extends GameView {
@@ -44,7 +44,7 @@ public class Dashboard extends GameView {
private final JButton decelerateButton = new JButton("Rallentir");
/** Voiture associée à ce dashboard */
- private final BasicCar car;
+ private Car car;
/**
* Construit un dashboard pour une voiture donnée.
@@ -57,13 +57,15 @@ public class Dashboard extends GameView {
* @param x position horizontale de la fenêtre
* @param y position verticale de la fenêtre
*/
- public Dashboard(Game game, BasicCar car, String title, int width, int height, int x, int y) {
+ public Dashboard(Game game, Car car, String title, int width, int height, int x, int y) {
super(game, "Dashboard: " + title, width, height, x, y);
-
this.car = car;
-
-
+ if (car != null && game != null)
+ init();
+ }
+
+ private void init() {
// Fond de la fenêtre = couleur de la voiture
frame.setBackground(car.getColor());
@@ -72,7 +74,7 @@ public class Dashboard extends GameView {
centerPanel.add(infoLabel);
centerPanel.add(stateLabel);
centerPanel.add(messageLabel);
- //pour rendre le panel transparent
+ // pour rendre le panel transparent
centerPanel.setOpaque(false);
// ----- Partie boutons -----
@@ -80,7 +82,6 @@ public class Dashboard extends GameView {
buttonPanel.add(decelerateButton);
buttonPanel.add(pauseButton);
buttonPanel.add(accelerateButton);
-
setLayout(new BorderLayout());
add(centerPanel, BorderLayout.CENTER);
@@ -108,25 +109,38 @@ public class Dashboard extends GameView {
// Accélérer
accelerateButton.addActionListener(e -> {
- String msg = car.accelerate();
+ String msg = car.accelerate();
messageLabel.setText(msg);
game.notifyObservers();
});
// Ralentir
decelerateButton.addActionListener(e -> {
- String msg = car.decelerate();
+ String msg = car.decelerate();
messageLabel.setText(msg);
game.notifyObservers();
});
}
+ public void setCar(Car car) {
+ this.car = car;
+ }
+
/**
* Mise à jour de la vue.
* Cette méthode est appelée par Game via notifyObservers().
*/
@Override
public boolean apply() {
+ if (this.car == null) {
+ System.out.println("ERREUR Dashboard: car est null");
+ return false;
+ }
+
+ if (!super.apply()) {
+ System.out.println("ERREUR Dashboard: game est null");
+ return false;
+ }
infoLabel.setText("Carburant : " + car.getFuel() + " | Tours : " + car.getRound());
stateLabel.setText("Etat : " + car.getState());
diff --git a/src/visual/GameView.java b/src/visual/GameView.java
index 6b1f502..b40fdf7 100644
--- a/src/visual/GameView.java
+++ b/src/visual/GameView.java
@@ -15,8 +15,11 @@ import model.Game;
*/
public abstract class GameView extends JComponent implements Game.Observer {
/** Fenêtre associée à cette vue */
- protected final JFrame frame;
- protected final Game game;
+ protected JFrame frame;
+ protected Game game;
+ private String title;
+ private int width, height;
+ private int x, y;
/**
* Bloc statique exécuté au chargement de la classe pour vérifier
@@ -29,6 +32,10 @@ public abstract class GameView extends JComponent implements Game.Observer {
}
}
+ public void setGame(Game game) {
+ this.game = game;
+ }
+
/**
* Construit une nouvelle GameView avec une fenêtre JFrame.
*
@@ -38,7 +45,7 @@ public abstract class GameView extends JComponent implements Game.Observer {
* @param x Position horizontale de la fenêtre à l'écran
* @param y Position verticale de la fenêtre à l'écran
*/
- protected GameView(Game game, String title, int width, int height, int x, int y) {
+ protected void init(Game game) {
this.game = game;
// la fenetre
@@ -60,4 +67,20 @@ public abstract class GameView extends JComponent implements Game.Observer {
game.addObserver(this);
}
+
+ protected GameView(Game game, String title, int width, int height, int x, int y) {
+ this.title = title;
+ this.width = width;
+ this.height = height;
+ this.x = x;
+ this.y = y;
+
+ if (game != null)
+ init(game);
+ }
+
+ @Override
+ public boolean apply() {
+ return (game != null);
+ }
}
\ No newline at end of file
diff --git a/src/visual/Rankboard.java b/src/visual/Rankboard.java
index 69a8eba..6f47cc5 100644
--- a/src/visual/Rankboard.java
+++ b/src/visual/Rankboard.java
@@ -3,11 +3,12 @@ package visual;
import java.awt.BorderLayout;
import java.util.ArrayList;
import java.util.Comparator;
+import java.util.List;
import javax.swing.JLabel;
import model.Game;
-import model.car.BasicCar;
+import model.car.Car;
/**
* Rankboard est une vue graphique affichant le classement des voitures.
@@ -18,58 +19,68 @@ import model.car.BasicCar;
*
*/
public class Rankboard extends GameView {
- /** Liste des voitures à afficher */
- ArrayList cars;
+ /** Liste des voitures à afficher */
+ List cars;
- /** Composant JLabel pour afficher le classement */
- private final JLabel label;
+ /** Composant JLabel pour afficher le classement */
+ private JLabel label;
- /**
- * Construit un Rankboard.
- *
- * @param title Titre de la fenêtre
- * @param cars Liste des voitures à suivre
- * @param width Largeur de la fenêtre
- * @param height Hauteur de la fenêtre
- * @param x Position horizontale de la fenêtre
- * @param y Position verticale de la fenêtre
- */
- public Rankboard(Game game, String title, int width, int height, int x, int y) {
- super(game, title, width, height, x, y);
- this.cars = game.getCars();
- this.label = new JLabel();
- this.add(label, BorderLayout.CENTER);
- }
+ @Override
+ protected void init(Game game) {
+ super.init(game);
+ this.cars = game.getCars();
+ this.label = new JLabel();
+ this.add(label, BorderLayout.CENTER);
+ }
- /**
- * Met à jour le texte affiché dans le JLabel.
- *
- * Trie les voitures par score décroissant et construit
- * un tableau HTML pour l'affichage.
- *
- */
- private void updateRankText() {
+ /**
+ * Construit un Rankboard.
+ *
+ * @param title Titre de la fenêtre
+ * @param cars Liste des voitures à suivre
+ * @param width Largeur de la fenêtre
+ * @param height Hauteur de la fenêtre
+ * @param x Position horizontale de la fenêtre
+ * @param y Position verticale de la fenêtre
+ */
+ public Rankboard(Game game, String title, int width, int height, int x, int y) {
+ super(game, title, width, height, x, y);
+ if (game != null)
+ init(game);
+ }
- // cloner pour de modifier la classe principale
- ArrayList cars_clone = new ArrayList<>(cars);
- cars_clone.sort(Comparator.comparingInt(BasicCar::getScore).reversed());
+ /**
+ * Met à jour le texte affiché dans le JLabel.
+ *
+ * Trie les voitures par score décroissant et construit
+ * un tableau HTML pour l'affichage.
+ *
+ */
+ private void updateRankText() {
+ // cloner pour de modifier la classe principale
+ List cars_clone = new ArrayList<>(cars);
+ cars_clone.sort(Comparator.comparingInt(Car::getScore).reversed());
- StringBuilder s = new StringBuilder();
- s.append("");
- for (BasicCar c : cars_clone) {
- s.append("| " + c.getName() + ": " + c.getScore() + "% |
");
- }
- s.append("
");
- label.setText(s.toString());
- }
+ StringBuilder s = new StringBuilder();
+ s.append("");
+ for (Car c : cars_clone) {
+ s.append("| " + c.getName() + ": " + c.getScore() + "% |
");
+ }
+ s.append("
");
+ label.setText(s.toString());
+ }
- @Override
- /**
- * Méthode appelée par GameView.update().
- * Elle met à jour le classement affiché.
- */
- public boolean apply() {
- updateRankText();
- return true;
- }
+ @Override
+ /**
+ * Méthode appelée par GameView.update().
+ * Elle met à jour le classement affiché.
+ */
+ public boolean apply() {
+ if (!super.apply()) {
+ System.out.println("ERREUR Rankboard: game est null");
+ return false;
+ }
+ updateRankText();
+ return true;
+ }
}
diff --git a/src/visual/Track.java b/src/visual/Track.java
index 66dc6c8..f4d43ff 100644
--- a/src/visual/Track.java
+++ b/src/visual/Track.java
@@ -1,216 +1,229 @@
package visual;
+
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Point;
-import java.util.ArrayList;
+import java.util.List;
import model.Game;
-import model.car.BasicCar;
+import model.car.Car;
import model.map.Circuit;
import model.map.Map;
/**
* Track est une vue graphique représentant le circuit de course
- * ainsi que les voitures qui y circulent.
- * Cette classe hérite de GameView pour être intégrée au système de vues.
+ * ainsi que les voitures qui y circulent.
+ * Cette classe hérite de GameView pour être intégrée au système de
+ * vues.
*
- * Le rendu est basé sur une grille définie par Map et chaque cellule
+ * Le rendu est basé sur une grille définie par Map et chaque
+ * cellule
* est dessinée selon son type. Les voitures sont superposées sur la grille.
*
*/
public class Track extends GameView {
- /** La carte du circuit */
- private Map map;
- /** Liste des voitures à dessiner */
- private ArrayList cars;
- /** Échelle utilisée pour ajuster la taille des voitures dans les cellules */
- private final int scale = 80;
+ /** La carte du circuit */
+ private Map map;
+ /** Liste des voitures à dessiner */
+ private List cars;
+ /** Échelle utilisée pour ajuster la taille des voitures dans les cellules */
+ private final int scale = 80;
- /**
- * Construit la vue Track avec une carte et une liste de voitures.
- *
- * @param map La carte du circuit
- * @param cars Liste des voitures
- * @param title Titre de la fenêtre
- * @param width Largeur de la fenêtre
- * @param height Hauteur de la fenêtre
- * @param x Position X de la fenêtre
- * @param y Position Y de la fenêtre
- */
- protected Track(Game game, String title, int width, int height, int x, int y)
- {
- super(game, title, width, height, x, y);
- map = game.getMap();
- cars = game.getCars();
- }
+ @Override
+ protected void init(Game game) {
+ super.init(game);
+ map = game.getMap();
+ cars = game.getCars();
+ }
- /**
- * Méthode de dessin appelée automatiquement par Swing.
- * Dessine chaque cellule de la carte ainsi que les voitures.
- */
- @Override
- protected void paintComponent(Graphics g) {
- super.paintComponent(g);
+ /**
+ * Construit la vue Track avec une carte et une liste de voitures.
+ *
+ * @param map La carte du circuit
+ * @param cars Liste des voitures
+ * @param title Titre de la fenêtre
+ * @param width Largeur de la fenêtre
+ * @param height Hauteur de la fenêtre
+ * @param x Position X de la fenêtre
+ * @param y Position Y de la fenêtre
+ */
+ public Track(Game game, String title, int width, int height, int x, int y) {
+ super(game, title, width, height, x, y);
+ if (game != null)
+ init(game);
+ }
- int rows = map.getHeight();
- int cols = map.getWidth();
+ /**
+ * Méthode de dessin appelée automatiquement par Swing.
+ * Dessine chaque cellule de la carte ainsi que les voitures.
+ */
+ @Override
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
- // Calcul de la taille d'une cellule en pixels selon la taille de la fenêtre
- int[] cellSize = new int[] {
- (getWidth() + 10) / cols,
- (getHeight() + 10) / rows
- };
+ int rows = map.getHeight();
+ int cols = map.getWidth();
- // Définir une police monospace en gras pour les caractères du circuit
- g.setFont(new Font("Monospaced", Font.BOLD, cellSize[1] / 2));
+ // Calcul de la taille d'une cellule en pixels selon la taille de la fenêtre
+ int[] cellSize = new int[] {
+ (getWidth() + 10) / cols,
+ (getHeight() + 10) / rows
+ };
- // Parcours de toutes les cellules du circuit
- for (int y = 0; y < rows; y++) {
- for (int x = 0; x < cols; x++) {
- Circuit cell = this.map.getElement(x, y);
- drawCell(g, cell, new int[] {x, y}, cellSize);
- }
- }
- }
+ // Définir une police monospace en gras pour les caractères du circuit
+ g.setFont(new Font("Monospaced", Font.BOLD, cellSize[1] / 2));
- /**
- * Retourne la couleur d'une cellule selon son type.
- */
- private Color getCellColor(Circuit.Cell cell) {
- return switch (cell) {
- case ROAD -> Color.GRAY;
- case START -> Color.YELLOW;
- case FINISH -> Color.YELLOW;
- case EMPTY -> Color.GREEN;
- case YROAD -> Color.YELLOW;
- };
- }
+ // Parcours de toutes les cellules du circuit
+ for (int y = 0; y < rows; y++) {
+ for (int x = 0; x < cols; x++) {
+ Circuit cell = this.map.getElement(x, y);
+ drawCell(g, cell, new int[] { x, y }, cellSize);
+ }
+ }
+ }
- /**
- * Retourne le caractère à afficher pour une cellule du circuit.
- */
- private char getCellChar(Circuit cell) {
- return switch (cell.getType()) {
- case ROAD -> '\0';
- case START -> 'D';
- case FINISH -> 'A';
- case EMPTY -> '\0';
- case YROAD -> (char)('0' + cell.getValue());
- };
- }
+ /**
+ * Retourne la couleur d'une cellule selon son type.
+ */
+ private Color getCellColor(Circuit.Cell cell) {
+ return switch (cell) {
+ case ROAD -> Color.GRAY;
+ case START -> Color.YELLOW;
+ case FINISH -> Color.YELLOW;
+ case EMPTY -> Color.GREEN;
+ case YROAD -> Color.YELLOW;
+ };
+ }
- /**
- * Dessine toutes les voitures sur une cellule donnée.
- * Les voitures sont légèrement décalées pour ne pas avoir exactement la même taille.
- */
- private void drawCars(Graphics g, int[] cellCoord) {
- int size = 1;
- for (BasicCar c : cars) {
- int i = c.getPos();
- Point p = this.map.getPath(i);
- int[] ncoord = new int[] {p.x, p.y};
- drawInnerBlock(g, ncoord, cellCoord, c.getColor(), scale - size);
- size += 3; // pour différencier visuellement les voitures
- }
- }
+ /**
+ * Retourne le caractère à afficher pour une cellule du circuit.
+ */
+ private char getCellChar(Circuit cell) {
+ return switch (cell.getType()) {
+ case ROAD -> '\0';
+ case START -> 'D';
+ case FINISH -> 'A';
+ case EMPTY -> '\0';
+ case YROAD -> (char) ('0' + cell.getValue());
+ };
+ }
- /**
- * Dessine une cellule complète avec son contenu (caractère et voitures).
- */
- private void drawCell(Graphics g, Circuit cell, int[] coord, int[] cellCoord) {
- drawBlock(g, cell, coord, cellCoord);
+ /**
+ * Dessine toutes les voitures sur une cellule donnée.
+ * Les voitures sont légèrement décalées pour ne pas avoir exactement la même
+ * taille.
+ */
+ private void drawCars(Graphics g, int[] cellCoord) {
+ int size = 1;
+ for (Car c : cars) {
+ int i = c.getPosition();
+ Point p = this.map.getPath(i);
+ int[] ncoord = new int[] { p.x, p.y };
+ drawInnerBlock(g, ncoord, cellCoord, c.getColor(), scale - size);
+ size += 3; // pour différencier visuellement les voitures
+ }
+ }
- char c = getCellChar(cell);
- if (c != '\0') {
- drawCharacter(g, coord, cellCoord, c);
- }
+ /**
+ * Dessine une cellule complète avec son contenu (caractère et voitures).
+ */
+ private void drawCell(Graphics g, Circuit cell, int[] coord, int[] cellCoord) {
+ drawBlock(g, cell, coord, cellCoord);
- drawCars(g, cellCoord);
- }
+ char c = getCellChar(cell);
+ if (c != '\0') {
+ drawCharacter(g, coord, cellCoord, c);
+ }
- /**
- * Dessine un caractère centré dans une cellule.
- */
- private void drawCharacter(Graphics g, int[] coord, int[] cellCoord, char c) {
- int x = coord[0];
- int y = coord[1];
+ drawCars(g, cellCoord);
+ }
- int cellWidth = cellCoord[0];
- int cellHeight = cellCoord[1];
+ /**
+ * Dessine un caractère centré dans une cellule.
+ */
+ private void drawCharacter(Graphics g, int[] coord, int[] cellCoord, char c) {
+ int x = coord[0];
+ int y = coord[1];
- String s = c + "";
- g.setColor(Color.BLACK);
+ int cellWidth = cellCoord[0];
+ int cellHeight = cellCoord[1];
- FontMetrics fm = g.getFontMetrics();
- // taille du string + font
- int textWidth = fm.stringWidth(s);
- // hauteur haute par exemple: h depasse en haut
- int textHeight = fm.getAscent();
- // hauteur basse par exemple: g depasse en bas
- int descent = fm.getDescent();
+ String s = c + "";
+ g.setColor(Color.BLACK);
- int cx = x * cellWidth + (cellWidth - textWidth) / 2;
- int cy = y * cellHeight + (cellHeight + textHeight - descent) / 2;
+ FontMetrics fm = g.getFontMetrics();
+ // taille du string + font
+ int textWidth = fm.stringWidth(s);
+ // hauteur haute par exemple: h depasse en haut
+ int textHeight = fm.getAscent();
+ // hauteur basse par exemple: g depasse en bas
+ int descent = fm.getDescent();
- g.drawString(s, cx, cy);
- }
+ int cx = x * cellWidth + (cellWidth - textWidth) / 2;
+ int cy = y * cellHeight + (cellHeight + textHeight - descent) / 2;
- /**
- * Dessine un bloc intérieur plus petit, utilisé pour représenter une voiture
- */
- private void drawInnerBlock(Graphics g, int[] coord, int[] cellCoord, Color c, int scale) {
- // scale de la taille du bloc
- int w = cellCoord[0] * scale / 100;
- int h = cellCoord[1] * scale / 100;
+ g.drawString(s, cx, cy);
+ }
- // calcul de la position avec la nouvelle taille
- int ox = coord[0] * cellCoord[0] + (cellCoord[0] - w) / 2;
- int oy = coord[1] * cellCoord[1] + (cellCoord[1] - h) / 2;
+ /**
+ * Dessine un bloc intérieur plus petit, utilisé pour représenter une voiture
+ */
+ private void drawInnerBlock(Graphics g, int[] coord, int[] cellCoord, Color c, int scale) {
+ // scale de la taille du bloc
+ int w = cellCoord[0] * scale / 100;
+ int h = cellCoord[1] * scale / 100;
- // dessine le bloc plus petit
- g.setColor(c);
- g.fillRect(ox, oy, w, h);
- }
+ // calcul de la position avec la nouvelle taille
+ int ox = coord[0] * cellCoord[0] + (cellCoord[0] - w) / 2;
+ int oy = coord[1] * cellCoord[1] + (cellCoord[1] - h) / 2;
- /**
- * Dessine une cellule de base selon son type et ajoute un contour noir.
- */
- private void drawBlock(Graphics g, Circuit cell, int[] coord, int[] cellCoord) {
- int x = coord[0];
- int y = coord[1];
+ // dessine le bloc plus petit
+ g.setColor(c);
+ g.fillRect(ox, oy, w, h);
+ }
- int cellWidth = cellCoord[0];
- int cellHeight = cellCoord[1];
+ /**
+ * Dessine une cellule de base selon son type et ajoute un contour noir.
+ */
+ private void drawBlock(Graphics g, Circuit cell, int[] coord, int[] cellCoord) {
+ int x = coord[0];
+ int y = coord[1];
- switch (cell.getType()) {
- case YROAD:
- // dessine le bloc de route
- g.setColor(getCellColor(Circuit.Cell.ROAD));
- g.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);
-
- // dessine le sous bloc de route
- drawInnerBlock(g, coord, cellCoord, getCellColor(cell.getType()), scale);
- break;
- default:
- g.setColor(getCellColor(cell.getType()));
- g.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);
- break;
- }
+ int cellWidth = cellCoord[0];
+ int cellHeight = cellCoord[1];
- // contour noir
- g.setColor(Color.BLACK);
- g.drawRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);
- }
+ switch (cell.getType()) {
+ case YROAD:
+ // dessine le bloc de route
+ g.setColor(getCellColor(Circuit.Cell.ROAD));
+ g.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);
- /**
- * Méthode appelée automatiquement pour mettre à jour l'affichage.
- */
- @Override
- public boolean apply()
- {
- repaint();
- return true;
- }
+ // dessine le sous bloc de route
+ drawInnerBlock(g, coord, cellCoord, getCellColor(cell.getType()), scale);
+ break;
+ default:
+ g.setColor(getCellColor(cell.getType()));
+ g.fillRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);
+ break;
+ }
+
+ // contour noir
+ g.setColor(Color.BLACK);
+ g.drawRect(x * cellWidth, y * cellHeight, cellWidth, cellHeight);
+ }
+
+ /**
+ * Méthode appelée automatiquement pour mettre à jour l'affichage.
+ */
+ @Override
+ public boolean apply() {
+ if (!super.apply()) {
+ System.out.println("ERREUR Track: game est null");
+ return false;
+ }
+ repaint();
+ return true;
+ }
}