Files
archived-L3-racing-game/src/visual/Track.java

197 lines
6.0 KiB
Java

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.List;
import model.Game;
import model.car.Car;
import model.map.Circuit;
import model.map.Map;
/**
* <code>Track</code> est une vue graphique représentant le circuit de course
* ainsi que les voitures qui y circulent.
* Cette classe hérite de <code>GameView</code> pour être intégrée au système de
* vues.
* <p>
* Le rendu est basé sur une grille définie par <code>Map</code> et chaque
* cellule
* est dessinée selon son type. Les voitures sont superposées sur la grille.
* </p>
*/
public class Track extends GameView {
/** La carte du circuit */
private Map map;
/** Liste des voitures à dessiner */
private List<Car> cars;
/** Échelle utilisée pour ajuster la taille des voitures dans les cellules */
private final int scale = 80;
@Override
protected void init(Game game) {
super.init(game);
map = game.getMap();
cars = game.getCars();
}
/**
* 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);
}
/**
* 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);
int rows = map.getHeight();
int cols = map.getWidth();
// Taille d'un cube sur la fenetre
Point size = new Point(
(getWidth() + 10) / cols,
(getHeight() + 10) / rows);
// Définir une police monospace en gras pour les caractères du circuit
g.setFont(new Font("Monospaced", Font.BOLD, size.y / 2));
drawCells(g, size);
drawCars(g, size);
}
/**
* Dessine une cellule complète avec son contenu (caractère et voitures).
*/
private void drawCells(Graphics g, Point squareSize) {
for (int y = 0; y < map.getHeight(); y++) {
for (int x = 0; x < map.getWidth(); x++) {
Point pos = new Point(x, y);
Circuit element = map.getElement(x, y);
drawBlock(g, element, pos, squareSize);
}
}
}
/**
* 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, Point squaresize) {
int size = cars.size();
for (int i = 0; i < size; i++) {
Car car = cars.get(i);
Point p = map.getPath(car.getPosition());
drawInnerBlock(g, p, squaresize, car.getColor(), scale / size, 2 + i * (squaresize.y / size));
}
}
/**
* Dessine une cellule de base selon son type et ajoute un contour noir.
*/
private void drawBlock(Graphics g, Circuit element, Point coord, Point squareSize) {
g.setColor(switch (element.getType()) {
case ROAD -> Color.GRAY;
case EMPTY -> Color.GREEN;
default -> Color.YELLOW;
});
g.fillRect(
coord.x * squareSize.x,
coord.y * squareSize.y,
squareSize.x,
squareSize.y);
// contour noir
g.setColor(Color.BLACK);
g.drawRect(coord.x * squareSize.x,
coord.y * squareSize.y,
squareSize.x,
squareSize.y);
drawCharacter(g, element, coord, squareSize);
}
/**
* Dessine un caractère centré dans une cellule.
*/
private void drawCharacter(Graphics g, Circuit element, Point coord, Point squareSize) {
String character = switch (element.getType()) {
case START -> 'D';
case FINISH -> 'A';
case YROAD -> (char) ('0' + element.getValue());
default -> "";
} + "";
if (character.isEmpty())
return;
g.setColor(Color.BLACK);
FontMetrics fm = g.getFontMetrics();
// taille du string + font
int textWidth = fm.stringWidth(character);
// hauteur haute par exemple: h depasse en haut
int textHeight = fm.getAscent();
// hauteur basse par exemple: g depasse en bas
int descent = fm.getDescent();
Point cp = new Point(
coord.x * squareSize.x + (squareSize.x - textWidth) / 2,
coord.y * squareSize.y + (squareSize.y + textHeight - descent) / 2);
g.drawString(character, cp.x, cp.y);
}
/**
* Dessine un bloc intérieur plus petit, utilisé pour représenter une voiture
*/
private void drawInnerBlock(Graphics g, Point coord, Point squareSize, Color c, int scale, int y) {
// scale de la taille du bloc
Point size = new Point(
squareSize.x * scale / 100,
squareSize.y * scale / 100);
// calcul de la position avec la nouvelle taille
Point pos = new Point(
coord.x * squareSize.x + (squareSize.x - size.x) / 2,
coord.y * squareSize.y + y);
// dessine le bloc plus petit
g.setColor(c);
g.fillRect(pos.x, pos.y, size.x, size.y);
}
/**
* 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;
}
}