[FEAT] Score tracking, time-based gameplay, and countdown indicator bar

This commit is contained in:
2023-04-07 20:33:16 +01:00
parent ba2cc8e6ef
commit bbb9ebcf4e
12 changed files with 538 additions and 42 deletions

View File

@@ -207,7 +207,6 @@ public class GameBlock extends Canvas {
public void setFocussed(boolean value) { public void setFocussed(boolean value) {
logger.info("Block at x: {}, y: {} has been set to focus: {}", getX(), getY(), value); logger.info("Block at x: {}, y: {} has been set to focus: {}", getX(), getY(), value);
isFocussed = value; isFocussed = value;
// TODO: add/remove overlay
paint(); paint();
} }
@@ -228,19 +227,17 @@ public class GameBlock extends Canvas {
logger.info("Fading out block at x: {}, y: {}", getX(), getY()); logger.info("Fading out block at x: {}, y: {}", getX(), getY());
AnimationTimer timer = new AnimationTimer() { AnimationTimer timer = new AnimationTimer() {
Color color = COLOURS[getValue()]; private Color color = COLOURS[getValue()];
int iterations = 0; private int iterations = 0;
@Override @Override
public void handle(long now) { public void handle(long now) {
if (iterations < 12) { if (iterations < 12) {
color = color.deriveColor(0,1,1.2,1); color = color.deriveColor(0,1,1.2,1);
paintColor(color); paintColor(color);
logger.info("New color brightness is {}", color.getBrightness());
if (isFocussed) paintFocusOverlay(); if (isFocussed) paintFocusOverlay();
} else if (color.getOpacity() > 0.1) { } else if (color.getOpacity() > 0.1) {
color = color.deriveColor(0,1,1,0.95); color = color.deriveColor(0,1,1,0.95);
paintColor(color); paintColor(color);
logger.info("New color opacity is {}", color.getOpacity());
if (isFocussed) paintFocusOverlay(); if (isFocussed) paintFocusOverlay();
} else { } else {
paintEmpty(); paintEmpty();

View File

@@ -0,0 +1,71 @@
package uk.mgrove.ac.soton.comp1206.component;
import javafx.animation.FadeTransition;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.util.Duration;
import javafx.util.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
/**
* Class for displaying list of scores and associated users
*/
public class ScoresList extends VBox {
/**
* Logger
*/
private static final Logger logger = LogManager.getLogger(ScoresList.class);
/**
* Scores
*/
private final SimpleListProperty<Pair<String,Integer>> scores;
/**
* Initialise the scores list
*/
public ScoresList() {
logger.info("Building scores list");
ObservableList<Pair<String,Integer>> observableScoresList = FXCollections.observableArrayList();
scores = new SimpleListProperty<>(observableScoresList);
setOpacity(0);
scores.addListener((ListChangeListener<? super Pair<String, Integer>>) change -> {
logger.info("Detected change in scores list: {}", change);
getChildren().clear();
for (var pair : scores.get()) {
var score = new HBox();
score.getChildren().addAll(new Text(pair.getKey()), new Text(pair.getValue().toString()));
getChildren().add(score);
}
});
}
/**
* Bind scores to external property
* @param scores external property to bind to
*/
public void bindScores(SimpleListProperty<Pair<String,Integer>> scores) {
this.scores.bindBidirectional(scores);
}
/**
* Reveal the scores
*/
public void reveal() {
logger.info("Revealing scores");
FadeTransition fadeInTransition = new FadeTransition(Duration.millis(1000), this);
fadeInTransition.setToValue(1);
fadeInTransition.play();
}
}

View File

@@ -0,0 +1,14 @@
package uk.mgrove.ac.soton.comp1206.event;
/**
* Listener for game loop being scheduled
*/
public interface GameLoopListener {
/**
* Process the game loop being scheduled
* @param timerDelay delay until game loop is executed
*/
public void process(int timerDelay);
}

View File

@@ -4,8 +4,15 @@ import uk.mgrove.ac.soton.comp1206.component.GameBlockCoordinate;
import java.util.Set; import java.util.Set;
/**
* Listener for lines being cleared on the game board
*/
public interface LineClearedListener { public interface LineClearedListener {
/**
* Process the line(s) being cleared
* @param blockCoordinates coordinates of the blocks being cleared
*/
public void clearLine(Set<GameBlockCoordinate> blockCoordinates); public void clearLine(Set<GameBlockCoordinate> blockCoordinates);
} }

View File

@@ -0,0 +1,15 @@
package uk.mgrove.ac.soton.comp1206.event;
import uk.mgrove.ac.soton.comp1206.game.Game;
/**
* Listener for showing the scores scene
*/
public interface ShowScoresSceneListener {
/**
* Show the scene
*/
public void show(Game game);
}

View File

@@ -1,13 +1,16 @@
package uk.mgrove.ac.soton.comp1206.game; package uk.mgrove.ac.soton.comp1206.game;
import javafx.application.Platform;
import javafx.beans.property.IntegerProperty; import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty; import javafx.beans.property.SimpleIntegerProperty;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.component.GameBlock; import uk.mgrove.ac.soton.comp1206.component.GameBlock;
import uk.mgrove.ac.soton.comp1206.component.GameBlockCoordinate; import uk.mgrove.ac.soton.comp1206.component.GameBlockCoordinate;
import uk.mgrove.ac.soton.comp1206.event.GameLoopListener;
import uk.mgrove.ac.soton.comp1206.event.LineClearedListener; import uk.mgrove.ac.soton.comp1206.event.LineClearedListener;
import uk.mgrove.ac.soton.comp1206.event.NextPieceListener; import uk.mgrove.ac.soton.comp1206.event.NextPieceListener;
import uk.mgrove.ac.soton.comp1206.event.ShowScoresSceneListener;
import uk.mgrove.ac.soton.comp1206.util.Multimedia; import uk.mgrove.ac.soton.comp1206.util.Multimedia;
import java.util.*; import java.util.*;
@@ -80,6 +83,22 @@ public class Game {
*/ */
private LineClearedListener lineClearedListener; private LineClearedListener lineClearedListener;
/**
* Game timer for time-based functionality
*/
private Timer gameTimer;
/**
* Listener for game loop being scheduled
*/
private GameLoopListener gameLoopListener;
/**
* Listener for showing scores scene
*/
private ShowScoresSceneListener showScoresListener;
/** /**
* Create a new game with the specified rows and columns. Creates a corresponding grid model. * Create a new game with the specified rows and columns. Creates a corresponding grid model.
* @param cols number of columns * @param cols number of columns
@@ -142,6 +161,55 @@ public class Game {
logger.info("Initialising game"); logger.info("Initialising game");
followingPiece = spawnPiece(); followingPiece = spawnPiece();
nextPiece(); nextPiece();
scheduleGameLoop();
}
/**
* Game loop - ongoing time-based functionality
*/
private void gameLoop() {
logger.info("Executing game loop");
setLives(getLives() - 1);
nextPiece();
setMultiplier(1);
Multimedia.playAudio("sounds/lifelose.wav");
if(getLives() < 0) {
endGame();
if (showScoresListener != null) Platform.runLater(() -> showScoresListener.show(this));
}
else scheduleGameLoop();
}
/**
* Start new game loop
*/
private void scheduleGameLoop() {
logger.info("Scheduling game loop");
if (gameTimer != null) gameTimer.cancel();
TimerTask gameTimerTask = new TimerTask() {
@Override
public void run() {
gameLoop();
}
};
gameTimer = new Timer("Timer");
var timerDelay = getTimerDelay();
gameTimer.schedule(gameTimerTask, timerDelay);
if (gameLoopListener != null) gameLoopListener.process(timerDelay);
}
/**
* End game
*/
public void endGame() {
if (gameTimer != null) gameTimer.cancel();
Multimedia.playAudio("sounds/explode.wav");
// TODO: do processing to end game - switch to ScoresScene
} }
/** /**
@@ -166,7 +234,6 @@ public class Game {
logger.info("Playing piece at x: {}, y: {}", x, y); logger.info("Playing piece at x: {}, y: {}", x, y);
grid.playPiece(currentPiece,x,y); grid.playPiece(currentPiece,x,y);
afterPiece(); afterPiece();
nextPiece();
Multimedia.playAudio("sounds/place.wav"); Multimedia.playAudio("sounds/place.wav");
} else { } else {
@@ -236,6 +303,9 @@ public class Game {
for (var block : blocksToRemove) { for (var block : blocksToRemove) {
block.set(0); block.set(0);
} }
nextPiece();
scheduleGameLoop();
} }
/** /**
@@ -280,6 +350,14 @@ public class Game {
if (nextPieceListener != null) nextPieceListener.nextPiece(currentPiece, followingPiece); if (nextPieceListener != null) nextPieceListener.nextPiece(currentPiece, followingPiece);
} }
/**
* Get timer delay - amount of time before timer should expire
* @return timer delay
*/
private int getTimerDelay() {
return Math.max(2500, 12000 - 500 * getLevel());
}
/** /**
* Get the grid model inside this game representing the game state of the board * Get the grid model inside this game representing the game state of the board
* @return game grid model * @return game grid model
@@ -412,4 +490,20 @@ public class Game {
lineClearedListener = listener; lineClearedListener = listener;
} }
/**
* Set listener for game loop being executed
* @param listener listener to set
*/
public void setOnGameLoop(GameLoopListener listener) {
gameLoopListener = listener;
}
/**
* Set listener for showing scores scene
* @param listener listener to set
*/
public void setShowScoresListener(ShowScoresSceneListener listener) {
showScoresListener = listener;
}
} }

View File

@@ -1,7 +1,16 @@
package uk.mgrove.ac.soton.comp1206.scene; package uk.mgrove.ac.soton.comp1206.scene;
import javafx.animation.*;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.geometry.Pos;
import javafx.scene.input.KeyEvent; import javafx.scene.input.KeyEvent;
import javafx.scene.layout.*; import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.util.Duration;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.component.GameBlock; import uk.mgrove.ac.soton.comp1206.component.GameBlock;
@@ -19,7 +28,14 @@ import uk.mgrove.ac.soton.comp1206.util.Multimedia;
*/ */
public class ChallengeScene extends BaseScene { public class ChallengeScene extends BaseScene {
private static final Logger logger = LogManager.getLogger(MenuScene.class); /**
* Logger
*/
private static final Logger logger = LogManager.getLogger(ChallengeScene.class);
/**
* The game that is running
*/
protected Game game; protected Game game;
/** /**
@@ -37,6 +53,26 @@ public class ChallengeScene extends BaseScene {
*/ */
private GameBoard board; private GameBoard board;
/**
* Progress bar to indicate time left until game loop executes (i.e. life is lost)
*/
private Rectangle timerCountdownBar;
/**
* Fill transition for timer countdown bar
*/
private FillTransition timerCountdownBarFillTransition;
/**
* Scale transition for timer countdown bar
*/
private ScaleTransition timerCountdownBarScaleTransition;
/**
* Top high score property
*/
private final IntegerProperty highScore = new SimpleIntegerProperty(0);
/** /**
* Create a new Single Player challenge scene * Create a new Single Player challenge scene
* @param gameWindow the Game Window * @param gameWindow the Game Window
@@ -66,7 +102,7 @@ public class ChallengeScene extends BaseScene {
var mainPane = new BorderPane(); var mainPane = new BorderPane();
challengePane.getChildren().add(mainPane); challengePane.getChildren().add(mainPane);
board = new GameBoard(game.getGrid(),gameWindow.getWidth()/2,gameWindow.getWidth()/2); board = new GameBoard(game.getGrid(),gameWindow.getWidth()/2f,gameWindow.getWidth()/2f);
board.setOnRightClicked(game::rotateCurrentPiece); board.setOnRightClicked(game::rotateCurrentPiece);
mainPane.setCenter(board); mainPane.setCenter(board);
@@ -77,11 +113,25 @@ public class ChallengeScene extends BaseScene {
currentPieceBoard.setOnLeftClicked(game::rotateCurrentPiece); currentPieceBoard.setOnLeftClicked(game::rotateCurrentPiece);
followingPieceBoard = new PieceBoard(72, 72); followingPieceBoard = new PieceBoard(72, 72);
var topHighScoreText = new Text();
topHighScoreText.textProperty().bind(highScore.asString());
highScore.set(getHighScore());
game.scoreProperty().addListener((ChangeListener<? super Number>) (change, oldValue, newValue) -> {
if (newValue.intValue() > highScore.get()) highScore.set(newValue.intValue());
});
var rightMenu = new VBox(); var rightMenu = new VBox();
rightMenu.getChildren().addAll(statsMenu,currentPieceBoard,followingPieceBoard); rightMenu.getChildren().addAll(statsMenu,currentPieceBoard,followingPieceBoard,topHighScoreText);
mainPane.setRight(rightMenu); mainPane.setRight(rightMenu);
timerCountdownBar = new Rectangle(gameWindow.getWidth()/2f,48);
BorderPane.setAlignment(timerCountdownBar, Pos.BOTTOM_CENTER);
// TODO: alignment of timer bar
mainPane.setBottom(timerCountdownBar);
Multimedia.playMusic("music/game.wav"); Multimedia.playMusic("music/game.wav");
//Handle block on game board grid being clicked //Handle block on game board grid being clicked
@@ -137,19 +187,54 @@ public class ChallengeScene extends BaseScene {
game.setLineClearedListener(board::fadeOut); game.setLineClearedListener(board::fadeOut);
game.setOnGameLoop(this::scheduleCountdown);
game.setShowScoresListener(this::showScores);
game.start(); game.start();
} }
private void returnToMenu() { private void returnToMenu() {
// TODO: any processing to end game game.endGame();
gameWindow.startMenu(); gameWindow.startMenu();
} }
private void showScores(Game game) {
if (timerCountdownBarFillTransition != null) timerCountdownBarFillTransition.stop();
if (timerCountdownBarScaleTransition != null) timerCountdownBarScaleTransition.stop();
gameWindow.startScores(game);
}
private void setCurrentPiece(GamePiece currentPiece, GamePiece followingPiece) { private void setCurrentPiece(GamePiece currentPiece, GamePiece followingPiece) {
currentPieceBoard.displayPiece(currentPiece); currentPieceBoard.displayPiece(currentPiece);
followingPieceBoard.displayPiece(followingPiece); followingPieceBoard.displayPiece(followingPiece);
} }
/**
* Reset the countdown progress bar with new game timer delay when the game loop is scheduled
* @param timerDelay delay until game loop is executed
*/
private void scheduleCountdown(int timerDelay) {
logger.info("Scheduling UI countdown timer");
timerCountdownBar.setArcHeight(32);
timerCountdownBar.setArcWidth(32);
timerCountdownBar.setFill(Color.GREEN);
timerCountdownBarFillTransition = new FillTransition(Duration.millis(timerDelay), timerCountdownBar, Color.GREEN, Color.RED);
timerCountdownBarScaleTransition = new ScaleTransition(Duration.millis(timerDelay), timerCountdownBar);
timerCountdownBarScaleTransition.setFromX(1);
timerCountdownBarScaleTransition.setToX(0);
timerCountdownBarFillTransition.play();
timerCountdownBarScaleTransition.play();
}
/**
* Get top high score
* @return top high score
*/
private int getHighScore() {
return ScoresScene.getScores("scores.txt").get(0).getValue();
}
} }

View File

@@ -1,7 +1,6 @@
package uk.mgrove.ac.soton.comp1206.scene; package uk.mgrove.ac.soton.comp1206.scene;
import javafx.geometry.Pos; import javafx.geometry.Pos;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode; import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane; import javafx.scene.layout.BorderPane;
@@ -16,6 +15,9 @@ import uk.mgrove.ac.soton.comp1206.game.GamePiece;
import uk.mgrove.ac.soton.comp1206.ui.GamePane; import uk.mgrove.ac.soton.comp1206.ui.GamePane;
import uk.mgrove.ac.soton.comp1206.ui.GameWindow; import uk.mgrove.ac.soton.comp1206.ui.GameWindow;
/**
* Scene to show game instructions
*/
public class InstructionsScene extends BaseScene { public class InstructionsScene extends BaseScene {
/** /**

View File

@@ -0,0 +1,216 @@
package uk.mgrove.ac.soton.comp1206.scene;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.util.Pair;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.component.ScoresList;
import uk.mgrove.ac.soton.comp1206.game.Game;
import uk.mgrove.ac.soton.comp1206.ui.GamePane;
import uk.mgrove.ac.soton.comp1206.ui.GameWindow;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;
/**
* Scene to show scores and record high scores
*/
public class ScoresScene extends BaseScene {
/**
* Logger
*/
private static final Logger logger = LogManager.getLogger(ScoresScene.class);
/**
* The game that just finished
*/
private final Game game;
/**
* List of scores stored locally
*/
private SimpleListProperty<Pair<String,Integer>> localScores;
/**
* Root pane in scene inside the GamePane
*/
private StackPane scoresPane;
/**
* Node to display high scores
*/
private ScoresList scoresUiList;
/**
* Container for prompting for username when high score achieved
*/
private VBox userNamePrompt;
/**
* Create a new scores scene
* @param gameWindow the Game Window
* @param game the game that just finished
*/
public ScoresScene(GameWindow gameWindow, Game game) {
super(gameWindow);
logger.info("Creating Scores Scene");
this.game = game;
}
/**
* Build the layout of the scene
*/
@Override
public void build() {
logger.info("Building " + this.getClass().getName());
root = new GamePane(gameWindow.getWidth(),gameWindow.getHeight());
scoresPane = new StackPane();
scoresPane.setMaxWidth(gameWindow.getWidth());
scoresPane.setMaxHeight(gameWindow.getHeight());
scoresPane.getStyleClass().add("menu-background");
root.getChildren().add(scoresPane);
var mainPane = new BorderPane();
scoresPane.getChildren().add(mainPane);
ArrayList<Pair<String,Integer>> scoresList = new ArrayList<>();
ObservableList<Pair<String,Integer>> observableScoresList = FXCollections.observableArrayList(scoresList);
localScores = new SimpleListProperty<>(observableScoresList);
loadScores("scores.txt");
if (game.getScore() > localScores.get(localScores.getSize() - 1).getValue()) showHighScorePrompt(game.getScore());
scoresUiList = new ScoresList();
scoresUiList.bindScores(localScores);
mainPane.setCenter(scoresUiList);
}
/**
* Initialise this scene. Called after creation
*/
@Override
public void initialise() {
}
/**
* Load high scores from file
* @param filePath file path to load scores from
*/
public void loadScores(String filePath) {
logger.info("Loading scores from file: {}", filePath);
localScores = getScores(filePath);
}
/**
* Get scores from file
* @param filePath file to load scores from
* @return list of scores
*/
public static SimpleListProperty<Pair<String,Integer>> getScores(String filePath) {
logger.info("Retrieving scores from file: {}", filePath);
var scores = new SimpleListProperty<Pair<String,Integer>>(FXCollections.observableArrayList());
try {
File scoresFile = new File(filePath);
Scanner scanner = new Scanner(scoresFile);
while (scanner.hasNextLine()) {
var line = scanner.nextLine();
if (line.matches("^.+:[0-9]+$")) {
int splitIndex = line.lastIndexOf(":");
String[] info = {line.substring(0,splitIndex), line.substring(splitIndex+1)};
scores.add(new Pair<>(info[0], Integer.valueOf(info[1])));
}
}
scanner.close();
} catch (FileNotFoundException e1) {
logger.error("Unable to load scores file, writing default scores instead: {}", filePath);
scores.add(new Pair<>("Sam",3000));
scores.add(new Pair<>("Jane",2000));
scores.add(new Pair<>("Pete",1000));
writeScores("scores.txt", scores);
}
logger.info("Retrieved scores: {}", scores);
return scores;
}
/**
* Write list of scores to file
* @param filePath file to write to
* @param scores scores to write
*/
public static void writeScores(String filePath, SimpleListProperty<Pair<String,Integer>> scores) {
logger.info("Writing scores to file: {}", filePath);
try {
FileWriter scoresWriter = new FileWriter(filePath);
for (var pair : scores.get()) {
scoresWriter.write(pair.getKey() + ":" + pair.getValue() + "\n");
}
scoresWriter.close();
} catch (IOException e) {
logger.error("Unable to write scores file: {}", filePath);
}
}
/**
* Add new high score - prompt user for name and add to saved scores
* @param score new high score to save
*/
private void showHighScorePrompt(int score) {
logger.info("Showing high score username input prompt");
userNamePrompt = new VBox();
var userNameInput = new TextField();
userNameInput.setPromptText("Enter username...");
userNameInput.setOnAction((event) -> saveHighScore(userNameInput.getText(), score));
var userNameSubmit = new Button("Submit");
userNameSubmit.setOnAction((event) -> saveHighScore(userNameInput.getText(), score));
userNamePrompt.getChildren().addAll(new Text("Username:"), userNameInput, userNameSubmit);
scoresPane.getChildren().add(userNamePrompt);
}
/**
* Save new high score
* @param username username of user who set high score
* @param score high score to save
*/
private void saveHighScore(String username, int score) {
logger.info("Saving high score: {} for user: {}", score, username);
for (var i = 0; i < localScores.getSize(); i++) {
if (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);
scoresPane.getChildren().remove(userNamePrompt);
scoresUiList.reveal();
}
/**
* Get local scores property
* @return local scores property
*/
public SimpleListProperty<Pair<String, Integer>> localScoresProperty() {
return localScores;
}
}

View File

@@ -9,6 +9,7 @@ import javafx.stage.Stage;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.App; import uk.mgrove.ac.soton.comp1206.App;
import uk.mgrove.ac.soton.comp1206.game.Game;
import uk.mgrove.ac.soton.comp1206.network.Communicator; import uk.mgrove.ac.soton.comp1206.network.Communicator;
import uk.mgrove.ac.soton.comp1206.scene.*; import uk.mgrove.ac.soton.comp1206.scene.*;
import uk.mgrove.ac.soton.comp1206.scene.BaseScene; import uk.mgrove.ac.soton.comp1206.scene.BaseScene;
@@ -86,7 +87,9 @@ public class GameWindow {
/** /**
* Display the single player challenge * Display the single player challenge
*/ */
public void startChallenge() { loadScene(new ChallengeScene(this)); } public void startChallenge() {
loadScene(new ChallengeScene(this));
}
/** /**
* Display the multiplayer challenge * Display the multiplayer challenge
@@ -101,7 +104,12 @@ public class GameWindow {
public void startInstructions() { loadScene(new InstructionsScene(this)); } public void startInstructions() { loadScene(new InstructionsScene(this)); }
/** /**
* Setup the default settings for the stage itself (the window), such as the title and minimum width and height. * Display the single player challenge
*/
public void startScores(Game game) { loadScene(new ScoresScene(this, game)); }
/**
* Set up the default settings for the stage itself (the window), such as the title and minimum width and height.
*/ */
public void setupStage() { public void setupStage() {
stage.setTitle("TetrECS"); stage.setTitle("TetrECS");

View File

@@ -5,8 +5,6 @@ import javafx.scene.layout.VBox;
import javafx.scene.text.Text; import javafx.scene.text.Text;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.component.PieceBoard;
import uk.mgrove.ac.soton.comp1206.game.Game;
/** /**
* Stats menu class to show basic stats about game status * Stats menu class to show basic stats about game status
@@ -16,24 +14,7 @@ public class StatsMenu extends VBox {
/** /**
* Logger * Logger
*/ */
private static final Logger logger = LogManager.getLogger(Game.class); private static final Logger logger = LogManager.getLogger(StatsMenu.class);
/**
* Player's current score
*/
private final Text score = new Text("0");
/**
* Player's current level
*/
private final Text level = new Text("0");
/**
* Player's remaining lives
*/
private final Text lives = new Text("3");
/**
* Player's current multiplier
*/
private final Text multiplier = new Text("1");
/** /**
* Initialise the menu by adding basic stats and binding them to properties * Initialise the menu by adding basic stats and binding them to properties
@@ -45,17 +26,21 @@ public class StatsMenu extends VBox {
public StatsMenu(IntegerProperty score, IntegerProperty level, IntegerProperty lives, IntegerProperty multiplier) { public StatsMenu(IntegerProperty score, IntegerProperty level, IntegerProperty lives, IntegerProperty multiplier) {
logger.info("Initialising new stats menu with score {}, level {}, lives {}, and multiplier {}", score.get(), level.get(), lives.get(), multiplier.get()); logger.info("Initialising new stats menu with score {}, level {}, lives {}, and multiplier {}", score.get(), level.get(), lives.get(), multiplier.get());
this.score.textProperty().bind(score.asString()); Text score1 = new Text();
this.level.textProperty().bind(level.asString()); score1.textProperty().bind(score.asString());
this.lives.textProperty().bind(lives.asString()); Text level1 = new Text();
this.multiplier.textProperty().bind(multiplier.asString()); level1.textProperty().bind(level.asString());
Text lives1 = new Text();
lives1.textProperty().bind(lives.asString());
Text multiplier1 = new Text();
multiplier1.textProperty().bind(multiplier.asString());
var scoreHeader = new Text("Score"); var scoreHeader = new Text("Score");
var levelHeader = new Text("Level"); var levelHeader = new Text("Level");
var livesHeader = new Text("Lives"); var livesHeader = new Text("Lives");
var multiplierHeader = new Text("Multiplier"); var multiplierHeader = new Text("Multiplier");
getChildren().addAll(scoreHeader,this.score,levelHeader,this.level,livesHeader,this.lives,multiplierHeader,this.multiplier); getChildren().addAll(scoreHeader, score1,levelHeader, level1,livesHeader, lives1,multiplierHeader, multiplier1);
} }
} }

View File

@@ -4,14 +4,16 @@ import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer; import javafx.scene.media.MediaPlayer;
import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.game.Game;
/**
* Class for static multimedia actions like playing sounds
*/
public class Multimedia { public class Multimedia {
/** /**
* Logger * Logger
*/ */
private static final Logger logger = LogManager.getLogger(Game.class); private static final Logger logger = LogManager.getLogger(Multimedia.class);
/** /**
* Media player for game music * Media player for game music