[FEAT] Add basic instructions and show current piece during game
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user