import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.List; /** * Dient dem Aufbau der Matrix (Spielfeld) und füllt diese mit Funktion * @author Lucas Bronson, Luca Conte, Joshua Kuklok */ public class BoardDisplay extends JPanel { private JButton[][] fields; private int gridSize; private Ship currentShip; private Player player; private boolean horizontal = false; private List shipButtonList; private boolean enemyBoard; private Point mousePosition; /** * Fügt Buttons zu Liste hinzu und aktualisiert Feld durch Aufruf von paintFields * @param button Jeweiliger Button der hinzugefügt werden soll * @author Joshua Kuklok */ public void addShipButton(ShipButton button) { shipButtonList.add(button); paintFields(); } /** * Gibt currentShip zurück * @return currentShip Objekt der Klasse Schiff * @author Lucas Bronson Luca Conte */ public Ship getCurrentShip() { return currentShip; } /** * Konstruktor der startLocalGame. * @param gridSize Die Größe des Spielfelds * @param player Der Spieler * @author Lucas Bronson */ public BoardDisplay(int gridSize, Player player, boolean enemyBoard) { super(new GridLayout(gridSize + 1, gridSize + 1)); // +1 wegen extra Zeile/Spalte this.fields = new JButton[gridSize][gridSize]; this.shipButtonList = new ArrayList<>(); this.player = player; this.gridSize = gridSize; this.enemyBoard = enemyBoard; // Erstellung vom Spielfeld for (int i = 0; i <= gridSize; i++) { for (int j = 0; j <= gridSize; j++) { final int x = j - 1; // Temporäre Variable für überspringen von Rahmenzeile-/spalte final int y = i - 1; // Temporäre Variable für überspringen von Rahmenzeile-/spalte if (i == 0 && j == 0) { add(new JLabel(" ")); } else if (i == 0) { JLabel colLabel = new JLabel(String.valueOf(j)); colLabel.setHorizontalAlignment(SwingConstants.CENTER); colLabel.setFont(new Font("Roboto", Font.BOLD, 14)); add(colLabel); } else if (j == 0) { JLabel rowLabel = new JLabel(String.valueOf((char) ('A' + i - 1))); rowLabel.setHorizontalAlignment(SwingConstants.CENTER); rowLabel.setFont(new Font("Roboto", Font.BOLD, 14)); add(rowLabel); } else { // Spielfeld (interaktive Zellen) JButton field = new JButton(""); field.setBackground(Color.BLUE); field.setOpaque(true); field.setBorderPainted(true); fields[x][y] = field; add(field); // Um Mausinteraktionen zu ermöglichen (Rechts/- Linksklick, Hover) field.addMouseListener(new MouseAdapter() { // Um beim "Hovern" Position zu setzten und weiterzugeben. @Override public void mouseEntered(MouseEvent e) { mousePosition = new Point(x, y); paintFields(); } // Um nach "wegbewegen" der Maus wieder zu entfärben @Override public void mouseExited(MouseEvent e) { paintFields(); } // Um Schiffe zu rotieren/platzieren @Override public void mouseClicked(MouseEvent e) { if (SwingUtilities.isRightMouseButton(e)) { togglePlacementDirection(); } else if (SwingUtilities.isLeftMouseButton(e)) { Point o = new Point(x, y); handleFieldClick(o); SoundHandler.playSound("plop"); } } }); } } } } /** * Aktuelles Schiff auswählen * @param ship Schiff zum Auswählen * @author Lucas Bronson, Joshua Kuklok */ public void selectCurrentShip(Ship ship) { this.currentShip = ship; paintFields(); } /** * Zurücksetzen von aktuellem Schiff und allen Schiffen des Spielers. * Danach blau färben des Spielfeldes * @author Lucas Bronson, Joshua Kuklok */ public void resetAllShips() { this.currentShip = null; for (Ship ship : player.getBoard().getShips()) { ship.resetPosition(); } paintFields(); } /** * Wechselt die Platzierungsrichtung zwischen horizontal und vertikal. * @author Lucas Bronson, Joshua Kuklok */ private void togglePlacementDirection() { horizontal = !horizontal; String direction = horizontal ? "horizontal" : "vertikal"; System.out.println("Platzierungsrichtung geändert zu: " + direction); paintFields(); } /** * Handhabt das Platzieren eines Schiffs auf dem Spielfeld. * @param o Die Koordinaten des Klicks. * @author Lucas Bronson, Luca Conte */ private void handleFieldClick(Point o) { System.out.println("CLICK " + o); if (!this.enemyBoard && !this.player.isGameRunning() && !this.player.isReady()) { this.currentShip.setPosition(o, horizontal, player.getBoard().getShips(),this.gridSize); } if (this.enemyBoard && this.player.isGameRunning() && this.player.enemy.myTurn) { this.player.enemy.shoot(o); } paintFields(); } /** * Färbt das Spielfeld blau, überprüft, ob das aktuelle Schiff null ist. * Färbt eine Preview in das Spielfeld ein, ob Schiff setzen möglich ist * Schiffe die gesetzt wurden, werden grau gefärbt * Aufrufen von refreshButtonState um zu zeigen, ob Button drückbar ist * @author Lucas Bronson, Luca Conte, Joshua Kuklok */ public void paintFields() { List test=new ArrayList<>(); if(currentShip != null) { test = currentShip.getVirtualOccupiedPoints(mousePosition, horizontal); } for(int i = 0; i < gridSize; i++) { for(int j = 0; j < gridSize; j++) { if(fields[i][j] == null) { continue; } if (this.enemyBoard) { // enemy board only accessible if game is running AND it's "enemy's" so local player's turn if (!this.player.isGameRunning() || !this.player.enemy.myTurn) { fields[i][j].setEnabled(false); } else { fields[i][j].setEnabled(true); } } else { if (this.player.isGameRunning() || this.player.isReady()) { fields[i][j].setEnabled(false); } else { fields[i][j].setEnabled(true); } } if (this.enemyBoard) { fields[i][j].setBackground(Color.WHITE); } else { fields[i][j].setBackground(Color.BLUE); } if (!this.player.isReady()) { for(Point p : test) { if(i==p.getX() && j==p.getY()) { if (currentShip.checkValidPlacement(mousePosition,horizontal,player.getBoard().getShips(),gridSize)) { fields[i][j].setBackground(Color.GREEN); } else { fields[i][j].setBackground(Color.RED); } } } } for(Ship ship: player.getBoard().getShips()) { if(ship.isShipOnPos(new Point(i,j))) { fields[i][j].setBackground(Color.WHITE); } } HitResponse hit = this.player.getBoard().getHitResponseOnPoint(new Point(i, j)); if (hit != null) { switch (hit.getType()) { case HIT: fields[i][j].setBackground(Color.ORANGE); //SoundHandler.playSound("hit"); break; case SUNK: //SoundHandler.playSound("destroyed"); case VICTORY: fields[i][j].setBackground(Color.RED); break; case MISS: if (this.enemyBoard) { //SoundHandler.playSound("miss"); fields[i][j].setBackground(Color.BLUE); } else { fields[i][j].setBackground(Color.CYAN); } break; } } } } for( ShipButton shipButton: shipButtonList) { shipButton.refreshButtonState(); } } /** * Ruft paintFields auf, um Felder zu aktualisieren * @author Luca Conte */ public void refresh() { paintFields(); } }