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); } }