167 lines
5.3 KiB
Java
167 lines
5.3 KiB
Java
package fr.iut_fbleau.HexGame;
|
|
|
|
import fr.iut_fbleau.GameAPI.Player;
|
|
|
|
import javax.swing.*;
|
|
import java.awt.*;
|
|
import java.awt.event.MouseAdapter;
|
|
import java.awt.event.MouseEvent;
|
|
import java.awt.geom.Path2D;
|
|
|
|
/**
|
|
* Panel Swing qui dessine un plateau Hex en hexagones et gère les clics.
|
|
*
|
|
* Grille "flat-top" (hexagones à sommet plat en haut),
|
|
* avec décalage vertical d'une demi-hauteur une colonne sur deux.
|
|
*/
|
|
public class HexPanel extends JPanel {
|
|
|
|
private final HexBoard board;
|
|
private final JLabel statusLabel;
|
|
|
|
// Rayon (distance centre -> sommet)
|
|
private final int s = 26;
|
|
private final int margin = 40;
|
|
// pointy-top : largeur = sqrt(3)*s, hauteur = 2*s
|
|
private final double hexW = Math.sqrt(3) * s;
|
|
private final double hexVStep = 1.5 * s; // distance verticale entre centres
|
|
|
|
|
|
private Shape[][] hexShapes;
|
|
|
|
public HexPanel(HexBoard board, JLabel statusLabel) {
|
|
this.board = board;
|
|
this.statusLabel = statusLabel;
|
|
this.hexShapes = new Shape[board.getSize()][board.getSize()];
|
|
|
|
setBackground(Color.WHITE);
|
|
|
|
addMouseListener(new MouseAdapter() {
|
|
@Override
|
|
public void mouseClicked(MouseEvent e) {
|
|
handleClick(e.getX(), e.getY());
|
|
}
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public Dimension getPreferredSize() {
|
|
int n = board.getSize();
|
|
|
|
// largeur : n * hexW + décalage max (hexW/2) + marges
|
|
int w = margin * 2 + (int) (n * hexW + hexW / 2);
|
|
|
|
// hauteur : (n-1)*1.5*s + 2*s + marges
|
|
int h = margin * 2 + (int) ((n - 1) * hexVStep + 2 * s);
|
|
|
|
return new Dimension(w, h);
|
|
}
|
|
|
|
|
|
private void handleClick(int x, int y) {
|
|
if (board.isGameOver()) return;
|
|
|
|
int n = board.getSize();
|
|
for (int row = 0; row < n; row++) {
|
|
for (int col = 0; col < n; col++) {
|
|
Shape sh = hexShapes[row][col];
|
|
if (sh != null && sh.contains(x, y)) {
|
|
HexPly ply = new HexPly(board.getCurrentPlayer(), row, col);
|
|
if (board.isLegal(ply)) {
|
|
board.doPly(ply);
|
|
HexFrame.updateStatus(board, statusLabel);
|
|
repaint();
|
|
} else {
|
|
Toolkit.getDefaultToolkit().beep();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void paintComponent(Graphics g) {
|
|
super.paintComponent(g);
|
|
|
|
Graphics2D g2 = (Graphics2D) g.create();
|
|
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
|
|
|
// Bordures objectifs (bleu gauche/droite, rouge haut/bas)
|
|
drawGoalBorders(g2);
|
|
|
|
int n = board.getSize();
|
|
|
|
// IMPORTANT : boucles cohérentes -> row puis col
|
|
for (int row = 0; row < n; row++) {
|
|
for (int col = 0; col < n; col++) {
|
|
|
|
Shape hex = createHexShape(row, col);
|
|
hexShapes[row][col] = hex;
|
|
|
|
Player p = board.getCellPlayer(row, col);
|
|
g2.setColor(colorForCell(p));
|
|
g2.fill(hex);
|
|
|
|
g2.setColor(new Color(120, 120, 120));
|
|
g2.setStroke(new BasicStroke(1.2f));
|
|
g2.draw(hex);
|
|
}
|
|
}
|
|
|
|
g2.dispose();
|
|
}
|
|
|
|
private Color colorForCell(Player p) {
|
|
if (p == Player.PLAYER1) return new Color(30, 90, 160); // bleu
|
|
if (p == Player.PLAYER2) return new Color(220, 50, 50); // rouge
|
|
return new Color(190, 190, 190); // gris
|
|
}
|
|
|
|
/**
|
|
* Pointy-top + décalage par ligne :
|
|
*
|
|
* centreX = margin + hexW/2 + col*hexW + (row%2)*(hexW/2)
|
|
* centreY = margin + s + row*(1.5*s)
|
|
*/
|
|
private Shape createHexShape(int row, int col) {
|
|
double cx = margin + (hexW / 2.0) + col * hexW + ((row % 2) * (hexW / 2.0));
|
|
double cy = margin + s + row * hexVStep;
|
|
|
|
Path2D.Double path = new Path2D.Double();
|
|
for (int i = 0; i < 6; i++) {
|
|
double angle = Math.toRadians(i * 60); // pointy-top
|
|
double x = cx + s * Math.cos(angle);
|
|
double y = cy + s * Math.sin(angle);
|
|
if (i == 0) path.moveTo(x, y);
|
|
else path.lineTo(x, y);
|
|
}
|
|
path.closePath();
|
|
return path;
|
|
}
|
|
|
|
|
|
private void drawGoalBorders(Graphics2D g2) {
|
|
int n = board.getSize();
|
|
|
|
double leftX = margin - 12;
|
|
double rightX = margin + (hexW / 2.0) + (n - 1) * hexW + (hexW / 2.0) + (hexW / 2.0) + 12;
|
|
// explication: largeur n colonnes + potentiel décalage d'une demi-largeur
|
|
|
|
double topY = margin - 12;
|
|
double bottomY = margin + s + (n - 1) * hexVStep + s + 12;
|
|
|
|
g2.setStroke(new BasicStroke(6f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
|
|
|
|
// Bleu: gauche / droite (objectif PLAYER1)
|
|
g2.setColor(new Color(30, 90, 160));
|
|
g2.drawLine((int) leftX, (int) topY, (int) leftX, (int) bottomY);
|
|
g2.drawLine((int) rightX, (int) topY, (int) rightX, (int) bottomY);
|
|
|
|
// Rouge: haut / bas (objectif PLAYER2)
|
|
g2.setColor(new Color(220, 50, 50));
|
|
g2.drawLine((int) leftX, (int) topY, (int) rightX, (int) topY);
|
|
g2.drawLine((int) leftX, (int) bottomY, (int) rightX, (int) bottomY);
|
|
}
|
|
}
|