mirror of
https://github.com/guezoloic/racing-game.git
synced 2026-03-28 18:03:50 +00:00
feat(Game): ajout commentaire et ajout fonction setup
This commit is contained in:
@@ -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<Game> {
|
||||
/**
|
||||
* {@code Observer} représente une entité réagissant au déroulement
|
||||
* du jeu : voiture, vue graphique, tableau de scores, etc.
|
||||
*
|
||||
* <p>
|
||||
* Les fonctions disponible dans l'interface sont les suivantes:
|
||||
* <ul>
|
||||
* <li>{@link #setup(Game)} : appelée lors de l'initialisation</li>
|
||||
* <li>{@link #apply()} : appelée à chaque tick du jeu</li>
|
||||
* <li>{@link #end()} : appelée lorsque le jeu se termine</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
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}.
|
||||
* <p>
|
||||
* Il permet de configurer l'ensemble des éléments du jeu avant son lancement :
|
||||
* <ul>
|
||||
* <li>les voitures ({@link Car})</li>
|
||||
* <li>les vues graphiques ({@link GameView})</li>
|
||||
* <li>la carte ({@link Map})</li>
|
||||
* <li>le temps entre chaque tick</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*/
|
||||
public static class Builder {
|
||||
/**
|
||||
* {@code DashboardConfig} encapsule les paramètres communs
|
||||
* nécessaires à la création automatique de plusieurs dashboards.
|
||||
* <p>
|
||||
*/
|
||||
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<Car> cars = new ArrayList<>();
|
||||
|
||||
/** Liste des vues graphiques observant le jeu */
|
||||
private final List<GameView> 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.
|
||||
* <p>
|
||||
* Cette méthode :
|
||||
* <ol>
|
||||
* <li>crée automatiquement les dashboards si configurés</li>
|
||||
* <li>regroupe toutes les voitures et vues comme observateurs</li>
|
||||
* <li>instancie le {@link Game}</li>
|
||||
* <li>appelle {@link Game.Observer#setup(Game)} sur chaque observateur</li>
|
||||
* </ol>
|
||||
* </p>
|
||||
*
|
||||
* @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<Game.Observer> 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<Game.Observer> 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* <p>
|
||||
* La boucle s'exécute tant que :
|
||||
* <ul>
|
||||
* <li>la partie n'est pas terminée</li>
|
||||
* <li>aucun observateur ne demande l'arrêt</li>
|
||||
* </ul>
|
||||
*
|
||||
* 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<Car> 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;
|
||||
}
|
||||
|
||||
@@ -131,22 +131,22 @@ public class BasicCar implements Car {
|
||||
* incrémenté et
|
||||
* la position revient à zéro.
|
||||
* </p>
|
||||
*
|
||||
* @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);
|
||||
*
|
||||
* @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);
|
||||
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)) {
|
||||
setDamage();
|
||||
return;
|
||||
if (hasAccident(element, jump)) {
|
||||
setDamage();
|
||||
return;
|
||||
}
|
||||
round = pos / map.getPathSize();
|
||||
}
|
||||
@@ -158,51 +158,51 @@ public class BasicCar implements Car {
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* <p>
|
||||
* La progression est déterminée par un intervalle aléatoire fourni par l'état
|
||||
* du jeu.
|
||||
* </p>
|
||||
*/
|
||||
@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.
|
||||
* <p>
|
||||
* La progression est déterminée par un intervalle aléatoire fourni par l'état
|
||||
* du jeu.
|
||||
* </p>
|
||||
*/
|
||||
@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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,8 @@ public class RankboardView extends GameView {
|
||||
* </p>
|
||||
*/
|
||||
private void updateRankText() {
|
||||
if (cars == null) return;
|
||||
if (cars == null)
|
||||
return;
|
||||
// cloner pour de modifier la classe principale
|
||||
List<Car> 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() {
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user