diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/component/GameBlockCoordinate.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/component/GameBlockCoordinate.java index 62d52b69fffaaf3a66a73ca3e5ae194706a2dd57..98ee9a50cf79380457f03fd11197361d21c86ca1 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/component/GameBlockCoordinate.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/component/GameBlockCoordinate.java @@ -4,127 +4,141 @@ import javafx.beans.NamedArg; /** * Represents a row and column representation of a block in the grid. Holds the x (column) and y (row). - * + * <p> * Useful for use in a set or list or other form of collection. */ public class GameBlockCoordinate { - /** - * Represents the column - */ - private final int x; - - /** - * Represents the row - */ - private final int y; - - /** - * A hash is computed to enable comparisons between this and other GameBlockCoordinates. - */ - private int hash = 0; - - - /** - * Create a new GameBlockCoordinate which stores a row and column reference to a block - * @param x column - * @param y row - */ - public GameBlockCoordinate(@NamedArg("x") int x, @NamedArg("y") int y) { - this.x = x; - this.y = y; - } - - /** - * Return the column (x) - * @return column number - */ - public int getX() { - return x; - } - - /** - * Return the row (y) - * @return the row number - */ - public int getY() { - return y; - } - - /** - * Add a row and column reference to this one and return a new GameBlockCoordinate - * @param x additional columns - * @param y additional rows - * @return a new GameBlockCoordinate with the result of the addition - */ - public GameBlockCoordinate add(int x, int y) { - return new GameBlockCoordinate( - getX() + x, - getY() + y); - } - - /** - * Add another GameBlockCoordinate to this one, returning a new GameBlockCoordinate - * @param point point to add - * @return a new GameBlockCoordinate with the result of the addition - */ - public GameBlockCoordinate add(GameBlockCoordinate point) { - return add(point.getX(), point.getY()); - } - - /** Subtract a row and column reference to this one and return a new GameBlockCoordinate - * @param x columns to remove - * @param y rows to remove - * @return a new GameBlockCoordinate with the result of the subtraction - */ - public GameBlockCoordinate subtract(int x, int y) { - return new GameBlockCoordinate( - getX() - x, - getY() - y); - } - - /** - * Subtract another GameBlockCoordinate to this one, returning a new GameBlockCoordinate - * @param point point to subtract - * @return a new GameBlockCoordinate with the result of the subtraction - */ - public GameBlockCoordinate subtract(GameBlockCoordinate point) { - return subtract(point.getX(), point.getY()); - } - - /** - * Compare this GameBlockCoordinate to another GameBlockCoordinate - * @param obj other object to compare to - * @return true if equal, otherwise false - */ - @Override public boolean equals(Object obj) { - if (obj == this) return true; - if (obj instanceof GameBlockCoordinate) { - GameBlockCoordinate other = (GameBlockCoordinate) obj; - return getX() == other.getX() && getY() == other.getY(); - } else return false; - } - - /** - * Calculate a hash code of this GameBlockCoordinate, used for comparisons - * @return hash code - */ - @Override public int hashCode() { - if (hash == 0) { - long bits = 7L; - bits = 31L * bits + Double.doubleToLongBits(getX()); - bits = 31L * bits + Double.doubleToLongBits(getY()); - hash = (int) (bits ^ (bits >> 32)); - } - return hash; - } - - /** - * Return a string representation of this GameBlockCoordinate - * @return string representation - */ - @Override public String toString() { - return "GameBlockCoordinate [x = " + getX() + ", y = " + getY() + "]"; + /** + * Represents the column + */ + private final int x; + + /** + * Represents the row + */ + private final int y; + + /** + * A hash is computed to enable comparisons between this and other GameBlockCoordinates. + */ + private int hash = 0; + + + /** + * Create a new GameBlockCoordinate which stores a row and column reference to a block + * + * @param x column + * @param y row + */ + public GameBlockCoordinate(@NamedArg("x") int x, @NamedArg("y") int y) { + this.x = x; + this.y = y; + } + + /** + * Return the column (x) + * + * @return column number + */ + public int getX() { + return x; + } + + /** + * Return the row (y) + * + * @return the row number + */ + public int getY() { + return y; + } + + /** + * Add a row and column reference to this one and return a new GameBlockCoordinate + * + * @param x additional columns + * @param y additional rows + * @return a new GameBlockCoordinate with the result of the addition + */ + public GameBlockCoordinate add(int x, int y) { + return new GameBlockCoordinate( + getX() + x, + getY() + y); + } + + /** + * Add another GameBlockCoordinate to this one, returning a new GameBlockCoordinate + * + * @param point point to add + * @return a new GameBlockCoordinate with the result of the addition + */ + public GameBlockCoordinate add(GameBlockCoordinate point) { + return add(point.getX(), point.getY()); + } + + /** + * Subtract a row and column reference to this one and return a new GameBlockCoordinate + * + * @param x columns to remove + * @param y rows to remove + * @return a new GameBlockCoordinate with the result of the subtraction + */ + public GameBlockCoordinate subtract(int x, int y) { + return new GameBlockCoordinate( + getX() - x, + getY() - y); + } + + /** + * Subtract another GameBlockCoordinate to this one, returning a new GameBlockCoordinate + * + * @param point point to subtract + * @return a new GameBlockCoordinate with the result of the subtraction + */ + public GameBlockCoordinate subtract(GameBlockCoordinate point) { + return subtract(point.getX(), point.getY()); + } + + /** + * Compare this GameBlockCoordinate to another GameBlockCoordinate + * + * @param obj other object to compare to + * @return true if equal, otherwise false + */ + @Override + public boolean equals(Object obj) { + if (obj == this) return true; + if (obj instanceof GameBlockCoordinate) { + GameBlockCoordinate other = (GameBlockCoordinate) obj; + return getX() == other.getX() && getY() == other.getY(); + } else return false; + } + + /** + * Calculate a hash code of this GameBlockCoordinate, used for comparisons + * + * @return hash code + */ + @Override + public int hashCode() { + if (hash == 0) { + long bits = 7L; + bits = 31L * bits + Double.doubleToLongBits(getX()); + bits = 31L * bits + Double.doubleToLongBits(getY()); + hash = (int) (bits ^ (bits >> 32)); } + return hash; + } + + /** + * Return a string representation of this GameBlockCoordinate + * + * @return string representation + */ + @Override + public String toString() { + return "GameBlockCoordinate [x = " + getX() + ", y = " + getY() + "]"; + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/event/BlockClickedListener.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/event/BlockClickedListener.java index 0e1001ab07746c17ce4376765015c3a451ff48f8..f32940c471a823838cf7179202306e2d02341d79 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/event/BlockClickedListener.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/event/BlockClickedListener.java @@ -8,9 +8,10 @@ import uk.ac.soton.comp1206.component.GameBlock; */ public interface BlockClickedListener { - /** - * Handle a block clicked event - * @param block the block that was clicked - */ - public void blockClicked(GameBlock block); + /** + * Handle a block clicked event + * + * @param block the block that was clicked + */ + void blockClicked(GameBlock block); } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/event/CommunicationsListener.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/event/CommunicationsListener.java index 89c532e3794fbf96e50292cc22bedf13b840c3fc..ae3a9b9f7dab70fbdbd7c77c6a87c37a44ad3889 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/event/CommunicationsListener.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/event/CommunicationsListener.java @@ -5,9 +5,10 @@ package uk.ac.soton.comp1206.event; */ public interface CommunicationsListener { - /** - * Handle an incoming message received by the Communicator - * @param communication the message that was received - */ - public void receiveCommunication(String communication); + /** + * Handle an incoming message received by the Communicator + * + * @param communication the message that was received + */ + void receiveCommunication(String communication); } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Game.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Game.java index fb971dd7fc20711414c1b9c6b9b8767c450dbc2d..c32f3c49bc0ee03a06313af22a11fd2e925dc2b2 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Game.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Game.java @@ -17,278 +17,283 @@ import java.util.Random; */ public class Game { - private static final Logger logger = LogManager.getLogger(Game.class); - - /** - * Number of rows - */ - protected final int rows; - - /** - * Number of columns - */ - protected final int cols; - - /** - * The grid model linked to the game - */ - protected final Grid grid; - - protected GamePiece currentPiece; - protected GamePiece nextPiece; - - private IntegerProperty score = new SimpleIntegerProperty(0); - private IntegerProperty level = new SimpleIntegerProperty(0); - private IntegerProperty lives = new SimpleIntegerProperty(0); - private IntegerProperty multiplier = new SimpleIntegerProperty(0); - - private int remainder = 0; - - protected NextPieceListener nextPieceHandler = null; + private static final Logger logger = LogManager.getLogger(Game.class); + + /** + * Number of rows + */ + protected final int rows; + + /** + * Number of columns + */ + protected final int cols; + + /** + * The grid model linked to the game + */ + protected final Grid grid; + + protected GamePiece currentPiece; + protected GamePiece nextPiece; + + private IntegerProperty score = new SimpleIntegerProperty(0); + private IntegerProperty level = new SimpleIntegerProperty(0); + private IntegerProperty lives = new SimpleIntegerProperty(0); + private IntegerProperty multiplier = new SimpleIntegerProperty(0); + + private int remainder = 0; + + protected NextPieceListener nextPieceHandler = null; + + /** + * Create a new game with the specified rows and columns. Creates a corresponding grid model. + * + * @param cols number of columns + * @param rows number of rows + */ + public Game(int cols, int rows) { + this.cols = cols; + this.rows = rows; + + //Create a new grid model to represent the game state + this.grid = new Grid(cols, rows); + } + + /** + * Start the game + */ + public void start() { + logger.info("Starting game"); + initialiseGame(); + } + + /** + * Initialise a new game and set up anything that needs to be done at the start + */ + public void initialiseGame() { + logger.info("Initialising game"); + + this.score.set(0); + this.level.set(0); + this.lives.set(3); + this.multiplier.set(1); + + this.nextPiece = spawnPiece(); + nextPiece(); + } + + /** + * Handle what should happen when a particular block is clicked + * + * @param gameBlock the block that was clicked + */ + public void blockClicked(GameBlock gameBlock) { + //Get the position of this block + int x = gameBlock.getX(); + int y = gameBlock.getY(); + + //Get the new value for this block + logger.info("Block clicked at x = {} y = {}", x, y); + boolean placed = grid.playPiece(currentPiece, x, y); + if (placed) { + logger.info("Placing block at x:{} y:{}", x, y); + Multimedia.playSound("place.wav"); + this.afterPiece(); + this.nextPiece(); + } else { + logger.info("Cannot place piece here"); + Multimedia.playSound("fail.wav"); + } + } - /** - * Create a new game with the specified rows and columns. Creates a corresponding grid model. - * @param cols number of columns - * @param rows number of rows - */ - public Game(int cols, int rows) { - this.cols = cols; - this.rows = rows; + public GamePiece spawnPiece() { + Random rand = new Random(); + GamePiece piece = GamePiece.createPiece(rand.nextInt(15), rand.nextInt(3)); + logger.info("Spawning piece: {}", piece); + return piece; + } - //Create a new grid model to represent the game state - this.grid = new Grid(cols,rows); - } + public GamePiece nextPiece() { + this.currentPiece = this.nextPiece; + this.nextPiece = spawnPiece(); - /** - * Start the game - */ - public void start() { - logger.info("Starting game"); - initialiseGame(); + if (this.nextPieceHandler != null) { + this.nextPieceHandler.nextPiece(this.currentPiece); } - /** - * Initialise a new game and set up anything that needs to be done at the start - */ - public void initialiseGame() { - logger.info("Initialising game"); + logger.info("Current piece is : {}", this.currentPiece); + logger.info("Next piece is: {}", this.nextPiece); - this.score.set(0); - this.level.set(0); - this.lives.set(3); - this.multiplier.set(1); + return this.currentPiece; + } - this.nextPiece = spawnPiece(); - nextPiece(); - } + public void afterPiece() { + ArrayList<Integer> fullCols = new ArrayList<>(); + ArrayList<Integer> fullRows = new ArrayList<>(); /** - * Handle what should happen when a particular block is clicked - * @param gameBlock the block that was clicked + * Check each vertical column to see if it is full */ - public void blockClicked(GameBlock gameBlock) { - //Get the position of this block - int x = gameBlock.getX(); - int y = gameBlock.getY(); - - //Get the new value for this block - logger.info("Block clicked at x = {} y = {}",x,y); - boolean placed = grid.playPiece(currentPiece, x, y); - if (placed) { - logger.info("Placing block at x:{} y:{}",x,y); - Multimedia.playSound("place.wav"); - this.afterPiece(); - this.nextPiece(); - } else { - logger.info("Cannot place piece here"); - Multimedia.playSound("fail.wav"); - } - } - - public GamePiece spawnPiece() { - Random rand = new Random(); - GamePiece piece = GamePiece.createPiece(rand.nextInt(15), rand.nextInt(3)); - logger.info("Spawning piece: {}" , piece); - return piece; - } - - public GamePiece nextPiece() { - this.currentPiece = this.nextPiece; - this.nextPiece = spawnPiece(); - - if (this.nextPieceHandler != null) { - this.nextPieceHandler.nextPiece(this.currentPiece); - } - - logger.info("Current piece is : {}", this.currentPiece); - logger.info("Next piece is: {}", this.nextPiece); - - return this.currentPiece; - } - - public void afterPiece() { - ArrayList<Integer> fullCols = new ArrayList<>(); - ArrayList<Integer> fullRows = new ArrayList<>(); - - /** - * Check each vertical column to see if it is full - */ - for (int x = 0; x < grid.getCols(); x++) { - boolean full = true; - for (int y = 0; y < grid.getRows(); y++) { - if (grid.get(x,y) == 0) { - full = false; - } - } - if (full) { - fullCols.add(x); - } - } - - /** - * Check each horizontal row to see if it is full - */ - for (int y = 0; y < grid.getCols(); y++) { - boolean full = true; - for (int x = 0; x < grid.getRows(); x++) { - if (grid.get(x,y) == 0) { - full = false; - } - } - if (full) { - fullRows.add(y); - } - } - - int numGridBlocks = 0; - - /** - * Removes all columns which are full - */ - for (int x : fullCols) { - for (int y = 0; y < grid.getCols(); y++) { - if (grid.get(x,y) != 0) { - grid.set(x,y,0); - numGridBlocks++; - } - } - } - - /** - * Removes all rows which are full - */ - for (int y : fullRows) { - for (int x = 0; x < grid.getCols(); x++) { - if (grid.get(x,y) != 0) { - grid.set(x,y,0); - numGridBlocks++; - } - } + for (int x = 0; x < grid.getCols(); x++) { + boolean full = true; + for (int y = 0; y < grid.getRows(); y++) { + if (grid.get(x, y) == 0) { + full = false; } - - - int newScore = score.get() + (fullCols.size() + fullRows.size()) * numGridBlocks * 10 * multiplier.get(); - this.setScore(newScore); - int newRemainder = score.get() % 1000; - if (newRemainder < remainder) { - this.setLevel(level.get() + 1); - remainder = 0; - } else { - remainder = newRemainder; - } - - if (fullCols.size() != 0 || fullRows.size() != 0) { - logger.info("Removing rows/columns"); - Multimedia.playSound("clear.wav"); - this.setMultiplier(multiplier.get() + 1); - } else { - this.setMultiplier(1); - } - } - - public void swapPiece() { - GamePiece tempPiece = this.currentPiece; - this.currentPiece = this.nextPiece; - this.nextPiece = tempPiece; + } + if (full) { + fullCols.add(x); + } } /** - * Get the grid model inside this game representing the game state of the board - * @return game grid model + * Check each horizontal row to see if it is full */ - public Grid getGrid() { - return grid; + for (int y = 0; y < grid.getCols(); y++) { + boolean full = true; + for (int x = 0; x < grid.getRows(); x++) { + if (grid.get(x, y) == 0) { + full = false; + } + } + if (full) { + fullRows.add(y); + } } + int numGridBlocks = 0; + /** - * Get the number of columns in this game - * @return number of columns + * Removes all columns which are full */ - public int getCols() { - return cols; + for (int x : fullCols) { + for (int y = 0; y < grid.getCols(); y++) { + if (grid.get(x, y) != 0) { + grid.set(x, y, 0); + numGridBlocks++; + } + } } /** - * Get the number of rows in this game - * @return number of rows + * Removes all rows which are full */ - public int getRows() { - return rows; - } - - public GamePiece getCurrentPiece() { - return currentPiece; - } - - public GamePiece getNextPiece() { - return nextPiece; - } - - public void setOnNextPiece(NextPieceListener handler) { - this.nextPieceHandler = handler; - } - - public void rotatePiece(int rotations) { - this.currentPiece.rotate(rotations); - } - - public IntegerProperty getLevel() { - return level; - } - - public IntegerProperty getLives() { - return lives; - } - - public IntegerProperty getScore() { - return score; - } - - public IntegerProperty getMultiplier() { - return multiplier; + for (int y : fullRows) { + for (int x = 0; x < grid.getCols(); x++) { + if (grid.get(x, y) != 0) { + grid.set(x, y, 0); + numGridBlocks++; + } + } } - public void setScore(int score) { - logger.info("Score is now " + score); - this.score.set(score); - } - public void setLevel(int level) { - logger.info("Increasing level to " + level); - Multimedia.playSound("level.wav"); - this.level.set(level); + int newScore = score.get() + (fullCols.size() + fullRows.size()) * numGridBlocks * 10 * multiplier.get(); + this.setScore(newScore); + int newRemainder = score.get() % 1000; + if (newRemainder < remainder) { + this.setLevel(level.get() + 1); + remainder = 0; + } else { + remainder = newRemainder; } - public void setLives(int lives) { - this.lives.set(lives); + if (fullCols.size() != 0 || fullRows.size() != 0) { + logger.info("Removing rows/columns"); + Multimedia.playSound("clear.wav"); + this.setMultiplier(multiplier.get() + 1); + } else { + this.setMultiplier(1); } - - public void setMultiplier(int multiplier) { - if (multiplier != 1) { - logger.info("Increasing multiplier to " + multiplier); - } else { - logger.info("Resetting multiplier"); - } - this.multiplier.set(multiplier); + } + + public void swapPiece() { + GamePiece tempPiece = this.currentPiece; + this.currentPiece = this.nextPiece; + this.nextPiece = tempPiece; + } + + /** + * Get the grid model inside this game representing the game state of the board + * + * @return game grid model + */ + public Grid getGrid() { + return grid; + } + + /** + * Get the number of columns in this game + * + * @return number of columns + */ + public int getCols() { + return cols; + } + + /** + * Get the number of rows in this game + * + * @return number of rows + */ + public int getRows() { + return rows; + } + + public GamePiece getCurrentPiece() { + return currentPiece; + } + + public GamePiece getNextPiece() { + return nextPiece; + } + + public void setOnNextPiece(NextPieceListener handler) { + this.nextPieceHandler = handler; + } + + public void rotatePiece(int rotations) { + this.currentPiece.rotate(rotations); + } + + public IntegerProperty getLevel() { + return level; + } + + public IntegerProperty getLives() { + return lives; + } + + public IntegerProperty getScore() { + return score; + } + + public IntegerProperty getMultiplier() { + return multiplier; + } + + public void setScore(int score) { + logger.info("Score is now " + score); + this.score.set(score); + } + + public void setLevel(int level) { + logger.info("Increasing level to " + level); + Multimedia.playSound("level.wav"); + this.level.set(level); + } + + public void setLives(int lives) { + this.lives.set(lives); + } + + public void setMultiplier(int multiplier) { + if (multiplier != 1) { + logger.info("Increasing multiplier to " + multiplier); + } else { + logger.info("Resetting multiplier"); } + this.multiplier.set(multiplier); + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/game/GamePiece.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/GamePiece.java index 761666e36322daf3ae4f76b08f8ac5819f30630b..627ef2de43159d5632c384b4dd519bbb585507b8 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/game/GamePiece.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/GamePiece.java @@ -2,224 +2,230 @@ package uk.ac.soton.comp1206.game; /** * Instances of GamePiece Represents the model of a specific Game Piece with it's block makeup. - * + * <p> * The GamePiece class also contains a factory for producing a GamePiece of a particular shape, as specified by it's * number. */ public class GamePiece { - /** - * The total number of pieces in this game - */ - public static final int PIECES = 15; - - /** - * The 2D grid representation of the shape of this piece - */ - private int[][] blocks; - - /** - * The value of this piece - */ - private final int value; - - /** - * The name of this piece - */ - private final String name; - - - /** - * Create a new GamePiece of the specified piece number - * @param piece piece number - * @return the created GamePiece - */ - public static GamePiece createPiece(int piece) { - switch (piece) { - //Line - case 0 -> { - int[][] blocks = {{0, 0, 0}, {1, 1, 1}, {0, 0, 0}}; - return new GamePiece("Line", blocks, 1); - } - - //C - case 1 -> { - int[][] blocks = {{0, 0, 0}, {1, 1, 1}, {1, 0, 1}}; - return new GamePiece("C", blocks, 2); - } - - //Plus - case 2 -> { - int[][] blocks = {{0, 1, 0}, {1, 1, 1}, {0, 1, 0}}; - return new GamePiece("Plus", blocks, 3); - } - - //Dot - case 3 -> { - int[][] blocks = {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}}; - return new GamePiece("Dot", blocks, 4); - } - - //Square - case 4 -> { - int[][] blocks = {{1, 1, 0}, {1, 1, 0}, {0, 0, 0}}; - return new GamePiece("Square", blocks, 5); - } - - //L - case 5 -> { - int[][] blocks = {{0, 0, 0}, {1, 1, 1}, {0, 0, 1}}; - return new GamePiece("L", blocks, 6); - } - - //J - case 6 -> { - int[][] blocks = {{0, 0, 1}, {1, 1, 1}, {0, 0, 0}}; - return new GamePiece("J", blocks, 7); - } - - //S - case 7 -> { - int[][] blocks = {{0, 0, 0}, {0, 1, 1}, {1, 1, 0}}; - return new GamePiece("S", blocks, 8); - } - - //Z - case 8 -> { - int[][] blocks = {{1, 1, 0}, {0, 1, 1}, {0, 0, 0}}; - return new GamePiece("Z", blocks, 9); - } - - //T - case 9 -> { - int[][] blocks = {{1, 0, 0}, {1, 1, 0}, {1, 0, 0}}; - return new GamePiece("T", blocks, 10); - } - - //X - case 10 -> { - int[][] blocks = {{1, 0, 1}, {0, 1, 0}, {1, 0, 1}}; - return new GamePiece("X", blocks, 11); - } - - //Corner - case 11 -> { - int[][] blocks = {{0, 0, 0}, {1, 1, 0}, {1, 0, 0}}; - return new GamePiece("Corner", blocks, 12); - } - - //Inverse Corner - case 12 -> { - int[][] blocks = {{1, 0, 0}, {1, 1, 0}, {0, 0, 0}}; - return new GamePiece("Inverse Corner", blocks, 13); - } - - //Diagonal - case 13 -> { - int[][] blocks = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; - return new GamePiece("Diagonal", blocks, 14); - } - - //Double - case 14 -> { - int[][] blocks = {{0, 1, 0}, {0, 1, 0}, {0, 0, 0}}; - return new GamePiece("Double", blocks, 15); - } - } - - //Not a valid piece number - throw new IndexOutOfBoundsException("No such piece: " + piece); + /** + * The total number of pieces in this game + */ + public static final int PIECES = 15; + + /** + * The 2D grid representation of the shape of this piece + */ + private int[][] blocks; + + /** + * The value of this piece + */ + private final int value; + + /** + * The name of this piece + */ + private final String name; + + + /** + * Create a new GamePiece of the specified piece number + * + * @param piece piece number + * @return the created GamePiece + */ + public static GamePiece createPiece(int piece) { + switch (piece) { + //Line + case 0 -> { + int[][] blocks = {{0, 0, 0}, {1, 1, 1}, {0, 0, 0}}; + return new GamePiece("Line", blocks, 1); + } + + //C + case 1 -> { + int[][] blocks = {{0, 0, 0}, {1, 1, 1}, {1, 0, 1}}; + return new GamePiece("C", blocks, 2); + } + + //Plus + case 2 -> { + int[][] blocks = {{0, 1, 0}, {1, 1, 1}, {0, 1, 0}}; + return new GamePiece("Plus", blocks, 3); + } + + //Dot + case 3 -> { + int[][] blocks = {{0, 0, 0}, {0, 1, 0}, {0, 0, 0}}; + return new GamePiece("Dot", blocks, 4); + } + + //Square + case 4 -> { + int[][] blocks = {{1, 1, 0}, {1, 1, 0}, {0, 0, 0}}; + return new GamePiece("Square", blocks, 5); + } + + //L + case 5 -> { + int[][] blocks = {{0, 0, 0}, {1, 1, 1}, {0, 0, 1}}; + return new GamePiece("L", blocks, 6); + } + + //J + case 6 -> { + int[][] blocks = {{0, 0, 1}, {1, 1, 1}, {0, 0, 0}}; + return new GamePiece("J", blocks, 7); + } + + //S + case 7 -> { + int[][] blocks = {{0, 0, 0}, {0, 1, 1}, {1, 1, 0}}; + return new GamePiece("S", blocks, 8); + } + + //Z + case 8 -> { + int[][] blocks = {{1, 1, 0}, {0, 1, 1}, {0, 0, 0}}; + return new GamePiece("Z", blocks, 9); + } + + //T + case 9 -> { + int[][] blocks = {{1, 0, 0}, {1, 1, 0}, {1, 0, 0}}; + return new GamePiece("T", blocks, 10); + } + + //X + case 10 -> { + int[][] blocks = {{1, 0, 1}, {0, 1, 0}, {1, 0, 1}}; + return new GamePiece("X", blocks, 11); + } + + //Corner + case 11 -> { + int[][] blocks = {{0, 0, 0}, {1, 1, 0}, {1, 0, 0}}; + return new GamePiece("Corner", blocks, 12); + } + + //Inverse Corner + case 12 -> { + int[][] blocks = {{1, 0, 0}, {1, 1, 0}, {0, 0, 0}}; + return new GamePiece("Inverse Corner", blocks, 13); + } + + //Diagonal + case 13 -> { + int[][] blocks = {{1, 0, 0}, {0, 1, 0}, {0, 0, 1}}; + return new GamePiece("Diagonal", blocks, 14); + } + + //Double + case 14 -> { + int[][] blocks = {{0, 1, 0}, {0, 1, 0}, {0, 0, 0}}; + return new GamePiece("Double", blocks, 15); + } } - /** - * Create a new GamePiece of the specified piece number and rotation - * @param piece piece number - * @param rotation number of times to rotate - * @return the created GamePiece - */ - public static GamePiece createPiece(int piece, int rotation) { - var newPiece = createPiece(piece); - - newPiece.rotate(rotation); - return newPiece; + //Not a valid piece number + throw new IndexOutOfBoundsException("No such piece: " + piece); + } + + /** + * Create a new GamePiece of the specified piece number and rotation + * + * @param piece piece number + * @param rotation number of times to rotate + * @return the created GamePiece + */ + public static GamePiece createPiece(int piece, int rotation) { + var newPiece = createPiece(piece); + + newPiece.rotate(rotation); + return newPiece; + } + + /** + * Create a new GamePiece with the given name, block makeup and value. Should not be called directly, only via the + * factory. + * + * @param name name of the piece + * @param blocks block makeup of the piece + * @param value the value of this piece + */ + private GamePiece(String name, int[][] blocks, int value) { + this.name = name; + this.blocks = blocks; + this.value = value; + + //Use the shape of the block to create a grid with either 0 (empty) or the value of this shape for each block. + for (int x = 0; x < blocks.length; x++) { + for (int y = 0; y < blocks[x].length; y++) { + if (blocks[x][y] == 0) continue; + blocks[x][y] = value; + } } - - /** - * Create a new GamePiece with the given name, block makeup and value. Should not be called directly, only via the - * factory. - * @param name name of the piece - * @param blocks block makeup of the piece - * @param value the value of this piece - */ - private GamePiece(String name, int[][] blocks, int value) { - this.name = name; - this.blocks = blocks; - this.value = value; - - //Use the shape of the block to create a grid with either 0 (empty) or the value of this shape for each block. - for(int x = 0; x < blocks.length; x++) { - for (int y = 0; y < blocks[x].length; y++) { - if(blocks[x][y] == 0) continue; - blocks[x][y] = value; - } - } - } - - /** - * Get the value of this piece - * @return piece value - */ - public int getValue() { - return value; - } - - /** - * Get the block makeup of this piece - * @return 2D grid of the blocks representing the piece shape - */ - public int[][] getBlocks() { - return blocks; - } - - /** - * Rotate this piece the given number of rotations - * @param rotations number of rotations - */ - public void rotate(int rotations) { - for(int rotated = 0; rotated < rotations; rotated ++) { - rotate(); - } - } - - /** - * Rotate this piece exactly once by rotating it's 3x3 grid - */ - public void rotate() { - int[][] rotated = new int[blocks.length][blocks[0].length]; - rotated[2][0] = blocks[0][0]; - rotated[1][0] = blocks[0][1]; - rotated[0][0] = blocks[0][2]; - - rotated[2][1] = blocks[1][0]; - rotated[1][1] = blocks[1][1]; - rotated[0][1] = blocks[1][2]; - - rotated[2][2] = blocks[2][0]; - rotated[1][2] = blocks[2][1]; - rotated[0][2] = blocks[2][2]; - - blocks = rotated; + } + + /** + * Get the value of this piece + * + * @return piece value + */ + public int getValue() { + return value; + } + + /** + * Get the block makeup of this piece + * + * @return 2D grid of the blocks representing the piece shape + */ + public int[][] getBlocks() { + return blocks; + } + + /** + * Rotate this piece the given number of rotations + * + * @param rotations number of rotations + */ + public void rotate(int rotations) { + for (int rotated = 0; rotated < rotations; rotated++) { + rotate(); } - - - /** - * Return the string representation of this piece - * @return the name of this piece - */ - public String toString() { - return this.name; - } - + } + + /** + * Rotate this piece exactly once by rotating it's 3x3 grid + */ + public void rotate() { + int[][] rotated = new int[blocks.length][blocks[0].length]; + rotated[2][0] = blocks[0][0]; + rotated[1][0] = blocks[0][1]; + rotated[0][0] = blocks[0][2]; + + rotated[2][1] = blocks[1][0]; + rotated[1][1] = blocks[1][1]; + rotated[0][1] = blocks[1][2]; + + rotated[2][2] = blocks[2][0]; + rotated[1][2] = blocks[2][1]; + rotated[0][2] = blocks[2][2]; + + blocks = rotated; + } + + + /** + * Return the string representation of this piece + * + * @return the name of this piece + */ + public String toString() { + return this.name; + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Grid.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Grid.java index 1e66ea3ae457426cbc9587f4ee9f0885da94d37f..133f8973e970894317c3e1e6d446c994849161c8 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Grid.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Grid.java @@ -10,143 +10,149 @@ import uk.ac.soton.comp1206.utility.Multimedia; /** * The Grid is a model which holds the state of a game board. It is made up of a set of Integer values arranged in a 2D * arrow, with rows and columns. - * + * <p> * Each value inside the Grid is an IntegerProperty can be bound to enable modification and display of the contents of * the grid. - * + * <p> * The Grid contains functions related to modifying the model, for example, placing a piece inside the grid. - * + * <p> * The Grid should be linked to a GameBoard for it's display. */ public class Grid { - private static final Logger logger = LogManager.getLogger(App.class); - /** - * The number of columns in this grid - */ - private final int cols; - - /** - * The number of rows in this grid - */ - private final int rows; - - /** - * The grid is a 2D arrow with rows and columns of SimpleIntegerProperties. - */ - private final SimpleIntegerProperty[][] grid; - - /** - * Create a new Grid with the specified number of columns and rows and initialise them - * @param cols number of columns - * @param rows number of rows - */ - public Grid(int cols, int rows) { - this.cols = cols; - this.rows = rows; - - //Create the grid itself - grid = new SimpleIntegerProperty[cols][rows]; - - //Add a SimpleIntegerProperty to every block in the grid - for(var y = 0; y < rows; y++) { - for(var x = 0; x < cols; x++) { - grid[x][y] = new SimpleIntegerProperty(0); - } - } - } - - /** - * Get the Integer property contained inside the grid at a given row and column index. Can be used for binding. - * @param x column - * @param y row - * @return the IntegerProperty at the given x and y in this grid - */ - public IntegerProperty getGridProperty(int x, int y) { - return grid[x][y]; - } - - /** - * Update the value at the given x and y index within the grid - * @param x column - * @param y row - * @param value the new value - */ - public void set(int x, int y, int value) { - grid[x][y].set(value); - } - - /** - * Get the value represented at the given x and y index within the grid - * @param x column - * @param y row - * @return the value - */ - public int get(int x, int y) { - try { - //Get the value held in the property at the x and y index provided - return grid[x][y].get(); - } catch (ArrayIndexOutOfBoundsException e) { - //No such index - return -1; - } - } - - public boolean canPlayPiece(GamePiece gamePiece, int placeX, int placeY) { - int[][] blocks = gamePiece.getBlocks(); - placeX = placeX - 1; - placeY = placeY - 1; - - for (int x = 0; x < blocks.length; x++) { - for (int y = 0; y < blocks[x].length; y++) { - int value = blocks[x][y]; - if (value == 0) continue; - if (get(x + placeX, y + placeY) != 0) { - return false; - } - } - } - return true; + private static final Logger logger = LogManager.getLogger(App.class); + /** + * The number of columns in this grid + */ + private final int cols; + + /** + * The number of rows in this grid + */ + private final int rows; + + /** + * The grid is a 2D arrow with rows and columns of SimpleIntegerProperties. + */ + private final SimpleIntegerProperty[][] grid; + + /** + * Create a new Grid with the specified number of columns and rows and initialise them + * + * @param cols number of columns + * @param rows number of rows + */ + public Grid(int cols, int rows) { + this.cols = cols; + this.rows = rows; + + //Create the grid itself + grid = new SimpleIntegerProperty[cols][rows]; + + //Add a SimpleIntegerProperty to every block in the grid + for (var y = 0; y < rows; y++) { + for (var x = 0; x < cols; x++) { + grid[x][y] = new SimpleIntegerProperty(0); + } } - - public boolean playPiece(GamePiece gamePiece, int placeX, int placeY) { - if (!this.canPlayPiece(gamePiece, placeX, placeY)) return false; - - int[][] blocks = gamePiece.getBlocks(); - placeX = placeX - 1; - placeY = placeY - 1; - - for (int x = 0; x < blocks.length; x++) { - for (int y = 0; y < blocks[x].length; y++) { - int value = blocks[x][y]; - if (value == 0) continue; - set(x + placeX, y + placeY, value); - } - } - return true; + } + + /** + * Get the Integer property contained inside the grid at a given row and column index. Can be used for binding. + * + * @param x column + * @param y row + * @return the IntegerProperty at the given x and y in this grid + */ + public IntegerProperty getGridProperty(int x, int y) { + return grid[x][y]; + } + + /** + * Update the value at the given x and y index within the grid + * + * @param x column + * @param y row + * @param value the new value + */ + public void set(int x, int y, int value) { + grid[x][y].set(value); + } + + /** + * Get the value represented at the given x and y index within the grid + * + * @param x column + * @param y row + * @return the value + */ + public int get(int x, int y) { + try { + //Get the value held in the property at the x and y index provided + return grid[x][y].get(); + } catch (ArrayIndexOutOfBoundsException e) { + //No such index + return -1; } - - public void clear() { - for (int y = 0; y < this.rows; y++) { - for (int x = 0; x < this.cols; x++) { - this.grid[x][y].set(0); - } + } + + public boolean canPlayPiece(GamePiece gamePiece, int placeX, int placeY) { + int[][] blocks = gamePiece.getBlocks(); + placeX = placeX - 1; + placeY = placeY - 1; + + for (int x = 0; x < blocks.length; x++) { + for (int y = 0; y < blocks[x].length; y++) { + int value = blocks[x][y]; + if (value == 0) continue; + if (get(x + placeX, y + placeY) != 0) { + return false; } + } } - - /** - * Get the number of columns in this game - * @return number of columns - */ - public int getCols() { - return cols; + return true; + } + + public boolean playPiece(GamePiece gamePiece, int placeX, int placeY) { + if (!this.canPlayPiece(gamePiece, placeX, placeY)) return false; + + int[][] blocks = gamePiece.getBlocks(); + placeX = placeX - 1; + placeY = placeY - 1; + + for (int x = 0; x < blocks.length; x++) { + for (int y = 0; y < blocks[x].length; y++) { + int value = blocks[x][y]; + if (value == 0) continue; + set(x + placeX, y + placeY, value); + } } - - /** - * Get the number of rows in this game - * @return number of rows - */ - public int getRows() { - return rows; + return true; + } + + public void clear() { + for (int y = 0; y < this.rows; y++) { + for (int x = 0; x < this.cols; x++) { + this.grid[x][y].set(0); + } } + } + + /** + * Get the number of columns in this game + * + * @return number of columns + */ + public int getCols() { + return cols; + } + + /** + * Get the number of rows in this game + * + * @return number of rows + */ + public int getRows() { + return rows; + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/network/Communicator.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/network/Communicator.java index 5af9474f8e91f58b6b8e43d116bcf37420f7ff91..8bc4c2586963056c4612d9bfef7066373011f516 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/network/Communicator.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/network/Communicator.java @@ -11,113 +11,119 @@ import java.util.List; /** * Uses web sockets to talk to a web socket server and relays communication to attached listeners - * + * <p> * YOU DO NOT NEED TO WORRY ABOUT THIS CLASS! Leave it be :-) */ public class Communicator { - private static final Logger logger = LogManager.getLogger(Communicator.class); - - /** - * Attached communication listeners listening to messages on this Communicator. Each will be sent any messages. - */ - private final List<CommunicationsListener> handlers = new ArrayList<>(); - - private WebSocket ws = null; - - /** - * Create a new communicator to the given web socket server - * - * @param server server to connect to - */ - public Communicator(String server) { - - try { - var socketFactory = new WebSocketFactory(); - - //Connect to the server - ws = socketFactory.createSocket(server); - ws.connect(); - logger.info("Connected to " + server); - - //When a message is received, call the receive method - ws.addListener(new WebSocketAdapter() { - @Override - public void onTextMessage(WebSocket websocket, String message) throws Exception { - Communicator.this.receive(websocket, message); - } - @Override - public void onPingFrame(WebSocket webSocket, WebSocketFrame webSocketFrame) throws Exception { - logger.info("Ping? Pong!"); - } - }); - - //Error handling - ws.addListener(new WebSocketAdapter() { - @Override - public void onTextMessage(WebSocket websocket, String message) throws Exception { - if(message.startsWith("ERROR")) { - logger.error(message); - } - } - @Override - public void handleCallbackError(WebSocket webSocket, Throwable throwable) throws Exception { - logger.error("Callback Error:" + throwable.getMessage()); - throwable.printStackTrace(); - } - @Override - public void onError(WebSocket webSocket, WebSocketException e) throws Exception { - logger.error("Error:" + e.getMessage()); - e.printStackTrace(); - } - }); - - } catch (Exception e){ - logger.error("Socket error: " + e.getMessage()); - e.printStackTrace(); - - Alert error = new Alert(Alert.AlertType.ERROR,"Unable to communicate with the TetrECS server\n\n" + e.getMessage() + "\n\nPlease ensure you are connected to the VPN"); - error.showAndWait(); - System.exit(1); - } - } + private static final Logger logger = LogManager.getLogger(Communicator.class); - /** Send a message to the server - * - * @param message Message to send - */ - public void send(String message) { - logger.info("Sending message: " + message); + /** + * Attached communication listeners listening to messages on this Communicator. Each will be sent any messages. + */ + private final List<CommunicationsListener> handlers = new ArrayList<>(); - ws.sendText(message); - } + private WebSocket ws = null; - /** - * Add a new listener to receive messages from the server - * @param listener the listener to add - */ - public void addListener(CommunicationsListener listener) { - this.handlers.add(listener); - } + /** + * Create a new communicator to the given web socket server + * + * @param server server to connect to + */ + public Communicator(String server) { - /** - * Clear all current listeners - */ - public void clearListeners() { - this.handlers.clear(); - } + try { + var socketFactory = new WebSocketFactory(); + + //Connect to the server + ws = socketFactory.createSocket(server); + ws.connect(); + logger.info("Connected to " + server); - /** Receive a message from the server. Relay to any attached listeners - * - * @param websocket the socket - * @param message the message that was received - */ - private void receive(WebSocket websocket, String message) { - logger.info("Received: " + message); + //When a message is received, call the receive method + ws.addListener(new WebSocketAdapter() { + @Override + public void onTextMessage(WebSocket websocket, String message) throws Exception { + Communicator.this.receive(websocket, message); + } - for(CommunicationsListener handler : handlers) { - handler.receiveCommunication(message); + @Override + public void onPingFrame(WebSocket webSocket, WebSocketFrame webSocketFrame) throws Exception { + logger.info("Ping? Pong!"); + } + }); + + //Error handling + ws.addListener(new WebSocketAdapter() { + @Override + public void onTextMessage(WebSocket websocket, String message) throws Exception { + if (message.startsWith("ERROR")) { + logger.error(message); + } } + + @Override + public void handleCallbackError(WebSocket webSocket, Throwable throwable) throws Exception { + logger.error("Callback Error:" + throwable.getMessage()); + throwable.printStackTrace(); + } + + @Override + public void onError(WebSocket webSocket, WebSocketException e) throws Exception { + logger.error("Error:" + e.getMessage()); + e.printStackTrace(); + } + }); + + } catch (Exception e) { + logger.error("Socket error: " + e.getMessage()); + e.printStackTrace(); + + Alert error = new Alert(Alert.AlertType.ERROR, "Unable to communicate with the TetrECS server\n\n" + e.getMessage() + "\n\nPlease ensure you are connected to the VPN"); + error.showAndWait(); + System.exit(1); + } + } + + /** + * Send a message to the server + * + * @param message Message to send + */ + public void send(String message) { + logger.info("Sending message: " + message); + + ws.sendText(message); + } + + /** + * Add a new listener to receive messages from the server + * + * @param listener the listener to add + */ + public void addListener(CommunicationsListener listener) { + this.handlers.add(listener); + } + + /** + * Clear all current listeners + */ + public void clearListeners() { + this.handlers.clear(); + } + + /** + * Receive a message from the server. Relay to any attached listeners + * + * @param websocket the socket + * @param message the message that was received + */ + private void receive(WebSocket websocket, String message) { + logger.info("Received: " + message); + + for (CommunicationsListener handler : handlers) { + handler.receiveCommunication(message); } + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/BaseScene.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/BaseScene.java index 3c3156fd2f0835840a53fea6fe559dafa2f3f60c..6fbc7dda31698ecca6988cf842c6ce66e3639dd5 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/BaseScene.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/BaseScene.java @@ -10,47 +10,50 @@ import uk.ac.soton.comp1206.ui.GameWindow; */ public abstract class BaseScene { - protected final GameWindow gameWindow; - - protected GamePane root; - protected Scene scene; - - /** - * Create a new scene, passing in the GameWindow the scene will be displayed in - * @param gameWindow the game window - */ - public BaseScene(GameWindow gameWindow) { - this.gameWindow = gameWindow; - } - - /** - * Initialise this scene. Called after creation - */ - public abstract void initialise(); - - /** - * Build the layout of the scene - */ - public abstract void build(); - - /** - * Create a new JavaFX scene using the root contained within this scene - * @return JavaFX scene - */ - public Scene setScene() { - var previous = gameWindow.getScene(); - Scene scene = new Scene(root, previous.getWidth(), previous.getHeight(), Color.BLACK); - scene.getStylesheets().add(getClass().getResource("/style/game.css").toExternalForm()); - this.scene = scene; - return scene; - } - - /** - * Get the JavaFX scene contained inside - * @return JavaFX scene - */ - public Scene getScene() { - return this.scene; - } + protected final GameWindow gameWindow; + + protected GamePane root; + protected Scene scene; + + /** + * Create a new scene, passing in the GameWindow the scene will be displayed in + * + * @param gameWindow the game window + */ + public BaseScene(GameWindow gameWindow) { + this.gameWindow = gameWindow; + } + + /** + * Initialise this scene. Called after creation + */ + public abstract void initialise(); + + /** + * Build the layout of the scene + */ + public abstract void build(); + + /** + * Create a new JavaFX scene using the root contained within this scene + * + * @return JavaFX scene + */ + public Scene setScene() { + var previous = gameWindow.getScene(); + Scene scene = new Scene(root, previous.getWidth(), previous.getHeight(), Color.BLACK); + scene.getStylesheets().add(getClass().getResource("/style/game.css").toExternalForm()); + this.scene = scene; + return scene; + } + + /** + * Get the JavaFX scene contained inside + * + * @return JavaFX scene + */ + public Scene getScene() { + return this.scene; + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ChallengeScene.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ChallengeScene.java index d2461ba4f84ec4c067861b96091b054b833ac55a..265a260626d90bbe60b8352d5ca92bd12906b49e 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ChallengeScene.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/ChallengeScene.java @@ -27,202 +27,204 @@ import java.util.ArrayList; */ public class ChallengeScene extends BaseScene { - private static final Logger logger = LogManager.getLogger(MenuScene.class); - protected Game game; + private static final Logger logger = LogManager.getLogger(MenuScene.class); + protected Game game; - protected GameBoard board; - protected PieceBoard currentPieceBoard; - protected PieceBoard nextPieceBoard; + protected GameBoard board; + protected PieceBoard currentPieceBoard; + protected PieceBoard nextPieceBoard; - /** - * Create a new Single Player challenge scene - * @param gameWindow the Game Window - */ - public ChallengeScene(GameWindow gameWindow) { - super(gameWindow); - logger.info("Creating Challenge Scene"); - } + /** + * Create a new Single Player challenge scene + * + * @param gameWindow the Game Window + */ + public ChallengeScene(GameWindow gameWindow) { + super(gameWindow); + logger.info("Creating Challenge Scene"); + } - /** - * Build the Challenge window - */ - @Override - public void build() { - logger.info("Building " + this.getClass().getName()); + /** + * Build the Challenge window + */ + @Override + public void build() { + logger.info("Building " + this.getClass().getName()); - setupGame(); + setupGame(); - root = new GamePane(gameWindow.getWidth(),gameWindow.getHeight()); + root = new GamePane(gameWindow.getWidth(), gameWindow.getHeight()); - StackPane challengePane = new StackPane(); - challengePane.setMaxWidth(gameWindow.getWidth()); - challengePane.setMaxHeight(gameWindow.getHeight()); - challengePane.getStyleClass().add("menu-background"); - root.getChildren().add(challengePane); + StackPane challengePane = new StackPane(); + challengePane.setMaxWidth(gameWindow.getWidth()); + challengePane.setMaxHeight(gameWindow.getHeight()); + challengePane.getStyleClass().add("menu-background"); + root.getChildren().add(challengePane); - var mainPane = new BorderPane(); - challengePane.getChildren().add(mainPane); + var mainPane = new BorderPane(); + challengePane.getChildren().add(mainPane); - //Header of Challenge Scene - HBox header = buildHeader(); + //Header of Challenge Scene + HBox header = buildHeader(); - mainPane.setTop(header); + mainPane.setTop(header); - HBox boards = buildBoards(); + HBox boards = buildBoards(); - mainPane.setCenter(boards); + mainPane.setCenter(boards); - } + } - public HBox buildHeader() { - //Header of Challenge Scene - HBox header = new HBox(); + public HBox buildHeader() { + //Header of Challenge Scene + HBox header = new HBox(); - //VBox to hold the Score title and value - VBox scoreBox = new VBox(); - var scoreTitle = new Text("Score"); - scoreTitle.getStyleClass().add("heading"); - var scoreValue = new Text(); - scoreValue.textProperty().bind(game.getScore().asString()); - scoreValue.getStyleClass().add("score"); - scoreBox.getChildren().addAll(scoreTitle,scoreValue); - scoreBox.setAlignment(Pos.BASELINE_CENTER); + //VBox to hold the Score title and value + VBox scoreBox = new VBox(); + var scoreTitle = new Text("Score"); + scoreTitle.getStyleClass().add("heading"); + var scoreValue = new Text(); + scoreValue.textProperty().bind(game.getScore().asString()); + scoreValue.getStyleClass().add("score"); + scoreBox.getChildren().addAll(scoreTitle, scoreValue); + scoreBox.setAlignment(Pos.BASELINE_CENTER); - header.getChildren().add(scoreBox); + header.getChildren().add(scoreBox); - //Challenge scene title - var challengeTitle = new Text("Challenge Mode"); - challengeTitle.getStyleClass().add("title"); - header.getChildren().add(challengeTitle); + //Challenge scene title + var challengeTitle = new Text("Challenge Mode"); + challengeTitle.getStyleClass().add("title"); + header.getChildren().add(challengeTitle); - //VBox to store lives title and value - VBox livesBox = new VBox(); - var livesTitle = new Text("Lives"); - livesTitle.getStyleClass().add("heading"); - var livesValue = new Text(); - livesValue.textProperty().bind(game.getLives().asString()); - livesValue.getStyleClass().add("lives"); - livesBox.getChildren().addAll(livesTitle,livesValue); - livesBox.setAlignment(Pos.BASELINE_CENTER); + //VBox to store lives title and value + VBox livesBox = new VBox(); + var livesTitle = new Text("Lives"); + livesTitle.getStyleClass().add("heading"); + var livesValue = new Text(); + livesValue.textProperty().bind(game.getLives().asString()); + livesValue.getStyleClass().add("lives"); + livesBox.getChildren().addAll(livesTitle, livesValue); + livesBox.setAlignment(Pos.BASELINE_CENTER); + + header.getChildren().add(livesBox); - header.getChildren().add(livesBox); + header.setAlignment(Pos.CENTER); + header.setSpacing(140); + + return header; + } + + public HBox buildBoards() { + HBox boards = new HBox(); + + this.board = new GameBoard(game.getGrid(), gameWindow.getWidth() / 2, gameWindow.getWidth() / 2); + //Handle block on gameboard grid being clicked + this.board.setOnBlockClick(this::blockClicked); + this.board.setOnRightClick(this::rotateBlock); + + boards.getChildren().add(this.board); + + VBox gameInfo = new VBox(); + + var hiScoreTitle = new Text("High Score"); + hiScoreTitle.getStyleClass().add("heading"); + gameInfo.getChildren().add(hiScoreTitle); + + var hiScoreVal = new Text("10000"); + hiScoreVal.getStyleClass().add("hiscore"); + gameInfo.getChildren().add(hiScoreVal); + + var levelTitle = new Text("Level"); + levelTitle.getStyleClass().add("heading"); + gameInfo.getChildren().add(levelTitle); + + var levelVal = new Text(); + levelVal.textProperty().bind(game.getLevel().asString()); + levelVal.getStyleClass().add("level"); + gameInfo.getChildren().add(levelVal); + + var incomingTitle = new Text("Incoming"); + incomingTitle.getStyleClass().add("heading"); + gameInfo.getChildren().add(incomingTitle); - header.setAlignment(Pos.CENTER); - header.setSpacing(140); - - return header; - } - - public HBox buildBoards() { - HBox boards = new HBox(); - - this.board = new GameBoard(game.getGrid(),gameWindow.getWidth()/2,gameWindow.getWidth()/2); - //Handle block on gameboard grid being clicked - this.board.setOnBlockClick(this::blockClicked); - this.board.setOnRightClick(this::rotateBlock); - - boards.getChildren().add(this.board); - - VBox gameInfo = new VBox(); - - var hiScoreTitle = new Text("High Score"); - hiScoreTitle.getStyleClass().add("heading"); - gameInfo.getChildren().add(hiScoreTitle); - - var hiScoreVal = new Text("10000"); - hiScoreVal.getStyleClass().add("hiscore"); - gameInfo.getChildren().add(hiScoreVal); - - var levelTitle = new Text("Level"); - levelTitle.getStyleClass().add("heading"); - gameInfo.getChildren().add(levelTitle); - - var levelVal = new Text(); - levelVal.textProperty().bind(game.getLevel().asString()); - levelVal.getStyleClass().add("level"); - gameInfo.getChildren().add(levelVal); - - var incomingTitle = new Text("Incoming"); - incomingTitle.getStyleClass().add("heading"); - gameInfo.getChildren().add(incomingTitle); + this.currentPieceBoard = new PieceBoard(gameWindow.getWidth() / 6, gameWindow.getWidth() / 6); + this.currentPieceBoard.setOnClick(this::rotateBlock); + gameInfo.getChildren().add(this.currentPieceBoard); - this.currentPieceBoard = new PieceBoard(gameWindow.getWidth()/6, gameWindow.getWidth()/6); - this.currentPieceBoard.setOnClick(this::rotateBlock); - gameInfo.getChildren().add(this.currentPieceBoard); - - this.nextPieceBoard = new PieceBoard(gameWindow.getWidth()/10, gameWindow.getWidth()/10); - this.nextPieceBoard.setOnClick(this::swapPiece); - gameInfo.getChildren().add(this.nextPieceBoard); - - gameInfo.setAlignment(Pos.CENTER); - gameInfo.setSpacing(10); - - boards.getChildren().add(gameInfo); - - boards.setAlignment(Pos.CENTER); - boards.setSpacing(100); - - return boards; - } - - private void swapPiece(GameBlock gameBlock) { - logger.info("Swapping current and next piece"); - this.currentPieceBoard.displayPiece(this.game.getNextPiece()); - this.nextPieceBoard.displayPiece(this.game.getCurrentPiece()); - this.game.swapPiece(); - } - - /** - * Handle when a block is clicked - * @param gameBlock the Game Block that was clocked - */ - private void blockClicked(GameBlock gameBlock) { - game.blockClicked(gameBlock); - } - - private void rotateBlock(int rotations) { - logger.info("Rotating block"); - Multimedia.playSound("rotate.wav"); - this.game.rotatePiece(rotations); - this.currentPieceBoard.displayPiece(this.game.getCurrentPiece()); - } - - private void rotateBlock(GameBlock gameBlock) { - rotateBlock(1); - } - - private void rotateBlock() { - rotateBlock(1); - } - - /** - * Setup the game object and model - */ - public void setupGame() { - logger.info("Starting a new challenge"); - - //Start new game - game = new Game(5, 5); - } - - /** - * Initialise the scene and start the game - */ - @Override - public void initialise() { - logger.info("Initialising Challenge"); - Multimedia.playBackgroundMusic("game_start.wav", false); - Multimedia.getBackgroundPlayer().setOnEndOfMedia(() -> Multimedia.playBackgroundMusic("game.wav", true)); - - this.game.setOnNextPiece(this::nextPiece); - game.start(); - } - - protected void nextPiece(GamePiece nextPiece) { - logger.info("Next piece to place: " + nextPiece); - this.currentPieceBoard.displayPiece(nextPiece); - this.nextPieceBoard.displayPiece(this.game.getNextPiece()); - } + this.nextPieceBoard = new PieceBoard(gameWindow.getWidth() / 10, gameWindow.getWidth() / 10); + this.nextPieceBoard.setOnClick(this::swapPiece); + gameInfo.getChildren().add(this.nextPieceBoard); + + gameInfo.setAlignment(Pos.CENTER); + gameInfo.setSpacing(10); + + boards.getChildren().add(gameInfo); + + boards.setAlignment(Pos.CENTER); + boards.setSpacing(100); + + return boards; + } + + private void swapPiece(GameBlock gameBlock) { + logger.info("Swapping current and next piece"); + this.currentPieceBoard.displayPiece(this.game.getNextPiece()); + this.nextPieceBoard.displayPiece(this.game.getCurrentPiece()); + this.game.swapPiece(); + } + + /** + * Handle when a block is clicked + * + * @param gameBlock the Game Block that was clocked + */ + private void blockClicked(GameBlock gameBlock) { + game.blockClicked(gameBlock); + } + + private void rotateBlock(int rotations) { + logger.info("Rotating block"); + Multimedia.playSound("rotate.wav"); + this.game.rotatePiece(rotations); + this.currentPieceBoard.displayPiece(this.game.getCurrentPiece()); + } + + private void rotateBlock(GameBlock gameBlock) { + rotateBlock(1); + } + + private void rotateBlock() { + rotateBlock(1); + } + + /** + * Setup the game object and model + */ + public void setupGame() { + logger.info("Starting a new challenge"); + + //Start new game + game = new Game(5, 5); + } + + /** + * Initialise the scene and start the game + */ + @Override + public void initialise() { + logger.info("Initialising Challenge"); + Multimedia.playBackgroundMusic("game_start.wav", false); + Multimedia.getBackgroundPlayer().setOnEndOfMedia(() -> Multimedia.playBackgroundMusic("game.wav", true)); + + this.game.setOnNextPiece(this::nextPiece); + game.start(); + } + + protected void nextPiece(GamePiece nextPiece) { + logger.info("Next piece to place: " + nextPiece); + this.currentPieceBoard.displayPiece(nextPiece); + this.nextPieceBoard.displayPiece(this.game.getNextPiece()); + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/MenuScene.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/MenuScene.java index 82084aaab7fd8b26cd25dc49e8694052fec131c2..c5797a53fdbb7e27bbb450881006b9e6d5f2b352 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/MenuScene.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/scene/MenuScene.java @@ -17,78 +17,80 @@ import uk.ac.soton.comp1206.utility.Multimedia; */ public class MenuScene extends BaseScene { - private static final Logger logger = LogManager.getLogger(MenuScene.class); - - /** - * Create a new menu scene - * @param gameWindow the Game Window this will be displayed in - */ - public MenuScene(GameWindow gameWindow) { - super(gameWindow); - logger.info("Creating Menu Scene"); - } - - /** - * Build the menu layout - */ - @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); - - VBox menuWidgets = new VBox(); - - Region space = new Region(); - space.setPrefHeight(100); - HBox.setHgrow(space,Priority.ALWAYS); - menuWidgets.getChildren().add(space); - - //Awful title - var title = new Text("TetrECS"); - title.getStyleClass().add("bigtitle"); - menuWidgets.getChildren().add(title); - - VBox menuButtons = new VBox(); - - var singlePlay = new Text("Single Player"); - singlePlay.getStyleClass().add("menuItem"); - singlePlay.setOnMouseClicked(this::startGame); - menuButtons.getChildren().add(singlePlay); - - menuButtons.setAlignment(Pos.CENTER); - menuWidgets.setAlignment(Pos.CENTER); - - mainPane.setTop(menuWidgets); - mainPane.setCenter(menuButtons); - - Multimedia.playBackgroundMusic("menu.mp3", true); - } - - /** - * Initialise the menu - */ - @Override - public void initialise() { - - } - - /** - * Handle when the Start Game button is pressed - * @param event event - */ - private void startGame(MouseEvent event) { - Multimedia.stopSound(); - gameWindow.startChallenge(); - } + private static final Logger logger = LogManager.getLogger(MenuScene.class); + + /** + * Create a new menu scene + * + * @param gameWindow the Game Window this will be displayed in + */ + public MenuScene(GameWindow gameWindow) { + super(gameWindow); + logger.info("Creating Menu Scene"); + } + + /** + * Build the menu layout + */ + @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); + + VBox menuWidgets = new VBox(); + + Region space = new Region(); + space.setPrefHeight(100); + HBox.setHgrow(space, Priority.ALWAYS); + menuWidgets.getChildren().add(space); + + //Awful title + var title = new Text("TetrECS"); + title.getStyleClass().add("bigtitle"); + menuWidgets.getChildren().add(title); + + VBox menuButtons = new VBox(); + + var singlePlay = new Text("Single Player"); + singlePlay.getStyleClass().add("menuItem"); + singlePlay.setOnMouseClicked(this::startGame); + menuButtons.getChildren().add(singlePlay); + + menuButtons.setAlignment(Pos.CENTER); + menuWidgets.setAlignment(Pos.CENTER); + + mainPane.setTop(menuWidgets); + mainPane.setCenter(menuButtons); + + Multimedia.playBackgroundMusic("menu.mp3", true); + } + + /** + * Initialise the menu + */ + @Override + public void initialise() { + + } + + /** + * Handle when the Start Game button is pressed + * + * @param event event + */ + private void startGame(MouseEvent event) { + Multimedia.stopSound(); + gameWindow.startChallenge(); + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/GamePane.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/GamePane.java index ef42b4fc9d0516367dc4fe707ecd092059bcff01..f92ca992d621a69c560dcbcf392b7e722b67fa55 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/GamePane.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/GamePane.java @@ -9,86 +9,88 @@ import org.apache.logging.log4j.Logger; /** * The Game Pane is a special pane which will scale anything inside it to the screen and maintain the aspect ratio. - * + * <p> * Drawing will be scaled appropriately. - * + * <p> * This takes the worry about the layout out and will allow the game to scale to any resolution easily. - * + * <p> * It uses the width and height given which should match the main window size. This will be the base drawing resolution, * but will be scaled up or down as the window is resized. - * + * <p> * You should not need to modify this class */ public class GamePane extends StackPane { - private static final Logger logger = LogManager.getLogger(GamePane.class); - - private final int width; - private final int height; - private double scalar = 1; - private final boolean autoScale = true; - - /** - * Create a new scalable GamePane with the given drawing width and height. - * @param width width - * @param height height - */ - public GamePane(int width, int height) { - super(); - this.width = width; - this.height = height; - - getStyleClass().add("gamepane"); - setAlignment(Pos.TOP_LEFT); + private static final Logger logger = LogManager.getLogger(GamePane.class); + + private final int width; + private final int height; + private double scalar = 1; + private final boolean autoScale = true; + + /** + * Create a new scalable GamePane with the given drawing width and height. + * + * @param width width + * @param height height + */ + public GamePane(int width, int height) { + super(); + this.width = width; + this.height = height; + + getStyleClass().add("gamepane"); + setAlignment(Pos.TOP_LEFT); + } + + /** + * Update the scalar being used by this draw pane + * + * @param scalar scalar + */ + protected void setScalar(double scalar) { + this.scalar = scalar; + } + + /** + * Use a Graphics Transformation to scale everything inside this pane. Padding is added to the edges to maintain + * the correct aspect ratio and keep the display centred. + */ + @Override + public void layoutChildren() { + super.layoutChildren(); + + if (!autoScale) { + return; } - /** - * Update the scalar being used by this draw pane - * @param scalar scalar - */ - protected void setScalar(double scalar) { - this.scalar = scalar; - } + //Work out the scale factor height and width + var scaleFactorHeight = getHeight() / height; + var scaleFactorWidth = getWidth() / width; - /** - * Use a Graphics Transformation to scale everything inside this pane. Padding is added to the edges to maintain - * the correct aspect ratio and keep the display centred. - */ - @Override - public void layoutChildren() { - super.layoutChildren(); - - if(!autoScale) { - return; - } - - //Work out the scale factor height and width - var scaleFactorHeight = getHeight() / height; - var scaleFactorWidth = getWidth() / width; - - //Work out whether to scale by width or height - if (scaleFactorHeight > scaleFactorWidth) { - setScalar(scaleFactorWidth); - } else { - setScalar(scaleFactorHeight); - } - - //Set up the scale - Scale scale = new Scale(scalar,scalar); - - //Get the parent width and height - var parentWidth = getWidth(); - var parentHeight = getHeight(); - - //Get the padding needed on the top and left - var paddingLeft = (parentWidth - (width * scalar)) / 2.0; - var paddingTop = (parentHeight - (height * scalar)) / 2.0; - - //Perform the transformation - Translate translate = new Translate(paddingLeft, paddingTop); - scale.setPivotX(0); - scale.setPivotY(0); - getTransforms().setAll(translate, scale); + //Work out whether to scale by width or height + if (scaleFactorHeight > scaleFactorWidth) { + setScalar(scaleFactorWidth); + } else { + setScalar(scaleFactorHeight); } + //Set up the scale + Scale scale = new Scale(scalar, scalar); + + //Get the parent width and height + var parentWidth = getWidth(); + var parentHeight = getHeight(); + + //Get the padding needed on the top and left + var paddingLeft = (parentWidth - (width * scalar)) / 2.0; + var paddingTop = (parentHeight - (height * scalar)) / 2.0; + + //Perform the transformation + Translate translate = new Translate(paddingLeft, paddingTop); + scale.setPivotX(0); + scale.setPivotY(0); + getTransforms().setAll(translate, scale); + } + } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/GameWindow.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/GameWindow.java index 772a24425e57f13fd5a8d9fe0379afc75cf7cd35..924668bd356c18b348307e97aed1692ae2da3668 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/GameWindow.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/ui/GameWindow.java @@ -15,149 +15,157 @@ import uk.ac.soton.comp1206.scene.*; /** * The GameWindow is the single window for the game where everything takes place. To move between screens in the game, * we simply change the scene. - * + * <p> * The GameWindow has methods to launch each of the different parts of the game by switching scenes. You can add more * methods here to add more screens to the game. */ public class GameWindow { - private static final Logger logger = LogManager.getLogger(GameWindow.class); - - private final int width; - private final int height; - - private final Stage stage; - - private BaseScene currentScene; - private Scene scene; - - final Communicator communicator; - - /** - * Create a new GameWindow attached to the given stage with the specified width and height - * @param stage stage - * @param width width - * @param height height - */ - public GameWindow(Stage stage, int width, int height) { - this.width = width; - this.height = height; - - this.stage = stage; - - //Setup window - setupStage(); - - //Setup resources - setupResources(); - - //Setup default scene - setupDefaultScene(); - - //Setup communicator - communicator = new Communicator("ws://ofb-labs.soton.ac.uk:9700"); - - //Go to menu - startMenu(); - } - - /** - * Setup the font and any other resources we need - */ - private void setupResources() { - logger.info("Loading resources"); - - //We need to load fonts here due to the Font loader bug with spaces in URLs in the CSS files - Font.loadFont(getClass().getResourceAsStream("/style/Orbitron-Regular.ttf"),32); - Font.loadFont(getClass().getResourceAsStream("/style/Orbitron-Bold.ttf"),32); - Font.loadFont(getClass().getResourceAsStream("/style/Orbitron-ExtraBold.ttf"),32); - } - - /** - * Display the main menu - */ - public void startMenu() { - loadScene(new MenuScene(this)); - } - - /** - * Display the single player challenge - */ - public void startChallenge() { loadScene(new ChallengeScene(this)); } - - /** - * Setup the default settings for the stage itself (the window), such as the title and minimum width and height. - */ - public void setupStage() { - stage.setTitle("TetrECS"); - stage.setMinWidth(width); - stage.setMinHeight(height + 20); - stage.setOnCloseRequest(ev -> App.getInstance().shutdown()); - } - - /** - * Load a given scene which extends BaseScene and switch over. - * @param newScene new scene to load - */ - public void loadScene(BaseScene newScene) { - //Cleanup remains of the previous scene - cleanup(); - - //Create the new scene and set it up - newScene.build(); - currentScene = newScene; - scene = newScene.setScene(); - stage.setScene(scene); - - //Initialise the scene when ready - Platform.runLater(() -> currentScene.initialise()); - } - - /** - * Setup the default scene (an empty black scene) when no scene is loaded - */ - public void setupDefaultScene() { - this.scene = new Scene(new Pane(),width,height, Color.BLACK); - stage.setScene(this.scene); - } - - /** - * When switching scenes, perform any cleanup needed, such as removing previous listeners - */ - public void cleanup() { - logger.info("Clearing up previous scene"); - communicator.clearListeners(); - } - - /** - * Get the current scene being displayed - * @return scene - */ - public Scene getScene() { - return scene; - } - - /** - * Get the width of the Game Window - * @return width - */ - public int getWidth() { - return this.width; - } - - /** - * Get the height of the Game Window - * @return height - */ - public int getHeight() { - return this.height; - } - - /** - * Get the communicator - * @return communicator - */ - public Communicator getCommunicator() { - return communicator; - } + private static final Logger logger = LogManager.getLogger(GameWindow.class); + + private final int width; + private final int height; + + private final Stage stage; + + private BaseScene currentScene; + private Scene scene; + + final Communicator communicator; + + /** + * Create a new GameWindow attached to the given stage with the specified width and height + * + * @param stage stage + * @param width width + * @param height height + */ + public GameWindow(Stage stage, int width, int height) { + this.width = width; + this.height = height; + + this.stage = stage; + + //Setup window + setupStage(); + + //Setup resources + setupResources(); + + //Setup default scene + setupDefaultScene(); + + //Setup communicator + communicator = new Communicator("ws://ofb-labs.soton.ac.uk:9700"); + + //Go to menu + startMenu(); + } + + /** + * Setup the font and any other resources we need + */ + private void setupResources() { + logger.info("Loading resources"); + + //We need to load fonts here due to the Font loader bug with spaces in URLs in the CSS files + Font.loadFont(getClass().getResourceAsStream("/style/Orbitron-Regular.ttf"), 32); + Font.loadFont(getClass().getResourceAsStream("/style/Orbitron-Bold.ttf"), 32); + Font.loadFont(getClass().getResourceAsStream("/style/Orbitron-ExtraBold.ttf"), 32); + } + + /** + * Display the main menu + */ + public void startMenu() { + loadScene(new MenuScene(this)); + } + + /** + * Display the single player challenge + */ + public void startChallenge() { + loadScene(new ChallengeScene(this)); + } + + /** + * Setup the default settings for the stage itself (the window), such as the title and minimum width and height. + */ + public void setupStage() { + stage.setTitle("TetrECS"); + stage.setMinWidth(width); + stage.setMinHeight(height + 20); + stage.setOnCloseRequest(ev -> App.getInstance().shutdown()); + } + + /** + * Load a given scene which extends BaseScene and switch over. + * + * @param newScene new scene to load + */ + public void loadScene(BaseScene newScene) { + //Cleanup remains of the previous scene + cleanup(); + + //Create the new scene and set it up + newScene.build(); + currentScene = newScene; + scene = newScene.setScene(); + stage.setScene(scene); + + //Initialise the scene when ready + Platform.runLater(() -> currentScene.initialise()); + } + + /** + * Setup the default scene (an empty black scene) when no scene is loaded + */ + public void setupDefaultScene() { + this.scene = new Scene(new Pane(), width, height, Color.BLACK); + stage.setScene(this.scene); + } + + /** + * When switching scenes, perform any cleanup needed, such as removing previous listeners + */ + public void cleanup() { + logger.info("Clearing up previous scene"); + communicator.clearListeners(); + } + + /** + * Get the current scene being displayed + * + * @return scene + */ + public Scene getScene() { + return scene; + } + + /** + * Get the width of the Game Window + * + * @return width + */ + public int getWidth() { + return this.width; + } + + /** + * Get the height of the Game Window + * + * @return height + */ + public int getHeight() { + return this.height; + } + + /** + * Get the communicator + * + * @return communicator + */ + public Communicator getCommunicator() { + return communicator; + } } diff --git a/tetrecs/src/main/java/uk/ac/soton/comp1206/utility/Multimedia.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/utility/Multimedia.java index ad81aba6f1d8c98ab51cf316d00e62ce29282d0c..a524f1dad28045dc40bbd10fdc2a392e18337895 100644 --- a/tetrecs/src/main/java/uk/ac/soton/comp1206/utility/Multimedia.java +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/utility/Multimedia.java @@ -15,7 +15,7 @@ public class Multimedia { public static void playBackgroundMusic(String music, boolean toLoop) { String toPlay = Multimedia.class.getResource("/music/" + music).toExternalForm(); - try{ + try { Media play = new Media(toPlay); backgroundPlayer = new MediaPlayer(play); backgroundPlayer.setVolume(0.3); @@ -33,7 +33,7 @@ public class Multimedia { public static void playSound(String sound) { String toPlay = Multimedia.class.getResource("/sounds/" + sound).toExternalForm(); - try{ + try { Media play = new Media(toPlay); mediaPlayer = new MediaPlayer(play); mediaPlayer.setVolume(0.65);