[FEAT] Add basic instructions and show current piece during game

This commit is contained in:
2023-04-05 13:28:52 +01:00
parent f7383f33dc
commit 9f0026b4ef
11 changed files with 252 additions and 11 deletions

View File

@@ -122,11 +122,11 @@ public class GameBlock extends Canvas {
gc.clearRect(0,0,width,height);
//Fill
gc.setFill(Color.WHITE);
gc.setFill(Color.web("111111",0.5));
gc.fillRect(0,0, width, height);
//Border
gc.setStroke(Color.BLACK);
gc.setStroke(Color.GRAY);
gc.strokeRect(0,0,width,height);
}
@@ -145,7 +145,7 @@ public class GameBlock extends Canvas {
gc.fillRect(0,0, width, height);
//Border
gc.setStroke(Color.BLACK);
gc.setStroke(Color.GRAY);
gc.strokeRect(0,0,width,height);
}

View File

@@ -75,7 +75,7 @@ public class GameBoard extends GridPane {
}
/**
* Create a new GameBoard with it's own internal grid, specifying the number of columns and rows, along with the
* Create a new GameBoard with its own internal grid, specifying the number of columns and rows, along with the
* visual width and height.
*
* @param cols number of columns for internal grid

View File

@@ -0,0 +1,24 @@
package uk.mgrove.ac.soton.comp1206.component;
import uk.mgrove.ac.soton.comp1206.game.GamePiece;
import uk.mgrove.ac.soton.comp1206.game.Grid;
public class PieceBoard extends GameBoard {
/**
* Create a new GameBoard with it's own internal grid, specifying the number of columns and rows, along with the
* visual width and height.
*
* @param width the visual width
* @param height the visual height
*/
public PieceBoard(double width, double height) {
super(3, 3, width, height);
}
public void displayPiece(GamePiece piece) {
grid.clearGrid();
grid.playPiece(piece,1,1);
}
}

View File

@@ -0,0 +1,15 @@
package uk.mgrove.ac.soton.comp1206.event;
import uk.mgrove.ac.soton.comp1206.game.GamePiece;
/**
* The Next Piece Listener is used for listening for new pieces being provided to the game.
*/
public interface NextPieceListener {
/**
* Handle a new piece being received by the game
* @param piece the piece that was received
*/
public void nextPiece(GamePiece piece);
}

View File

