From f10cdec09bf791c03061cff2f1ff236327bbb4b8 Mon Sep 17 00:00:00 2001 From: Matthew Grove Date: Sat, 22 Apr 2023 05:39:25 +0100 Subject: [PATCH] [FEAT] Show other players' boards in multiplayer --- .../ac/soton/comp1206/component/Chat.java | 3 +- .../soton/comp1206/component/GameBoard.java | 26 ++++++ .../soton/comp1206/component/Leaderboard.java | 1 + .../event/PlayerGameBoardListener.java | 18 +++++ .../mgrove/ac/soton/comp1206/game/Game.java | 26 +++++- .../mgrove/ac/soton/comp1206/game/Grid.java | 2 +- .../soton/comp1206/game/MultiplayerGame.java | 79 +++++++++++++++++-- .../soton/comp1206/scene/ChallengeScene.java | 25 +++++- .../ac/soton/comp1206/scene/LobbyScene.java | 30 ++++--- .../comp1206/scene/MultiplayerScene.java | 69 +++++++++++++++- .../ac/soton/comp1206/scene/ScoresScene.java | 19 +++-- src/main/resources/style/game.css | 8 ++ 12 files changed, 271 insertions(+), 35 deletions(-) create mode 100644 src/main/java/uk/mgrove/ac/soton/comp1206/event/PlayerGameBoardListener.java diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/component/Chat.java b/src/main/java/uk/mgrove/ac/soton/comp1206/component/Chat.java index fc8a39a..8a4ce85 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/component/Chat.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/component/Chat.java @@ -70,7 +70,8 @@ public class Chat extends VBox { messagesContainer.setContent(messages); messagesContainer.setFitToWidth(true); messagesContainer.setFitToHeight(true); - messagesContainer.setPrefHeight(320); + messagesContainer.setPrefHeight(280); + messagesContainer.setMaxHeight(280); messagesContainer.setHbarPolicy(ScrollPane.ScrollBarPolicy.NEVER); messagesContainer.setVvalue(1.0); messagesContainer.getStyleClass().add("scroller"); diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/component/GameBoard.java b/src/main/java/uk/mgrove/ac/soton/comp1206/component/GameBoard.java index 0e29b85..729f7f2 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/component/GameBoard.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/component/GameBoard.java @@ -1,5 +1,7 @@ package uk.mgrove.ac.soton.comp1206.component; +import javafx.beans.property.IntegerProperty; +import javafx.beans.property.SimpleIntegerProperty; import javafx.scene.input.MouseButton; import javafx.scene.input.MouseEvent; import javafx.scene.layout.GridPane; @@ -199,6 +201,14 @@ public class GameBoard extends GridPane { return block; } + /** + * Get grid value property + * @return properties for value of block at given location in grid + */ + public IntegerProperty getGridProperty(int x, int y) { + return grid.getGridProperty(x,y); + } + /** * Set the listener to handle an event when a block is clicked * @param listener listener to add @@ -305,4 +315,20 @@ public class GameBoard extends GridPane { currentPiece = newPiece; } + /** + * Get current game piece + * @return current piece + */ + public GamePiece getCurrentPiece() { + return currentPiece; + } + + /** + * Set whether board should be focussable + * @param enableFocus whether board should be focussable + */ + public void enableFocus(boolean enableFocus) { + this.enableFocus = enableFocus; + } + } diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/component/Leaderboard.java b/src/main/java/uk/mgrove/ac/soton/comp1206/component/Leaderboard.java index 4056c40..f952e45 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/component/Leaderboard.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/component/Leaderboard.java @@ -33,6 +33,7 @@ public class Leaderboard extends ScoresList { title = new Text(titleText); title.getStyleClass().add("heading"); getChildren().add(title); + setSpacing(4); reveal(); scores.addListener((ListChangeListener>>) change -> Platform.runLater(() -> { diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/event/PlayerGameBoardListener.java b/src/main/java/uk/mgrove/ac/soton/comp1206/event/PlayerGameBoardListener.java new file mode 100644 index 0000000..77c6d14 --- /dev/null +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/event/PlayerGameBoardListener.java @@ -0,0 +1,18 @@ +package uk.mgrove.ac.soton.comp1206.event; + +import javafx.beans.property.SimpleIntegerProperty; +import uk.mgrove.ac.soton.comp1206.component.GameBoard; + +/** + * Listener for player game boards + */ +public interface PlayerGameBoardListener { + + /** + * Action the listener with details of the board + * @param username player's username + * @param gridProperties properties for board grid contents + */ + void add(String username, SimpleIntegerProperty[][] gridProperties); + +} diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/game/Game.java b/src/main/java/uk/mgrove/ac/soton/comp1206/game/Game.java index 6210b57..4e07d80 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/game/Game.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/game/Game.java @@ -4,6 +4,7 @@ import javafx.application.Platform; import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleMapProperty; import javafx.util.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -96,7 +97,12 @@ public class Game { /** * Listener for showing scores scene */ - private ShowScoresSceneListener showScoresListener; + protected ShowScoresSceneListener showScoresListener; + + /** + * Listener for when new player board is added + */ + protected PlayerGameBoardListener playerBoardAddedListener; /** * Create a new game with the specified rows and columns. Creates a corresponding grid model. @@ -167,7 +173,7 @@ public class Game { /** * Game loop - ongoing time-based functionality */ - private void gameLoop() { + protected void gameLoop() { logger.info("Executing game loop"); setLives(getLives() - 1); nextPiece(); @@ -512,6 +518,22 @@ public class Game { return null; } + /** + * Get the player boards property - always null in this class + * @return property for player boards + */ + public SimpleMapProperty playerBoardsProperty() { + return null; + } + + /** + * Set listener for when new player board is added + * @param listener + */ + public void setOnPlayerBoardAdded(PlayerGameBoardListener listener) { + this.playerBoardAddedListener = listener; + } + /** * Set listener for game failure - but in this class does nothing * @param listener listener to set diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/game/Grid.java b/src/main/java/uk/mgrove/ac/soton/comp1206/game/Grid.java index ebe772b..a257731 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/game/Grid.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/game/Grid.java @@ -207,7 +207,7 @@ public class Grid { * @param y y-coordinate of piece centre */ public void previewPiece(GamePiece piece, int x, int y) { - if (!canPlayPiece(piece, x, y)) return; + if (piece == null || !canPlayPiece(piece, x, y)) return; logger.info("Previewing piece {} at {},{}", piece, x, y); int value = piece.getValue(); diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/game/MultiplayerGame.java b/src/main/java/uk/mgrove/ac/soton/comp1206/game/MultiplayerGame.java index 44199db..3873127 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/game/MultiplayerGame.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/game/MultiplayerGame.java @@ -1,16 +1,25 @@ package uk.mgrove.ac.soton.comp1206.game; import javafx.application.Platform; +import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleListProperty; +import javafx.beans.property.SimpleMapProperty; import javafx.collections.FXCollections; +import javafx.geometry.Pos; import javafx.scene.control.Alert; +import javafx.scene.layout.VBox; +import javafx.scene.text.Text; +import javafx.scene.text.TextAlignment; import javafx.util.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import uk.mgrove.ac.soton.comp1206.event.GameFailureListener; import uk.mgrove.ac.soton.comp1206.network.Communicator; +import uk.mgrove.ac.soton.comp1206.util.Multimedia; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import java.util.Scanner; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; @@ -33,15 +42,20 @@ public class MultiplayerGame extends Game { private final BlockingQueue pieceQueue = new LinkedBlockingQueue<>(); /** - * Scores for the leaderboard + * Scores for the leaderboard, with structure username, score, lives */ - private final SimpleListProperty>> leaderboardScores = new SimpleListProperty<>(FXCollections.observableArrayList(new ArrayList<>())); + private final SimpleListProperty>> leaderboardScores = new SimpleListProperty<>(FXCollections.observableArrayList()); /** * Listener for game failing */ private GameFailureListener gameFailureListener; + /** + * Mapping of usernames to player boards + */ + private final SimpleMapProperty playerBoards = new SimpleMapProperty<>(FXCollections.observableHashMap()); + /** * Create a new game with the specified rows and columns. Creates a corresponding grid model. * @@ -125,11 +139,34 @@ public class MultiplayerGame extends Game { break; } } + } else if (message.startsWith("BOARD ")) { + var info = message.replaceFirst("BOARD ", "").split(":"); + var gridValues = info[1].split(" "); + if (playerBoards.containsKey(info[0])) { + logger.info("Updating board for: {}", info[0]); + for (var x = 0; x < playerBoards.get(info[0]).length; x++) { + for (var y = 0; y < playerBoards.get(info[0])[0].length; y++) { + playerBoards.get(info[0])[x][y].set(Integer.parseInt(gridValues[playerBoards.get(info[0])[0].length * x + y])); + } + } + } else { + logger.info("Adding board for: {}", info[0]); + var dimensions = (int) Math.sqrt(gridValues.length); + SimpleIntegerProperty[][] newProperties = new SimpleIntegerProperty[dimensions][dimensions]; + for (var x = 0; x < dimensions; x++) { + for (var y = 0; y < dimensions; y++) { + newProperties[x][y] = new SimpleIntegerProperty(Integer.parseInt(gridValues[grid.getCols() * x + y])); + } + } + playerBoards.put(info[0], newProperties); + if (playerBoardAddedListener != null) playerBoardAddedListener.add(info[0], newProperties); + } + logger.info("Player boards: {}", playerBoards.get()); } } /** - * Parse high scores from a string to list property + * Parse high scores from a string to list property, with structure username, score, lives * @param data string to parse from * @return list property containing scores loaded */ @@ -141,7 +178,7 @@ public class MultiplayerGame extends Game { while (scanner.hasNextLine()) { var line = scanner.nextLine(); - if (line.matches("^.+:[0-9]+:([0-9]+|DEAD)$")) { + if (line.matches("^.+:[0-9]+:((-?[0-9]+)|DEAD)$")) { var info = line.split(":"); var lives = info[2].equals("DEAD") ? -1 : Integer.parseInt(info[2]); scores.add(new Pair<>(info[0], new Pair<>(Integer.valueOf(info[1]), lives))); @@ -162,15 +199,41 @@ public class MultiplayerGame extends Game { } /** - * End game + * Get the player boards property + * @return property for player boards */ - @Override - public void endGame() { - super.endGame(); + public SimpleMapProperty playerBoardsProperty() { + return playerBoards; + } + + /** + * Notify server that player is dead + */ + private void die() { logger.info("Sending die message to server"); communicator.send("DIE"); } + /** + * Game loop - ongoing time-based functionality + */ + @Override + protected void gameLoop() { + logger.info("Executing game loop"); + setLives(getLives() - 1); + nextPiece(); + setMultiplier(1); + Multimedia.playAudio("sounds/lifelose.wav"); + + if(getLives() < 0) { + die(); + logger.info("Ending game"); + endGame(); + if (showScoresListener != null) Platform.runLater(() -> showScoresListener.show(this)); + } + else scheduleGameLoop(); + } + /** * Update the score, multiplier, and level depending on the number of lines and blocks that have been cleared * @param lines number of lines cleared diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/scene/ChallengeScene.java b/src/main/java/uk/mgrove/ac/soton/comp1206/scene/ChallengeScene.java index 5b043d0..ac42970 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/scene/ChallengeScene.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/scene/ChallengeScene.java @@ -78,6 +78,11 @@ public class ChallengeScene extends BaseScene { */ protected final IntegerProperty highScore = new SimpleIntegerProperty(0); + /** + * Main stack pane for scene + */ + protected StackPane challengePane; + /** * Create a new Single Player challenge scene * @param gameWindow the Game Window @@ -98,7 +103,7 @@ public class ChallengeScene extends BaseScene { root = new GamePane(gameWindow.getWidth(),gameWindow.getHeight()); - var challengePane = new StackPane(); + challengePane = new StackPane(); challengePane.setMaxWidth(gameWindow.getWidth()); challengePane.setMaxHeight(gameWindow.getHeight()); challengePane.getStyleClass().add("menu-background"); @@ -163,9 +168,21 @@ public class ChallengeScene extends BaseScene { switch (event.getCode()) { case ESCAPE -> returnToMenu(); case ENTER, X -> game.dropPiece(board.getXFocus(),board.getYFocus()); - case SPACE, R -> game.swapPieces(); - case OPEN_BRACKET, Q, Z -> game.rotateCurrentPieceAnticlockwise(); - case CLOSE_BRACKET, E, C -> game.rotateCurrentPiece(); + case SPACE, R -> { + game.swapPieces(); + game.getGrid().clearPreview(); + game.getGrid().previewPiece(board.getCurrentPiece(), board.getXFocus(), board.getYFocus()); + } + case OPEN_BRACKET, Q, Z -> { + game.rotateCurrentPieceAnticlockwise(); + game.getGrid().clearPreview(); + game.getGrid().previewPiece(board.getCurrentPiece(), board.getXFocus(), board.getYFocus()); + } + case CLOSE_BRACKET, E, C -> { + game.rotateCurrentPiece(); + game.getGrid().clearPreview(); + game.getGrid().previewPiece(board.getCurrentPiece(), board.getXFocus(), board.getYFocus()); + } case LEFT, A -> board.changeXFocus(-1); case RIGHT, D -> board.changeXFocus(1); case DOWN, S -> board.changeYFocus(1); diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/scene/LobbyScene.java b/src/main/java/uk/mgrove/ac/soton/comp1206/scene/LobbyScene.java index 0f2d682..43f0435 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/scene/LobbyScene.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/scene/LobbyScene.java @@ -79,6 +79,11 @@ public class LobbyScene extends BaseScene { */ private final HBox channelFunctionButtons = new HBox(); + /** + * Timer to request list of channels from server + */ + private Timer listChannelsRequest; + /** * Create a new scene, passing in the GameWindow the scene will be displayed in * @@ -143,7 +148,7 @@ public class LobbyScene extends BaseScene { gameWindow.getCommunicator().addListener(this::handleCommunicatorMessage); - var listChannelsRequest = new Timer("Request list of channels from communicator"); + listChannelsRequest = new Timer("Request list of channels from communicator"); listChannelsRequest.schedule(new TimerTask() { @Override public void run() { @@ -227,14 +232,16 @@ public class LobbyScene extends BaseScene { }); } else if (message.equals("HOST")) { logger.info("User is host of current channel"); - isChannelHost = true; - Platform.runLater(() -> { - logger.info("Current channel host status: {}", isChannelHost); - var startGame = new Text("Start game"); - startGame.getStyleClass().add("channelItem"); - startGame.setOnMouseClicked((event) -> gameWindow.getCommunicator().send("START")); - channelFunctionButtons.getChildren().add(0, startGame); - }); + if (!isChannelHost) { + isChannelHost = true; + Platform.runLater(() -> { + logger.info("Current channel host status: {}", isChannelHost); + var startGame = new Text("Start game"); + startGame.getStyleClass().add("channelItem"); + startGame.setOnMouseClicked((event) -> gameWindow.getCommunicator().send("START")); + channelFunctionButtons.getChildren().add(0, startGame); + }); + } } else if (message.matches("^NICK .+:.+$")) { Platform.runLater(() -> { var usernames = message.replaceFirst("NICK ", "").split(":"); @@ -255,7 +262,10 @@ public class LobbyScene extends BaseScene { }); } else if (message.equals("START")) { logger.info("Starting game"); - Platform.runLater(gameWindow::startMultiplayerGame); + Platform.runLater(() -> { + listChannelsRequest.cancel(); + gameWindow.startMultiplayerGame(); + }); } } diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/scene/MultiplayerScene.java b/src/main/java/uk/mgrove/ac/soton/comp1206/scene/MultiplayerScene.java index 5d5af9f..d13cdac 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/scene/MultiplayerScene.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/scene/MultiplayerScene.java @@ -1,9 +1,16 @@ package uk.mgrove.ac.soton.comp1206.scene; import javafx.application.Platform; +import javafx.beans.property.MapProperty; +import javafx.beans.property.SimpleIntegerProperty; +import javafx.beans.property.SimpleMapProperty; +import javafx.collections.FXCollections; +import javafx.geometry.Pos; import javafx.scene.control.Separator; +import javafx.scene.layout.GridPane; import javafx.scene.layout.VBox; import javafx.scene.text.Text; +import javafx.scene.text.TextAlignment; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import uk.mgrove.ac.soton.comp1206.component.*; @@ -30,6 +37,16 @@ public class MultiplayerScene extends ChallengeScene { */ private Leaderboard leaderboard; + /** + * Other players' live boards + */ + private MapProperty playerBoards = new SimpleMapProperty<>(FXCollections.observableHashMap()); + + /** + * Grid of other players' live boards + */ + private final GridPane playerBoardGrid = new GridPane(); + /** * Create a new multiplayer challenge scene * @@ -50,6 +67,36 @@ public class MultiplayerScene extends ChallengeScene { game = new MultiplayerGame(5, 5, gameWindow.getCommunicator()); game.setOnGameFail(() -> Platform.runLater(gameWindow::startMenu)); + game.setOnPlayerBoardAdded((username, gridProperties) -> { + Platform.runLater(() -> { + var newGameBoard = new GameBoard(gridProperties.length, gridProperties[0].length, 100, 100); + newGameBoard.enableFocus(false); + for (var x = 0; x < gridProperties.length; x++) { + for (var y = 0; y < gridProperties[0].length; y++) { + newGameBoard.getGridProperty(x,y).bindBidirectional(gridProperties[x][y]); + } + } + var leaderboardScores = game.leaderboardScoresProperty(); + + var boardGridDimensions = (int) Math.sqrt(leaderboardScores.size()); + var playerIndex = -1; + for (var player : leaderboardScores) { + playerIndex++; + if (player.getKey().equals(username)) break; + } + var rowIndex = playerIndex / boardGridDimensions; + var columnIndex = playerIndex - rowIndex * boardGridDimensions; + var newBoardTitle = new Text(username); + newBoardTitle.setTextAlignment(TextAlignment.CENTER); + newBoardTitle.getStyleClass().add("heading"); + logger.debug("Creating board for: {} at row index: {}, column index: {}", username, rowIndex, columnIndex); + var newBoardContainer = new VBox(newBoardTitle, newGameBoard); + newBoardContainer.setAlignment(Pos.CENTER); + newBoardContainer.setSpacing(4); + playerBoardGrid.add(newBoardContainer, 1, 1); + }); + }); + gameWindow.getCommunicator().send("SCORES"); } @@ -63,12 +110,32 @@ public class MultiplayerScene extends ChallengeScene { leftMenu.setSpacing(8); leftMenu.setMaxWidth(200); leftMenu.setPrefWidth(200); + var viewOtherBoards = new Text("See others"); + viewOtherBoards.getStyleClass().add("channelItem"); + viewOtherBoards.setOnMouseClicked((event) -> { + Platform.runLater(() -> { + var returnButton = new Text("Back"); + returnButton.getStyleClass().add("channelItem"); + var playerBoardTitle = new Text("All Boards"); + playerBoardTitle.getStyleClass().add("title"); + playerBoardTitle.setTextAlignment(TextAlignment.CENTER); + var playerBoardGridContainer = new VBox(returnButton, playerBoardTitle, playerBoardGrid); + playerBoardGridContainer.setAlignment(Pos.CENTER); + playerBoardGridContainer.setFillWidth(true); + playerBoardGridContainer.setPrefHeight(Double.MAX_VALUE); + playerBoardGridContainer.setSpacing(12); + playerBoardGridContainer.getStyleClass().add("overlay"); + returnButton.setOnMouseClicked((returnEvent) -> Platform.runLater(() -> challengePane.getChildren().remove(playerBoardGridContainer))); + playerBoardGrid.setAlignment(Pos.CENTER); + challengePane.getChildren().add(playerBoardGridContainer); + }); + }); chat = new Chat(gameWindow.getCommunicator(), true); chat.setChatFocusTraversable(false); leaderboard = new Leaderboard("Leaderboard"); var chatTitle = new Text("Chat"); chatTitle.getStyleClass().add("heading"); - leftMenu.getChildren().addAll(leaderboard, new Separator(), chatTitle, chat); + leftMenu.getChildren().addAll(viewOtherBoards, leaderboard, new Separator(), chatTitle, chat); mainPane.setLeft(leftMenu); leaderboard.bindLeaderboardScores(game.leaderboardScoresProperty()); mainPane.requestFocus(); diff --git a/src/main/java/uk/mgrove/ac/soton/comp1206/scene/ScoresScene.java b/src/main/java/uk/mgrove/ac/soton/comp1206/scene/ScoresScene.java index 7d7b03f..113973a 100644 --- a/src/main/java/uk/mgrove/ac/soton/comp1206/scene/ScoresScene.java +++ b/src/main/java/uk/mgrove/ac/soton/comp1206/scene/ScoresScene.java @@ -299,6 +299,7 @@ public class ScoresScene extends BaseScene { userNamePrompt.getChildren().addAll(userNameInput, userNameSubmit); highScorePromptContainer = new VBox(usernameTitle, userNamePrompt); highScorePromptContainer.setSpacing(20); + highScorePromptContainer.setAlignment(Pos.CENTER); scoresPane.getChildren().addAll(highScorePromptContainer); StackPane.setAlignment(highScorePromptContainer, Pos.CENTER); } @@ -338,17 +339,19 @@ public class ScoresScene extends BaseScene { * @param score high score to save */ private void saveHighScore(String username, int score) { - logger.info("Saving high score: {} for user: {}", score, username); + if (!game.getClass().equals(MultiplayerGame.class)) { + logger.info("Saving high score: {} for user: {}", score, username); - for (var i = 0; i <= localScores.getSize(); i++) { - if (i == localScores.getSize() || localScores.get(i).getValue() < score) { - localScores.add(i, new Pair<>(username, score)); - break; + for (var i = 0; i <= localScores.getSize(); i++) { + if (i == localScores.getSize() || localScores.get(i).getValue() < score) { + localScores.add(i, new Pair<>(username, score)); + break; + } } + // if score isn't higher than last high score then this shouldn't have been triggered + // so while it won't get stored, this isn't an issue + writeScores("scores.txt", localScores); } - // if score isn't higher than last high score then this shouldn't have been triggered - // so while it won't get stored, this isn't an issue - writeScores("scores.txt", localScores); } private void writeOnlineScore(String username, int score) { diff --git a/src/main/resources/style/game.css b/src/main/resources/style/game.css index f10301b..55a0d08 100644 --- a/src/main/resources/style/game.css +++ b/src/main/resources/style/game.css @@ -6,6 +6,10 @@ -fx-background-color: black; } +.overlay { + -fx-background-color: rgba(0,0,0,0.7); +} + Text { -fx-fill: white; -fx-font-family: 'Orbitron'; @@ -18,6 +22,9 @@ Label { .menu-background { -fx-background-image: url("../images/1.jpg"); -fx-background-size: cover; +} + +BorderPane { -fx-padding: 20; } @@ -195,6 +202,7 @@ Label { } TextField, .text-field { + -fx-font-family: 'Orbitron'; -fx-border-color: white; -fx-border-width: 1px; -fx-background-color: rgba(0,0,0,0.5);