Files
archived-L3-racing-game/src/Game.java

347 lines
9.6 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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;
}
}