cool onhover effect for reversi

This commit is contained in:
Ticho Hidding
2025-10-29 14:06:05 +01:00
parent 3a51434f91
commit 7f36d7f244
5 changed files with 115 additions and 9 deletions

View File

@@ -6,6 +6,6 @@ import java.util.function.Consumer;
public class Connect4Canvas extends GameCanvas { public class Connect4Canvas extends GameCanvas {
public Connect4Canvas(Color color, int width, int height, Consumer<Integer> onCellClicked) { public Connect4Canvas(Color color, int width, int height, Consumer<Integer> onCellClicked) {
super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked); super(color, Color.TRANSPARENT, width, height, 7, 6, 10, true, onCellClicked,null);
} }
} }

View File

@@ -8,6 +8,7 @@ import javafx.scene.input.MouseButton;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import javafx.util.Duration; import javafx.util.Duration;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer; import java.util.function.Consumer;
public abstract class GameCanvas { public abstract class GameCanvas {
@@ -35,7 +36,7 @@ public abstract class GameCanvas {
protected final Cell[] cells; protected final Cell[] cells;
protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer<Integer> onCellClicked) { protected GameCanvas(Color color, Color backgroundColor, int width, int height, int rowSize, int columnSize, int gapSize, boolean edges, Consumer<Integer> onCellClicked, Consumer<Integer> newCellEntered) {
canvas = new Canvas(width, height); canvas = new Canvas(width, height);
graphics = canvas.getGraphicsContext2D(); graphics = canvas.getGraphicsContext2D();
@@ -81,6 +82,9 @@ public abstract class GameCanvas {
} }
}); });
render(); render();
} }
@@ -150,6 +154,21 @@ public abstract class GameCanvas {
graphics.fillOval(x, y, width, height); 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) { private void drawDotScaled(Color color, int cell, double scale) {
final float cx = cells[cell].x() + gapSize; final float cx = cells[cell].x() + gapSize;
final float cy = cells[cell].y() + gapSize; final float cy = cells[cell].y() + gapSize;

View File

@@ -1,15 +1,68 @@
package org.toop.app.canvas; package org.toop.app.canvas;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import org.toop.game.Game;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer; import java.util.function.Consumer;
public final class ReversiCanvas extends GameCanvas { public final class ReversiCanvas extends GameCanvas {
public ReversiCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) { private Game.Move[] currentlyHighlightedMoves = null;
super(color, Color.GREEN, width, height, 8, 8, 5, true, onCellClicked); public ReversiCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked, Consumer<Integer> newCellEntered) {
super(color, new Color(0f,0.4f,0.2f,1f), width, height, 8, 8, 5, true, onCellClicked, newCellEntered);
drawStartingDots(); drawStartingDots();
final AtomicReference<Cell> 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() { public void drawStartingDots() {
drawDot(Color.BLACK, 28); drawDot(Color.BLACK, 28);
drawDot(Color.WHITE, 36); drawDot(Color.WHITE, 36);
@@ -17,7 +70,15 @@ public final class ReversiCanvas extends GameCanvas {
drawDot(Color.WHITE, 27); drawDot(Color.WHITE, 27);
} }
public void drawLegalPosition(int cell) { public void drawLegalPosition(int cell, char player) {
drawDot(new Color(1.0f, 0.0f, 0.0f, 0.5f), cell);
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);
} }
} }

View File

@@ -6,7 +6,7 @@ import java.util.function.Consumer;
public final class TicTacToeCanvas extends GameCanvas { public final class TicTacToeCanvas extends GameCanvas {
public TicTacToeCanvas(Color color, int width, int height, Consumer<Integer> onCellClicked) { public TicTacToeCanvas(Color color, int width, int height, Consumer<Integer> 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) { public void drawX(Color color, int cell) {

View File

@@ -16,6 +16,7 @@ import org.toop.game.reversi.ReversiAI;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.paint.Color; import javafx.scene.paint.Color;
import java.awt.*;
import java.util.concurrent.BlockingQueue; import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -82,7 +83,9 @@ public final class ReversiGame {
} catch (InterruptedException _) {} } catch (InterruptedException _) {}
} }
} }
}); },this::highlightCells);
view.add(Pos.CENTER, canvas.getCanvas()); view.add(Pos.CENTER, canvas.getCanvas());
ViewStack.push(view); ViewStack.push(view);
@@ -159,6 +162,7 @@ public final class ReversiGame {
continue; continue;
} }
canvas.setCurrentlyHighlightedMovesNull();
final Game.State state = game.play(move); final Game.State state = game.play(move);
updateCanvas(true); updateCanvas(true);
@@ -285,7 +289,7 @@ public final class ReversiGame {
final Game.Move[] legalMoves = game.getLegalMoves(); final Game.Move[] legalMoves = game.getLegalMoves();
for (final Game.Move legalMove : legalMoves) { 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, currentValue,
information.players[isMe? 1 : 0].name); 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);
}
}
} }