@@ -5,6 +5,7 @@ import javafx.beans.property.SimpleIntegerProperty;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.component.GameBlock;
import uk.mgrove.ac.soton.comp1206.event.NextPieceListener;
import java.util.*;
@@ -61,6 +62,11 @@ public class Game {
*/
protected IntegerProperty multiplier = new SimpleIntegerProperty(1);
/**
* Listener for when new piece is received by the game
*/
private NextPieceListener nextPieceListener;
/**
* Create a new game with the specified rows and columns. Creates a corresponding grid model.
* @param cols number of columns
@@ -88,6 +94,7 @@ public class Game {
*/
public GamePiece nextPiece() {
currentPiece = spawnPiece();
if (nextPieceListener != null) nextPieceListener.nextPiece(currentPiece);
logger.info("Next piece is: {}", currentPiece);
return currentPiece;
}
@@ -317,4 +324,13 @@ public class Game {
public IntegerProperty scoreProperty() {
return score;
}
/**
* Set next piece listener
* @param listener listener to set
*/
public void setNextPieceListener(NextPieceListener listener) {
nextPieceListener = listener;
}
}

View File

@@ -147,6 +147,16 @@ public class Grid {
}
}
public void clearGrid() {
for (var x = 0; x < getCols(); x++) {
for (var y = 0; y < getRows(); y++) {
if (get(x,y) != 0) {
set(x,y,0);
}
}
}
}
/**
* Get the number of columns in this game
* @return number of columns

View File

@@ -1,11 +1,15 @@
package uk.mgrove.ac.soton.comp1206.scene;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.*;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.component.GameBlock;
import uk.mgrove.ac.soton.comp1206.component.GameBoard;
import uk.mgrove.ac.soton.comp1206.component.PieceBoard;
import uk.mgrove.ac.soton.comp1206.event.NextPieceListener;
import uk.mgrove.ac.soton.comp1206.game.Game;
import uk.mgrove.ac.soton.comp1206.game.GamePiece;
import uk.mgrove.ac.soton.comp1206.ui.GamePane;
import uk.mgrove.ac.soton.comp1206.ui.GameWindow;
import uk.mgrove.ac.soton.comp1206.ui.StatsMenu;
@@ -19,6 +23,11 @@ public class ChallengeScene extends BaseScene {
private static final Logger logger = LogManager.getLogger(MenuScene.class);
protected Game game;
/**
* PieceBoard to display current piece
*/
private PieceBoard currentPieceBoard;
/**
* Create a new Single Player challenge scene
* @param gameWindow the Game Window
@@ -52,7 +61,13 @@ public class ChallengeScene extends BaseScene {
mainPane.setCenter(board);
var statsMenu = new StatsMenu(game.scoreProperty(),game.levelProperty(),game.livesProperty(),game.multiplierProperty());
mainPane.setRight(statsMenu);
currentPieceBoard = new PieceBoard(100, 100);
var rightMenu = new VBox();
rightMenu.getChildren().addAll(statsMenu,currentPieceBoard);
mainPane.setRight(rightMenu);
Multimedia.playMusic("music/game.wav");
@@ -84,7 +99,28 @@ public class ChallengeScene extends BaseScene {
@Override
public void initialise() {
logger.info("Initialising Challenge");
// exit challenge when escape key pressed
scene.setOnKeyPressed((event) -> {
if (event.getCode() == KeyCode.ESCAPE) {
returnToMenu();
}
});
game.setNextPieceListener(this::setCurrentPiece);
game.start();
}
private void returnToMenu() {
// TODO: any processing to end game
gameWindow.startMenu();
}
private void setCurrentPiece(GamePiece piece) {
currentPieceBoard.displayPiece(piece);
}
}

View File

@@ -0,0 +1,99 @@
package uk.mgrove.ac.soton.comp1206.scene;
import javafx.geometry.Pos;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.component.PieceBoard;
import uk.mgrove.ac.soton.comp1206.game.GamePiece;
import uk.mgrove.ac.soton.comp1206.ui.GamePane;
import uk.mgrove.ac.soton.comp1206.ui.GameWindow;
public class InstructionsScene extends BaseScene {
/**
* Logger
*/
private static final Logger logger = LogManager.getLogger(InstructionsScene.class);
/**
* Create a new scene, passing in the GameWindow the scene will be displayed in
*
* @param gameWindow the game window
*/
public InstructionsScene(GameWindow gameWindow) {
super(gameWindow);
}
/**
* Initialise this scene. Called after creation
*/
@Override
public void initialise() {
logger.info("Initialising Instructions");
// exit challenge when escape key pressed
scene.setOnKeyPressed((event) -> {
if (event.getCode() == KeyCode.ESCAPE) {
gameWindow.startMenu();
}
});
}
/**
* Build the layout of the scene
*/
@Override
public void build() {
logger.info("Building " + this.getClass().getName());
root = new GamePane(gameWindow.getWidth(),gameWindow.getHeight());
var menuPane = new StackPane();
menuPane.setMaxWidth(gameWindow.getWidth());
menuPane.setMaxHeight(gameWindow.getHeight());
menuPane.getStyleClass().add("menu-background");
root.getChildren().add(menuPane);
var mainPane = new BorderPane();
menuPane.getChildren().add(mainPane);
//Awful title
var title = new Text("How to Play");
title.getStyleClass().add("title");
mainPane.setTop(title);
BorderPane.setAlignment(title, Pos.TOP_CENTER);
var instructions = new ImageView(getClass().getResource("/images/Instructions.png").toExternalForm());
instructions.setPreserveRatio(true);
instructions.setFitHeight(gameWindow.getHeight()*0.55);
mainPane.setCenter(instructions);
var pieceGrid = new GridPane();
pieceGrid.setVgap(8);
pieceGrid.setHgap(8);
for (var i = 0; i < GamePiece.PIECES; i++) {
var pieceBoard = new PieceBoard(48, 48);
pieceBoard.displayPiece(GamePiece.createPiece(i));
pieceGrid.add(pieceBoard, i % 5, Math.floorDiv(i,5));
}
var allPieces = new VBox();
var piecesHeader = new Text("Game Pieces");
piecesHeader.getStyleClass().add("title");
allPieces.getChildren().addAll(piecesHeader,pieceGrid);
allPieces.setAlignment(Pos.BOTTOM_CENTER);
pieceGrid.setAlignment(Pos.BOTTOM_CENTER);
mainPane.setBottom(allPieces);
BorderPane.setAlignment(allPieces, Pos.BOTTOM_CENTER);
}
}

