mirror of
https://github.com/2OOP/pism.git
synced 2026-02-04 10:54:51 +00:00
Merge remote-tracking branch 'origin/UI' into UI
# Conflicts: # app/src/main/java/org/toop/app/App.java # app/src/main/java/org/toop/app/menu/MainMenu.java # app/src/main/java/org/toop/app/menu/game/GameMenu.java
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package org.toop.app;
|
||||
|
||||
import org.toop.app.canvas.TicTacToeCanvas;
|
||||
import javafx.application.Platform;
|
||||
import org.toop.app.menu.MainMenu;
|
||||
import org.toop.app.menu.Menu;
|
||||
@@ -57,7 +58,6 @@ public final class App extends Application {
|
||||
|
||||
pane = new StackPane(background, box);
|
||||
pane.getStylesheets().add(ResourceManager.get(CssAsset.class, "quit.css").getUrl());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ public final class App extends Application {
|
||||
final StackPane root = new StackPane(new MainMenu().getPane());
|
||||
|
||||
final Scene scene = new Scene(root);
|
||||
scene.getStylesheets().add(((CssAsset) ResourceManager.get("app.css")).getUrl());
|
||||
scene.getStylesheets().add(ResourceManager.get(CssAsset.class, "app.css").getUrl());
|
||||
|
||||
stage.setTitle(loc.getString("windowTitle",currentLocale));
|
||||
stage.setMinWidth(1080);
|
||||
@@ -95,10 +95,16 @@ public final class App extends Application {
|
||||
App.width = (int)stage.getWidth();
|
||||
App.height = (int)stage.getHeight();
|
||||
|
||||
App.isQuitting = false;
|
||||
|
||||
new EventFlow().addPostEvent(new AudioEvents.StartBackgroundMusic()).asyncPostEvent();
|
||||
new EventFlow().addPostEvent(new AudioEvents.ChangeVolume(0.1)).asyncPostEvent();
|
||||
|
||||
App.isQuitting = false;
|
||||
// Todo: Temp Obviously
|
||||
// Replace with game of life
|
||||
final TicTacToeCanvas canvas = new TicTacToeCanvas();
|
||||
root.getChildren().addLast(canvas.getCanvas());
|
||||
|
||||
try {
|
||||
new EventFlow()
|
||||
.listen(this::handleChangeLanguage);
|
||||
@@ -117,6 +123,8 @@ public final class App extends Application {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void quitPopup() {
|
||||
isQuitting = true;
|
||||
push(new QuitMenu());
|
||||
|
||||
77
app/src/main/java/org/toop/app/canvas/GameCanvas.java
Normal file
77
app/src/main/java/org/toop/app/canvas/GameCanvas.java
Normal file
@@ -0,0 +1,77 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import javafx.scene.canvas.Canvas;
|
||||
import javafx.scene.canvas.GraphicsContext;
|
||||
import javafx.scene.input.MouseButton;
|
||||
|
||||
public abstract class GameCanvas {
|
||||
protected record Cell(float x, float y, float width, float height) {}
|
||||
|
||||
protected final int width;
|
||||
protected final int height;
|
||||
|
||||
protected final Canvas canvas;
|
||||
protected final GraphicsContext graphics;
|
||||
|
||||
protected final int rows;
|
||||
protected final int columns;
|
||||
|
||||
protected final int gapSize;
|
||||
|
||||
protected final Cell[] cells;
|
||||
|
||||
protected GameCanvas(int width, int height, int rows, int columns, int gapSize) {
|
||||
final Canvas canvas = new Canvas(width, height);
|
||||
final GraphicsContext graphics = canvas.getGraphicsContext2D();
|
||||
|
||||
final Cell[] cells = new Cell[rows * columns];
|
||||
|
||||
final float cellWidth = ((float)width - (rows - 1) * gapSize) / rows;
|
||||
final float cellHeight = ((float)height - (columns - 1) * gapSize) / columns;
|
||||
|
||||
for (int y = 0; y < columns; y++) {
|
||||
final float startY = y * cellHeight + y * gapSize;
|
||||
|
||||
for (int x = 0; x < rows; x++) {
|
||||
final float startX = x * cellWidth + x * gapSize;
|
||||
cells[y * rows + x] = new Cell(startX, startY, cellWidth, cellHeight);
|
||||
}
|
||||
}
|
||||
|
||||
canvas.setOnMouseClicked(event -> {
|
||||
final MouseButton button = event.getButton();
|
||||
|
||||
if (button != MouseButton.PRIMARY && button != MouseButton.SECONDARY) {
|
||||
return;
|
||||
}
|
||||
|
||||
final int column = (int)((event.getX() / width) * rows);
|
||||
final int row = (int)((event.getY() / height) * columns);
|
||||
|
||||
event.consume();
|
||||
onCellClicked(row * rows + column, button == MouseButton.PRIMARY);
|
||||
});
|
||||
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
this.canvas = canvas;
|
||||
this.graphics = graphics;
|
||||
|
||||
this.rows = rows;
|
||||
this.columns = columns;
|
||||
|
||||
this.gapSize = gapSize;
|
||||
|
||||
this.cells = cells;
|
||||
}
|
||||
|
||||
protected void clearCell(int cell) {
|
||||
assert cell >= 0 && cell < cells.length;
|
||||
graphics.clearRect(cells[cell].x(), cells[cell].y(), cells[cell].width(), cells[cell].height());
|
||||
}
|
||||
|
||||
protected abstract void onCellClicked(int cell, boolean primary);
|
||||
|
||||
public Canvas getCanvas() { return canvas; }
|
||||
}
|
||||
81
app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java
Normal file
81
app/src/main/java/org/toop/app/canvas/TicTacToeCanvas.java
Normal file
@@ -0,0 +1,81 @@
|
||||
package org.toop.app.canvas;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import org.toop.app.App;
|
||||
import org.toop.game.Game;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
|
||||
public class TicTacToeCanvas extends GameCanvas {
|
||||
private final TicTacToe game;
|
||||
|
||||
public TicTacToeCanvas() {
|
||||
super(App.getHeight(), App.getHeight(), 3, 3, 10);
|
||||
game = new TicTacToe();
|
||||
|
||||
graphics.setFill(Color.CYAN);
|
||||
|
||||
for (int x = 1; x < rows; x++) {
|
||||
graphics.fillRect(cells[x].x() - gapSize, 0, gapSize, height);
|
||||
}
|
||||
|
||||
for (int y = 1; y < columns; y++) {
|
||||
graphics.fillRect(0, cells[y * rows].y() - gapSize, width, gapSize);
|
||||
}
|
||||
}
|
||||
|
||||
public void placeX(int cell) {
|
||||
graphics.setStroke(Color.ORANGERED);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
graphics.strokeLine(x, y, x + width, y + height);
|
||||
graphics.strokeLine(x + width, y, x, y + height);
|
||||
}
|
||||
|
||||
public void placeO(int cell) {
|
||||
graphics.setStroke(Color.DEEPSKYBLUE);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x() + gapSize;
|
||||
final float y = cells[cell].y() + gapSize;
|
||||
|
||||
final float width = cells[cell].width() - gapSize * 2;
|
||||
final float height = cells[cell].height() - gapSize * 2;
|
||||
|
||||
graphics.strokeOval(x, y, width, height);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCellClicked(int cell, boolean primary) {
|
||||
for (final Game.Move move : game.getLegalMoves()) {
|
||||
if (move.position() == cell) {
|
||||
if (move.value() == 'X') {
|
||||
placeX(cell);
|
||||
} else {
|
||||
placeO(cell);
|
||||
}
|
||||
|
||||
final Game.State state = game.play(move);
|
||||
|
||||
if (state == Game.State.WIN) {
|
||||
graphics.setFill(Color.GREEN);
|
||||
graphics.fillRect(cells[4].x(), cells[4].y(), cells[4].width(), cells[4].height());
|
||||
|
||||
for (int i = 0; i < game.board.length; i++) {
|
||||
if (game.board[i] != move.value()) {
|
||||
clearCell(i);
|
||||
}
|
||||
}
|
||||
} else if (state == Game.State.DRAW) {
|
||||
graphics.setFill(Color.DARKORANGE);
|
||||
graphics.fillRect(cells[4].x(), cells[4].y(), cells[4].width(), cells[4].height());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public final class MainMenu extends Menu {
|
||||
public MainMenu() {
|
||||
final Region background = createBackground();
|
||||
|
||||
tictactoe = createButton(loc.getString("mainMenuSelectTicTacToe",currentLocale), () -> { App.activate(new TicTacToeMenu(new TicTacToe("player 1", true, "player 2", true))); });
|
||||
tictactoe = createButton(loc.getString("mainMenuSelectTicTacToe",currentLocale), () -> { App.activate(new GameSelectMenu(GameType.TICTACTOE)); });
|
||||
reversi = createButton(loc.getString("mainMenuSelectReversi",currentLocale), () -> { App.activate(new GameSelectMenu(GameType.REVERSI)); });
|
||||
|
||||
final VBox gamesBox = new VBox(10, tictactoe, reversi);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package org.toop.app.menu;
|
||||
|
||||
import javafx.scene.Node;
|
||||
import javafx.scene.control.Button;
|
||||
import javafx.scene.layout.Pane;
|
||||
import javafx.scene.layout.Region;
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
package org.toop.app.menu.game;
|
||||
|
||||
import javafx.scene.paint.Color;
|
||||
import org.toop.game.Game;
|
||||
import org.toop.game.Player;
|
||||
import org.toop.game.tictactoe.TicTacToe;
|
||||
import org.toop.game.tictactoe.TicTacToeAI;
|
||||
|
||||
import javax.management.RuntimeErrorException;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public final class TicTacToeMenu extends GameMenu {
|
||||
private final TicTacToe game;
|
||||
private final TicTacToeAI ai;
|
||||
|
||||
// private final ExecutorService executor = Executors.newFixedThreadPool(1);
|
||||
private final BlockingQueue<Game.Move> moveQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
public TicTacToeMenu(TicTacToe game) {
|
||||
super(3, 3, 10);
|
||||
|
||||
graphics.setFill(Color.CYAN);
|
||||
|
||||
for (int x = 1; x < rows; x++) {
|
||||
graphics.fillRect(cells[x].x - gapSize, 0, gapSize, size);
|
||||
}
|
||||
|
||||
for (int y = 1; y < columns; y++) {
|
||||
graphics.fillRect(0, cells[y * rows].y - gapSize, size, gapSize);
|
||||
}
|
||||
|
||||
this.game = game;
|
||||
ai = new TicTacToeAI();
|
||||
|
||||
canvas.setOnMouseClicked(event -> {
|
||||
for (int i = 0; i < cells.length; i++) {
|
||||
if (cells[i].check((float) event.getX(), (float) event.getY())) {
|
||||
final Game.Move move = new Game.Move(i, game.getCurrentPlayer().values()[0]);
|
||||
play(move);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
new Thread(this::gameThread).start();
|
||||
}
|
||||
|
||||
private void play(Game.Move move) {
|
||||
final Game.Move[] legalMoves = game.getLegalMoves();
|
||||
|
||||
boolean isLegal = false;
|
||||
|
||||
for (final Game.Move legalMove : legalMoves) {
|
||||
if (legalMove.position() == move.position() && legalMove.value() == move.value()) {
|
||||
isLegal = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isLegal) {
|
||||
return;
|
||||
}
|
||||
|
||||
try { moveQueue.put(move); }
|
||||
catch (InterruptedException _) {}
|
||||
}
|
||||
|
||||
private void placeX(int cell) {
|
||||
graphics.setStroke(Color.ORANGERED);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x + gapSize;
|
||||
final float y = cells[cell].y + gapSize;
|
||||
|
||||
final float width = cells[cell].width - gapSize * 2;
|
||||
final float height = cells[cell].height - gapSize * 2;
|
||||
|
||||
graphics.strokeLine(x, y, x + width, y + height);
|
||||
graphics.strokeLine(x + width, y, x, y + height);
|
||||
}
|
||||
|
||||
private void placeO(int cell) {
|
||||
graphics.setStroke(Color.DEEPSKYBLUE);
|
||||
graphics.setLineWidth(gapSize);
|
||||
|
||||
final float x = cells[cell].x + gapSize;
|
||||
final float y = cells[cell].y + gapSize;
|
||||
|
||||
final float width = cells[cell].width - gapSize * 2;
|
||||
final float height = cells[cell].height - gapSize * 2;
|
||||
|
||||
graphics.strokeOval(x, y, width, height);
|
||||
}
|
||||
|
||||
private void gameThread() {
|
||||
boolean running = true;
|
||||
|
||||
while(running) {
|
||||
final Player currentPlayer = game.getCurrentPlayer();
|
||||
|
||||
try {
|
||||
Game.Move move;
|
||||
|
||||
if (!currentPlayer.isAI()) {
|
||||
try { move = moveQueue.take(); }
|
||||
catch (InterruptedException _) { return; }
|
||||
} else {
|
||||
move = ai.findBestMove(game, 9);
|
||||
}
|
||||
|
||||
assert move != null;
|
||||
final Game.State state = game.play(move);
|
||||
|
||||
if (move.value() == 'X') {
|
||||
placeX(move.position());
|
||||
} else {
|
||||
placeO(move.position());
|
||||
}
|
||||
|
||||
switch (state) {
|
||||
case NORMAL: break;
|
||||
|
||||
case DRAW:
|
||||
case LOSE:
|
||||
case WIN:
|
||||
running = false;
|
||||
break;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ public class AppContext {
|
||||
currentLocale = locale;
|
||||
new EventFlow().addPostEvent(new LocalizationEvents.LanguageHasChanged(locale.getLanguage())).asyncPostEvent();
|
||||
}
|
||||
|
||||
public static Locale getLocale() {
|
||||
return currentLocale;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
windowTitle=ISY Games Selector
|
||||
|
||||
# Main Menu buttons
|
||||
mainMenuSelectTicTacToe=Tic Tac Toe
|
||||
mainMenuSelectReversi=Reversi
|
||||
mainMenuSelectTicTacToe=Tic Tac Toe\u5426
|
||||
mainMenuSelectReversi=Reversi\u5426
|
||||
mainMenuSelectSudoku=Sudoku
|
||||
mainMenuSelectBattleship=Battleship
|
||||
mainMenuSelectOther=Other
|
||||
|
||||
Reference in New Issue
Block a user