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 62c8b794106a9c0031bd45667889002c45ee7ba4..d1dd5e048ac7dc70badbaf2d4357c10c291a246c 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 @@ -1,9 +1,11 @@ package uk.ac.soton.comp1206.game; +import javafx.beans.property.IntegerProperty; import javafx.beans.property.SimpleIntegerProperty; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import uk.ac.soton.comp1206.component.GameBlock; +import uk.ac.soton.comp1206.utility.Multimedia; import java.util.ArrayList; import java.util.Random; @@ -35,11 +37,15 @@ public class Game { private SimpleIntegerProperty score; - private SimpleIntegerProperty level; + private IntegerProperty level; - private SimpleIntegerProperty lives; + private IntegerProperty lives; - private SimpleIntegerProperty multiplier; + private IntegerProperty multiplier; + + private final Multimedia multimedia; + + private int remainder = 0; /** * Create a new game with the specified rows and columns. Creates a corresponding grid model. @@ -55,6 +61,7 @@ public class Game { this.lives = new SimpleIntegerProperty(3); this.multiplier = new SimpleIntegerProperty(1); + this.multimedia = new Multimedia(); //Create a new grid model to represent the game state this.grid = new Grid(cols,rows); @@ -98,7 +105,7 @@ public class Game { Random rand = new Random(); int value = rand.nextInt(15); logger.info("Spawning piece of value " + (value + 1)); - return GamePiece.createPiece(14); + return GamePiece.createPiece(value); } public void nextPiece() { @@ -139,9 +146,6 @@ public class Game { } } - if (fullCols.size() != 0 || fullRows.size() != 0) { - logger.info("Removing rows/columns"); - } int numGridBlocks = 0; @@ -169,8 +173,25 @@ public class Game { } } - score = new SimpleIntegerProperty(score.get() + (fullCols.size() + fullRows.size()) * numGridBlocks * 10 * multiplier.get()); - System.out.println(score.get()); + + int newScore = score.get() + (fullCols.size() + fullRows.size()) * numGridBlocks * 10 * multiplier.get(); + this.setScore(newScore); + int newRemainder = score.get() % 1000; + System.out.println("newRemainder = " + newRemainder + " remainder = " + remainder); + 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); + } } /** @@ -197,19 +218,43 @@ public class Game { return rows; } - public SimpleIntegerProperty getLevel() { + public IntegerProperty getLevel() { return level; } - public SimpleIntegerProperty getLives() { + public IntegerProperty getLives() { return lives; } - public SimpleIntegerProperty getScore() { + public IntegerProperty getScore() { return score; } - public SimpleIntegerProperty getMultiplier() { + 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/Grid.java b/tetrecs/src/main/java/uk/ac/soton/comp1206/game/Grid.java index e876bee020bb5ab0ea1da0be3f759e7f023d390b..fc583daf8327a40983f1a56017a2819af0c20c14 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 @@ -5,6 +5,7 @@ import javafx.beans.property.SimpleIntegerProperty; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import uk.ac.soton.comp1206.App; +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 @@ -34,6 +35,8 @@ public class Grid { */ private final SimpleIntegerProperty[][] grid; + private final Multimedia multimedia; + /** * Create a new Grid with the specified number of columns and rows and initialise them * @param cols number of columns @@ -46,6 +49,8 @@ public class Grid { //Create the grid itself grid = new SimpleIntegerProperty[cols][rows]; + this.multimedia = new Multimedia(); + //Add a SimpleIntegerProperty to every block in the grid for(var y = 0; y < rows; y++) { for(var x = 0; x < cols; x++) { @@ -101,6 +106,7 @@ public class Grid { if (value == 0) continue; if (get(x + placeX, y + placeY) != 0) { logger.info("Cannot place piece here"); + multimedia.playSound("fail.wav"); return false; } } @@ -112,6 +118,7 @@ public class Grid { if (!this.canPlayPiece(gamePiece, placeX, placeY)) return false; logger.info("Placing block at x:{} y:{}",placeX,placeY); + multimedia.playSound("place.wav"); int[][] blocks = gamePiece.getBlocks(); placeX = placeX - 1; placeY = placeY - 1; 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 3e3951f4ef7d584c344f24ecdc3d12138630241c..82798501e82fd54e0454e1f373e83f2e5c444d11 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 @@ -4,6 +4,7 @@ import javafx.beans.property.Property; import javafx.geometry.Pos; import javafx.scene.layout.*; import javafx.scene.text.Text; +import javafx.util.converter.NumberStringConverter; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import uk.ac.soton.comp1206.component.GameBlock; @@ -11,6 +12,7 @@ import uk.ac.soton.comp1206.component.GameBoard; import uk.ac.soton.comp1206.game.Game; import uk.ac.soton.comp1206.ui.GamePane; import uk.ac.soton.comp1206.ui.GameWindow; +import uk.ac.soton.comp1206.utility.Multimedia; /** * The Single Player challenge scene. Holds the UI for the single player challenge mode in the game. @@ -20,6 +22,8 @@ public class ChallengeScene extends BaseScene { private static final Logger logger = LogManager.getLogger(MenuScene.class); protected Game game; + private Multimedia multimedia; + /** * Create a new Single Player challenge scene * @param gameWindow the Game Window @@ -58,7 +62,7 @@ public class ChallengeScene extends BaseScene { var scoreTitle = new Text("Score"); scoreTitle.getStyleClass().add("heading"); var scoreValue = new Text(); - scoreValue.textProperty().bind(game.getScore().asString()); + scoreValue.textProperty().bindBidirectional(game.getScore(), new NumberStringConverter()); scoreValue.getStyleClass().add("score"); scoreBox.getChildren().addAll(scoreTitle,scoreValue); scoreBox.setAlignment(Pos.BASELINE_CENTER); @@ -66,8 +70,7 @@ public class ChallengeScene extends BaseScene { header.getChildren().add(scoreBox); Region space = new Region(); - space.setPrefHeight(100); - space.setPrefWidth(100); + space.setMaxWidth(140); HBox.setHgrow(space,Priority.ALWAYS); header.getChildren().add(space); @@ -76,8 +79,7 @@ public class ChallengeScene extends BaseScene { header.getChildren().add(challengeTitle); Region space2 = new Region(); - space2.setPrefHeight(100); - space2.setPrefWidth(100); + space2.setMaxWidth(140); HBox.setHgrow(space2,Priority.ALWAYS); header.getChildren().add(space2); @@ -112,7 +114,9 @@ public class ChallengeScene extends BaseScene { */ public void setupGame() { logger.info("Starting a new challenge"); - + multimedia = new Multimedia(); + multimedia.playBackgroundMusic("game_start.wav", false); + Multimedia.getBackgroundPlayer().setOnEndOfMedia(() -> multimedia.playBackgroundMusic("game.wav", true)); //Start new game game = new Game(5, 5); } 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 79c3ae119fc966d27272e18d386deead328abea2..7d65d35660b97149582942ac42abe18123a21f36 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 @@ -4,11 +4,13 @@ import javafx.geometry.Pos; import javafx.scene.control.Button; import javafx.scene.input.MouseEvent; import javafx.scene.layout.*; +import javafx.scene.media.MediaPlayer; import javafx.scene.text.Text; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import uk.ac.soton.comp1206.ui.GamePane; import uk.ac.soton.comp1206.ui.GameWindow; +import uk.ac.soton.comp1206.utility.Multimedia; /** * The main menu of the game. Provides a gateway to the rest of the game. @@ -17,6 +19,8 @@ public class MenuScene extends BaseScene { private static final Logger logger = LogManager.getLogger(MenuScene.class); + private Multimedia multimedia; + /** * Create a new menu scene * @param gameWindow the Game Window this will be displayed in @@ -46,6 +50,11 @@ public class MenuScene extends BaseScene { 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"); @@ -59,11 +68,14 @@ public class MenuScene extends BaseScene { menuButtons.getChildren().add(singlePlay); menuButtons.setAlignment(Pos.CENTER); - menuWidgets.setAlignment(Pos.TOP_CENTER); + menuWidgets.setAlignment(Pos.CENTER); mainPane.setTop(menuWidgets); mainPane.setCenter(menuButtons); + multimedia = new Multimedia(); + multimedia.playBackgroundMusic("menu.mp3", true); + } /** @@ -79,6 +91,7 @@ public class MenuScene extends BaseScene { * @param event event */ private void startGame(MouseEvent event) { + multimedia.stopSound(); gameWindow.startChallenge(); } 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 new file mode 100644 index 0000000000000000000000000000000000000000..7019bc04ec58700f3faee201ebe80de62be3b62d --- /dev/null +++ b/tetrecs/src/main/java/uk/ac/soton/comp1206/utility/Multimedia.java @@ -0,0 +1,55 @@ +package uk.ac.soton.comp1206.utility; + +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; +import javafx.util.Duration; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +public class Multimedia { + + private static final Logger logger = LogManager.getLogger(Multimedia.class); + + private static MediaPlayer mediaPlayer; + private static MediaPlayer backgroundPlayer; + + public void playBackgroundMusic(String music, boolean toLoop) { + String toPlay = Multimedia.class.getResource("/music/" + music).toExternalForm(); + try{ + Media play = new Media(toPlay); + backgroundPlayer = new MediaPlayer(play); + backgroundPlayer.setVolume(0.3); + if (toLoop) { + backgroundPlayer.setOnEndOfMedia(() -> backgroundPlayer.seek(Duration.ZERO)); + } + backgroundPlayer.play(); + logger.info("Playing background music: " + music + " loop = " + toLoop); + } catch (Exception e) { + e.printStackTrace(); + logger.error(e.toString()); + } + } + + public void playSound(String sound) { + String toPlay = Multimedia.class.getResource("/sounds/" + sound).toExternalForm(); + + try{ + Media play = new Media(toPlay); + mediaPlayer = new MediaPlayer(play); + mediaPlayer.setVolume(0.65); + mediaPlayer.play(); + logger.info("Playing sound clip " + sound); + } catch (Exception e) { + e.printStackTrace(); + logger.error(e.toString()); + } + } + + public void stopSound() { + backgroundPlayer.stop(); + } + + public static MediaPlayer getBackgroundPlayer() { + return backgroundPlayer; + } +} diff --git a/tetrecs/target/classes/uk/ac/soton/comp1206/game/Game.class b/tetrecs/target/classes/uk/ac/soton/comp1206/game/Game.class index cecf78d96f50f7fea2ff6433c5031c891306b191..7e03052f6beac83c683a6cc7985ca105d8c325b4 100644 Binary files a/tetrecs/target/classes/uk/ac/soton/comp1206/game/Game.class and b/tetrecs/target/classes/uk/ac/soton/comp1206/game/Game.class differ diff --git a/tetrecs/target/classes/uk/ac/soton/comp1206/scene/ChallengeScene.class b/tetrecs/target/classes/uk/ac/soton/comp1206/scene/ChallengeScene.class index 7f9919323bc72f5e710ffcb3680d621e109f49b4..d3b846bf114e63d4cac1d643ca442a651e0a42dc 100644 Binary files a/tetrecs/target/classes/uk/ac/soton/comp1206/scene/ChallengeScene.class and b/tetrecs/target/classes/uk/ac/soton/comp1206/scene/ChallengeScene.class differ diff --git a/tetrecs/target/classes/uk/ac/soton/comp1206/scene/MenuScene.class b/tetrecs/target/classes/uk/ac/soton/comp1206/scene/MenuScene.class index afc0c298de62f7b0ad2e34a37ff7f6c67d34139b..71d171fc0b09428b00659938d81a5d448b8b49c5 100644 Binary files a/tetrecs/target/classes/uk/ac/soton/comp1206/scene/MenuScene.class and b/tetrecs/target/classes/uk/ac/soton/comp1206/scene/MenuScene.class differ