View File

@@ -15,6 +15,9 @@ import uk.mgrove.ac.soton.comp1206.util.Multimedia;
*/
public class MenuScene extends BaseScene {
/**
* Logger
*/
private static final Logger logger = LogManager.getLogger(MenuScene.class);
/**
@@ -49,14 +52,22 @@ public class MenuScene extends BaseScene {
title.getStyleClass().add("title");
mainPane.setTop(title);
//For now, let us just add a button that starts the game. I'm sure you'll do something way better.
var button = new Button("Play");
mainPane.setCenter(button);
var menuItems = new VBox();
var singlePlayerButton = new Button("Single Player");
var multiPlayerButton = new Button("Multi Player");
var howToPlayButton = new Button("How to Play");
var exitButton = new Button("Exit");
menuItems.getChildren().addAll(singlePlayerButton,multiPlayerButton,howToPlayButton,exitButton);
mainPane.setCenter(menuItems);
// TOOD: window animations
Multimedia.playMusic("music/menu.mp3");
//Bind the button action to the startGame method in the menu
button.setOnAction(this::startGame);
singlePlayerButton.setOnAction(this::startSinglePlayer);
multiPlayerButton.setOnAction(this::startMultiPlayer);
howToPlayButton.setOnAction(this::showInstructions);
}
/**
@@ -68,11 +79,27 @@ public class MenuScene extends BaseScene {
}
/**
* Handle when the Start Game button is pressed
* Handle when the Start Single Player Game button is pressed
* @param event event
*/
private void startGame(ActionEvent event) {
private void startSinglePlayer(ActionEvent event) {
gameWindow.startChallenge();
}
/**
* Handle when the Start Multiplayer Game button is pressed
* @param event event
*/
private void startMultiPlayer(ActionEvent event) {
gameWindow.startMultiplayer();
}
/**
* Handle when the How to Play button is pressed
* @param event event
*/
private void showInstructions(ActionEvent event) {
gameWindow.startInstructions();
}
}

View File

@@ -88,6 +88,18 @@ public class GameWindow {
*/
public void startChallenge() { loadScene(new ChallengeScene(this)); }
/**
* Display the multiplayer challenge
*/
public void startMultiplayer() {
// TODO: load multiplayer scene
}
/**
* Display the instructions
*/
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.
*/

View File

@@ -5,6 +5,7 @@ import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import uk.mgrove.ac.soton.comp1206.component.PieceBoard;
import uk.mgrove.ac.soton.comp1206.game.Game;
/**
@@ -53,6 +54,7 @@ public class StatsMenu extends VBox {
var levelHeader = new Text("Level");
var livesHeader = new Text("Lives");
var multiplierHeader = new Text("Multiplier");
getChildren().addAll(scoreHeader,this.score,levelHeader,this.level,livesHeader,this.lives,multiplierHeader,this.multiplier);
}