From 7f36d7f244470f139e93bcee9324a3ff490b7353 Mon Sep 17 00:00:00 2001 From: Ticho Hidding Date: Wed, 29 Oct 2025 14:06:05 +0100 Subject: [PATCH] cool onhover effect for reversi --- .../org/toop/app/canvas/Connect4Canvas.java | 2 +- .../java/org/toop/app/canvas/GameCanvas.java | 21 +++++- .../org/toop/app/canvas/ReversiCanvas.java | 69 +++++++++++++++++-- .../org/toop/app/canvas/TicTacToeCanvas.java | 2 +- .../java/org/toop/app/game/ReversiGame.java | 30 +++++++- 5 files changed, 115 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/toop/app/canvas/Connect4Canvas.java b/app/src/main/java/org/toop/app/canvas/Connect4Canvas.java index 913bb62..c17dafd 100644 --- a/app/src/main/java/org/toop/app/canvas/Connect4Canvas.java +++ b/app/src/main/java/org/toop/app/canvas/Connect4Canvas.java @@ -6,6 +6,6 @@ import java.util.function.Consumer; public class Connect4Canvas extends GameCanvas { public Connect4Canvas(Color color, int width, int height, Consumer onCellClicked) { - super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked); + super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked,null); } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/canvas/GameCanvas.java b/app/src/main/java/org/toop/app/canvas/GameCanvas.java index 1a002a6..f8f6d70 100644 --- a/app/src/main/java/org/toop/app/canvas/GameCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/GameCanvas.java @@ -8,6 +8,7 @@ import javafx.scene.input.MouseButton; import javafx.scene.paint.Color; import javafx.util.Duration; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; public abstract class GameCanvas { @@ -35,7 +36,7 @@ public abstract class GameCanvas { protected final Cell[] cells; - protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer onCellClicked) { + protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer onCellClicked, Consumer newCellEntered) { canvas = new Canvas(width, height); graphics = canvas.getGraphicsContext2D(); @@ -81,6 +82,9 @@ public abstract class GameCanvas { } }); + + + render(); } @@ -150,6 +154,21 @@ public abstract class GameCanvas { graphics.fillOval(x, y, width, height); } + public void drawInnerDot(Color color, int cell, boolean slightlyBigger) { + final float x = cells[cell].x() + gapSize; + final float y = cells[cell].y() + gapSize; + + float multiplier = slightlyBigger?1.4f:1.5f; + + final float width = (cells[cell].width() - gapSize * 2)/multiplier; + final float height = (cells[cell].height() - gapSize * 2)/multiplier; + + float offset = slightlyBigger?5f:4f; + + graphics.setFill(color); + graphics.fillOval(x + width/offset, y + height/offset, width, height); + } + private void drawDotScaled(Color color, int cell, double scale) { final float cx = cells[cell].x() + gapSize; final float cy = cells[cell].y() + gapSize; diff --git a/app/src/main/java/org/toop/app/canvas/ReversiCanvas.java b/app/src/main/java/org/toop/app/canvas/ReversiCanvas.java index 8eec0ad..e22e054 100644 --- a/app/src/main/java/org/toop/app/canvas/ReversiCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/ReversiCanvas.java @@ -1,15 +1,68 @@ package org.toop.app.canvas; import javafx.scene.paint.Color; +import org.toop.game.Game; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; public final class ReversiCanvas extends GameCanvas { - public ReversiCanvas(Color color, int width, int height, Consumer onCellClicked) { - super(color, Color.GREEN, width, height, 8, 8, 5, true, onCellClicked); + private Game.Move[] currentlyHighlightedMoves = null; + public ReversiCanvas(Color color, int width, int height, Consumer onCellClicked, Consumer newCellEntered) { + super(color, new Color(0f,0.4f,0.2f,1f), width, height, 8, 8, 5, true, onCellClicked, newCellEntered); drawStartingDots(); + + final AtomicReference lastHoveredCell = new AtomicReference<>(null); + + canvas.setOnMouseMoved(event -> { + double mouseX = event.getX(); + double mouseY = event.getY(); + int cellId = -1; + + Cell hovered = null; + for (Cell cell : cells) { + if (cell.isInside(mouseX, mouseY)) { + hovered = cell; + cellId = turnCoordsIntoCellId(mouseX, mouseY); + break; + } + } + + Cell previous = lastHoveredCell.get(); + + if (hovered != previous) { + lastHoveredCell.set(hovered); + newCellEntered.accept(cellId); + } + }); } + public void setCurrentlyHighlightedMovesNull() { + currentlyHighlightedMoves = null; + } + + public void drawHighlightDots(Game.Move[] moves){ + if (currentlyHighlightedMoves != null){ + for (final Game.Move move : currentlyHighlightedMoves){ + Color color = move.value() == 'W'? Color.BLACK: Color.WHITE; + drawInnerDot(color, move.position(), true); + } + } + currentlyHighlightedMoves = moves; + if (moves != null) { + for (Game.Move move : moves) { + Color color = move.value() == 'B' ? Color.BLACK : Color.WHITE; + drawInnerDot(color, move.position(), false); + } + } + } + + private int turnCoordsIntoCellId(double x, double y) { + final int column = (int) ((x / this.width) * rowSize); + final int row = (int) ((y / this.height) * columnSize); + return column + row * rowSize; + } + public void drawStartingDots() { drawDot(Color.BLACK, 28); drawDot(Color.WHITE, 36); @@ -17,7 +70,15 @@ public final class ReversiCanvas extends GameCanvas { drawDot(Color.WHITE, 27); } - public void drawLegalPosition(int cell) { - drawDot(new Color(1.0f, 0.0f, 0.0f, 0.5f), cell); + public void drawLegalPosition(int cell, char player) { + + Color innerColor; + if (player == 'B') { + innerColor = new Color(0.0f, 0.0f, 0.0f, 0.6f); + } + else { + innerColor = new Color(1.0f, 1.0f, 1.0f, 0.75f); + } + drawInnerDot(innerColor, cell,false); } } \ No newline at end of file diff --git a/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java b/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java index d7ccbc8..890eb39 100644 --- a/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java +++ b/app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java @@ -6,7 +6,7 @@ import java.util.function.Consumer; public final class TicTacToeCanvas extends GameCanvas { public TicTacToeCanvas(Color color, int width, int height, Consumer onCellClicked) { - super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked); + super(color, Color.TRANSPARENT, width, height, 3, 3, 30, false, onCellClicked,null); } public void drawX(Color color, int cell) { diff --git a/app/src/main/java/org/toop/app/game/ReversiGame.java b/app/src/main/java/org/toop/app/game/ReversiGame.java index 64f0b6c..2889280 100644 --- a/app/src/main/java/org/toop/app/game/ReversiGame.java +++ b/app/src/main/java/org/toop/app/game/ReversiGame.java @@ -16,6 +16,7 @@ import org.toop.game.reversi.ReversiAI; import javafx.geometry.Pos; import javafx.scene.paint.Color; +import java.awt.*; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; @@ -82,7 +83,9 @@ public final class ReversiGame { } catch (InterruptedException _) {} } } - }); + },this::highlightCells); + + view.add(Pos.CENTER, canvas.getCanvas()); ViewStack.push(view); @@ -159,6 +162,7 @@ public final class ReversiGame { continue; } + canvas.setCurrentlyHighlightedMovesNull(); final Game.State state = game.play(move); updateCanvas(true); @@ -285,7 +289,7 @@ public final class ReversiGame { final Game.Move[] legalMoves = game.getLegalMoves(); for (final Game.Move legalMove : legalMoves) { - canvas.drawLegalPosition(legalMove.position()); + canvas.drawLegalPosition(legalMove.position(), game.getCurrentPlayer()); } }); @@ -301,4 +305,26 @@ public final class ReversiGame { currentValue, information.players[isMe? 1 : 0].name); } + + private void highlightCells(int cellEntered) { + Game.Move[] legalMoves = game.getLegalMoves(); + boolean isLegalMove = false; + for (Game.Move move : legalMoves) { + if (move.position() == cellEntered){ + isLegalMove = true; + break; + } + } + + if (cellEntered >= 0){ + Game.Move[] moves = null; + if (isLegalMove) { + moves = game.getFlipsForPotentialMove( + new Point(cellEntered%game.columnSize,cellEntered/game.rowSize), + game.makeBoardAGrid(), + game.getCurrentPlayer()); + } + canvas.drawHighlightDots(moves); + } + } } \ No newline at end of file