mirror of
https://github.com/guezoloic/L3-racing-game.git
synced 2026-03-31 12:21:34 +00:00
347 lines
9.6 KiB
Java
347 lines
9.6 KiB
Java
import java.awt.Color;
|
||
import java.util.ArrayList;
|
||
|
||
/**
|
||
* La classe {@link Game} représente le moteur principal du jeu.
|
||
* <p>
|
||
* 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).
|
||
* </p>
|
||
*/
|
||
public class Game
|
||
{
|
||
/**
|
||
* {@link CarInfo} est une structure simple qui contient les informations
|
||
* nécessaires pour créer une voiture dans le jeu : son nom et sa couleur.
|
||
*/
|
||
public record CarInfo(String name, Color color) {}
|
||
|
||
/**
|
||
* {@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).
|
||
* <p>
|
||
* Chaque instance contient toutes les informations nécessaires pour créer et positionner
|
||
* cette vue à l’écran.
|
||
* </p>
|
||
*
|
||
* @param type le type concret de la vue (classe héritant de {@link GameView})
|
||
* @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
|
||
*/
|
||
public record VisualInfo
|
||
(
|
||
Class<? extends GameView> type,
|
||
String title,
|
||
int width, int height,
|
||
int x, int y
|
||
) {}
|
||
|
||
/**
|
||
* Builder pour créer une instance de {@link Game} de façon fluide.
|
||
* <p>
|
||
* 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.
|
||
* </p>
|
||
*/
|
||
public static class Builder
|
||
{
|
||
/** Liste des voitures à créer pour le jeu */
|
||
private ArrayList<CarInfo> cars = new ArrayList<>();
|
||
/** Liste des voitures à créer pour le jeu */
|
||
private ArrayList<VisualInfo> visuals = new ArrayList<>();
|
||
/** État initial du jeu */
|
||
private State state = new State();
|
||
/** Temps entre chaque step du jeu */
|
||
private int time = 1000;
|
||
/** Carte sur laquelle se déroule le jeu */
|
||
private Map map = null;
|
||
|
||
/** Ajoute une voiture à la liste */
|
||
public Builder addCar(CarInfo car)
|
||
{
|
||
cars.add(car);
|
||
return this;
|
||
}
|
||
|
||
/** Supprime une voiture de la liste */
|
||
public Builder remCar(CarInfo car)
|
||
{
|
||
cars.remove(car);
|
||
return this;
|
||
}
|
||
|
||
/** Définit la carte du jeu */
|
||
public Builder setMap(Map map)
|
||
{
|
||
this.map = map;
|
||
return this;
|
||
}
|
||
|
||
/** Définit l'état initial du jeu */
|
||
public Builder setState(State s)
|
||
{
|
||
this.state = s;
|
||
return this;
|
||
}
|
||
|
||
/** Définit le temps entre chaque étape du jeu */
|
||
public Builder setTime(int time)
|
||
{
|
||
this.time = time;
|
||
return this;
|
||
}
|
||
|
||
public Builder addVisual(Class<? extends GameView> type, String title, int width, int height, int x, int y)
|
||
{
|
||
visuals.add(new VisualInfo(type, title, width, height, x, y));
|
||
return this;
|
||
}
|
||
|
||
private void buildVisual(Game game)
|
||
{
|
||
for (VisualInfo v : visuals)
|
||
{
|
||
if (v.type == Rankboard.class)
|
||
game.addObserver(new Rankboard(game, v.title, v.width, v.height, v.x, v.y));
|
||
else if (v.type == Track.class)
|
||
game.addObserver(new Track(game, v.title, v.width, v.height, v.x, v.y));
|
||
else if (v.type == Dashboard.class)
|
||
{
|
||
for (CarInfo info : cars)
|
||
{
|
||
if (info.name.equals(v.title))
|
||
{
|
||
Car car = game.getCars().stream()
|
||
.filter(c -> c.getName().equals(info.name))
|
||
.findFirst()
|
||
.orElse(null);
|
||
if (car != null)
|
||
game.addObserver(new Dashboard(game, car, v.title, v.width, v.height, v.x, v.y));
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Construit l'instance de {@link Game} avec les paramètres définis.
|
||
* <p>
|
||
* Si la carte n'a pas été définie, le programme s'arrête.
|
||
* </p>
|
||
*/
|
||
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(map, cars, state, time);
|
||
buildVisual(game);
|
||
return game;
|
||
}
|
||
}
|
||
|
||
private final Map map;
|
||
/** État du jeu (par exemple, positions, carburant) */
|
||
private final State state;
|
||
/** Temps entre chaque étape du jeu en millisecondes */
|
||
private final int time;
|
||
|
||
/** Liste des voitures du jeu */
|
||
private final ArrayList<Car> cars = new ArrayList<>();
|
||
/** Liste des observateurs pour la mise à jour des vues */
|
||
private final ArrayList<GObserver> obs = new ArrayList<>();
|
||
|
||
/** Indique si le jeu est en pause */
|
||
private boolean isPaused = false;
|
||
|
||
/**
|
||
* 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<CarInfo> carInfos, State state, int time)
|
||
{
|
||
this.map = map;
|
||
this.state = state;
|
||
this.time = time;
|
||
|
||
init(carInfos);
|
||
}
|
||
|
||
/**
|
||
* Initialise le jeu en créant les vues et les objets {@link Car}.
|
||
* <p>
|
||
* Chaque voiture obtient un Dashboard, la piste est affichée avec Track,
|
||
* et le Rankboard est créé pour afficher le classement.
|
||
* </p>
|
||
*
|
||
* @param carInfos liste des informations des voitures
|
||
* @return l'instance de Game
|
||
*/
|
||
private Game init(ArrayList<CarInfo> carInfos)
|
||
{
|
||
final int loop = map.getPathSize();
|
||
|
||
// Création de chaque voiture avec son Dashboard
|
||
for (CarInfo ci : carInfos)
|
||
cars.add(new Car(ci.name, ci.color, loop, state));
|
||
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Vérifie si le jeu est terminé.
|
||
* <p>
|
||
* Le jeu est fini si au moins une voiture a épuisé son carburant.
|
||
* </p>
|
||
*
|
||
* @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(GObserver o)
|
||
{
|
||
obs.add(o);
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Supprime un observateur.
|
||
*
|
||
* @param o observateur
|
||
* @return instance de Game pour chaîner
|
||
*/
|
||
public Game remObserver(GObserver o)
|
||
{
|
||
obs.remove(o);
|
||
return this;
|
||
}
|
||
|
||
/**
|
||
* Bascule l'état de pause du jeu.
|
||
* <p>
|
||
* Si le jeu était en pause, il est relancé et les threads en attente sont notifiés.
|
||
* </p>
|
||
*
|
||
* @return true si le jeu est maintenant en pause
|
||
*/
|
||
public synchronized boolean togglePause()
|
||
{
|
||
if (isPaused) notifyAll();
|
||
isPaused = !isPaused;
|
||
return isPaused;
|
||
}
|
||
|
||
public void notifyObservers()
|
||
{
|
||
for (GObserver 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
|
||
* <p>
|
||
* Chaque voiture effectue son action, puis les observateurs sont notifiés.
|
||
* La boucle attend si le jeu est en pause.
|
||
* </p>
|
||
*
|
||
* @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.
|
||
* <p>
|
||
* Tant que le jeu n'est pas terminé, on exécute les étapes et on met à jour
|
||
* les vues toutes les 'time' millisecondes.
|
||
* </p>
|
||
*/
|
||
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<Car> getCars()
|
||
{
|
||
return cars;
|
||
}
|
||
|
||
public Map getMap()
|
||
{
|
||
return map;
|
||
}
|
||
|
||
public State getState()
|
||
{
|
||
return state;
|
||
}
|
||
|
||
public boolean getPause()
|
||
{
|
||
return isPaused;
|
||
}
|
||
}
|