From f169c531984e0014a00b54dac7b90bc24619c673 Mon Sep 17 00:00:00 2001 From: ayazb7 <60544937+ayazb7@users.noreply.github.com> Date: Sun, 3 Apr 2022 00:35:08 +0100 Subject: [PATCH] Adding UI and audio Changes --- .../java/uk/ac/soton/comp1206/game/Game.java | 71 ++++++++++++++---- .../java/uk/ac/soton/comp1206/game/Grid.java | 7 ++ .../soton/comp1206/scene/ChallengeScene.java | 16 ++-- .../uk/ac/soton/comp1206/scene/MenuScene.java | 15 +++- .../ac/soton/comp1206/utility/Multimedia.java | 55 ++++++++++++++ .../uk/ac/soton/comp1206/game/Game.class | Bin 5129 -> 6340 bytes .../soton/comp1206/scene/ChallengeScene.class | Bin 3734 -> 6373 bytes .../ac/soton/comp1206/scene/MenuScene.class | Bin 3681 -> 4282 bytes 8 files changed, 144 insertions(+), 20 deletions(-) create mode 100644 tetrecs/src/main/java/uk/ac/soton/comp1206/utility/Multimedia.java 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 62c8b79..d1dd5e0 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 e876bee..fc583da 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 3e3951f..8279850 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 79c3ae1..7d65d35 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 0000000..7019bc0 --- /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 GIT binary patch literal 6340 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 literal 5129 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 HBL+zT)Zxy4 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 GIT binary patch delta 3430 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 U866oI7`PZ18J!qi7~L2o0r4+&SO5S3 delta 828 zcmaEAI8B!8)W2Q(7#J9A8MbZYn#sx~#K6c<$iq;?P(0a_tAwqThoOw2eDYx~U#?1! zXcZ%auEyjGe5#Y}xj7kYCVO&Ab8s=FFj#Uh)K6CAl@)2^VQ6B|U}Rt|E=epZVP|Mz zWKfydC_TBFmy3s?jiH^Lp@WB^lc8(#MBZ%1$xr#+COZf?@-ximVpzbikey)>4}&tp z;>i;P4l6J$Wn|!TD$UGE$;?YvVB}|GSkA?;f?*{)!zvzz)eLJk7Ynj5%2)BTGOXuf z;9#g^WZ?14%S$bC&PgmTPAz6<*u==7I+;;OeDXdaekO)3lg|qo%Q7)YF>o{RFfcH% zFeEZ0F)%Q&F)%W)g30d5>cR?c3_T1C415gC3=9mC46F=N4Ezkz4805t3}OsS3=9kc z41Em!3?LxDpv$1gz{tSJFo8jXfsvt`fq_w%ft`Vcfq`M;<X+)r^}1TS7z!8|wlS1! zWME)m0-J2bz{kMApu`};pu!-*pvGXxpuu3tpvmCMpv4f#pv@4=pu>>OpvO?mpwCdp zV92nL!H8iQgDJxX1~afLv>@g~U17;k!7!0w5(6VcF@qh$WQHjWObiPd1Q@0=Ok-fK zXJBF|VyJ>Rjlq$D3G4w*tt|}k+S?c^5N_fEOV~1SFxY|ZfcTUXY6k-YC&P4x8DO8P z!+gr%#lXtI$iToLv5A3QsCp*@KNEx2ZibXd4vy^%wObkDH!?7Q>_-Hq3j-H}JA*ib z2iOW8h-Ro2j0`j32D>mYf#rli2G>Ch-og;SjiCYIU`X`%GjK5kFbFaPBAF-zHIaj1 z7DEg)Ru~k)1~M>k3N`OwXx+@f4l;=m937z8XJ8OyU}l&Nj-ojXa~T*Igcz6@<}olb hEMZv2z|63gVI9L-h7Al13|tJ13>z6XGi+s$1OTOlitqpc 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 GIT binary patch delta 1500 zcmaDTvrCcd)W2Q(7#J9A8J=(CYGh%Qnw-ckVi%N}o|&J=#SqJ2$L0{p00tmlG7m!v zgEJ!oZ*gi#Kv8O%M`~tzMhPcF8bdleLk15+CPNk@gAB+Bk$|Gi{G!Z~N=61YN1t%V z$Y4eWxycFaqLMHPYc7TyhFo@rJRXL8h5|+g36M5552ySJMh1@J)Dn;MqWp431``dR zti-a!v<m&=<kY-WeZTyaRBMny!f=B$!?+lt7(&<?iYIrnNC%fPGO&lFmK3=<2XiqL zF_iN#uri2%SRNb<Rg4TANtx*-nI$=?91Jy#47|aadFeT+3IREZm8nG>40VhQ9J#4^ zrJg0Jxk3z#3=KRCjSNkb|F8sd6fv~$FtjqXO%7!>=k8$WWM}B&Vd!S)nLM4<nyrtA zp`T&G<QuG7TwDxc43l^mCNoT#tjwk+F^z{|I>Qu32F~Kt66e&slGGx0hM9~E>JuA9 zjY>;0b23XR^?gfoN-}d(Q!*2|7-lfoaWZf)%;8~}%P^0Tfh!j-$H<`RGqF+B1yh$b z2g3rW!}W3tj6sGh;$c|Ku!NC8xF9F7(kU@HJH05sG%v-sv^X=FkwI+oLq=hjC{W1F zU|7b(u$;jj<ie8tf?$v;E(RTjl{^fqK%#ubC5c5P&KZe0IjMQ+say<e7}l~gtm9!= z&#-}!L3#2SHkr+f*en@2iVG5xQ$f+6z%I%LNkNmZvp?fI%f)bx;XFIT1s(=vhKrL= za~zSs%*epyRGOKSl9`vTz{t<WaFvVU8pCyVh8sK#HyLhiUdPG8Xm^K^K^z|Wsb#5o zCHk%)(poc&pOxVr7Xt^weIAA*3`YeRjxsXvc;@A$7CGl678j=$vok!N{DDi0<tZr9 z8E}eEF5qIDY|Sk!%fukXz|FwJz`(!+3SI^V237_}237_(21bUBlasj>T{kf>Fz_)j zGcYj7GO#kpG4M0UGi+vHU=U+qVqjnpVA#U26`UOe7&IBQ7#JBC8MZOlgLE@6Fo`g* zGH@_3Fq%w0$=z1Jogv<eMUq8?Az>Rsk|fI}hSVJl*}B^p3ME-~GWaqvgzsi3iWDl@ z&QNB>D#^Nyp+cw<A`Vu=3SsYNh>G0K5M#v#R$L8I%r40eQd|pBAjz(^i=m!@VH-oU zBpb+ZcBptg+a`wgZ4AA-5K2dP8^c5$kdmodyBTIgZfBUam0`Bl7KYhE^I5hrEZhhV z6OixA7-Sh37}OX<7&I7k8MGKo8MGN38FUzY8FU#U8T1&^84MWm84MY!7>pU37)%+u z8O#_aGng~XX0Tvb&S1^3iNS_pKZ9*O!)XS4hARw?4EGtF7~U{AGkj-oVPs)&W8`6Q zXB1}eWRzg=Vw7X>Vbo;sWi)2+2M2QyBmkkoY|8MTVLQVP21bT_hNBES8Fn!+F*Gr3 zV%W{Fhk==)n_(rxUWR=PEDW0%ni%#o9AIE&xWbUYaFAgS0~<sAeTGnmLktHP*cliZ z4#VPzL7Rbrff0le9tK4|14B62ejbP<)P5#V@`6MzgEs>sI0^8B!fYGEQmriv>f0Dr zAdG>enm7h_hIj@(hJ;$Md5~no4>ga0fuG?R!*K>i1`dW3a3?8(?POr!6yn&yuzE8C zJIG8%22fl;oF>A+%y1GMKc^T@GcYg+F)%TlVPIsq#Bhaync+6WU4{n?4;dI3xEL52 M9x*&&c*Y<J0ELrbc>n+a delta 1025 zcmdm`_)v!H)W2Q(7#J9A8IEk^YGh#)n|zK_EQ*66fsuhdB(<c-)j61pA(kPDhk=zr z1jO>-U`S<T;7H0$FUc&)N#$aQVhG`2$Y5mP4bIF<&q-AX$VseBE#hFvVr1aRP0cIy zEJ@83Vqj#*;bF*S$eYZ<7RV9HP{6}b$WSynmd%{IgrSt3p^S&2oS|a!d^T&gDjtSv zhMLI_*t8Tm8A=%Hco^y#Di|5KLi_{bon8GxT!Xk6!WbHP7@8QGCyTJF*|zd9v@tX@ zGH@2BmN=*8m82GNG3YRK@Gx{T*fTQl6_+Fyl{jZ4=H#U2rKfT+bTjm@GxYK>^fB}^ zGAK{(=aAW)%3;Yk`6%ZjzExZds~Og?GpyxdP-a*+c`Mfu`3;N=Tu!B#IVqWW=?aYe zYz&*Y7&bF(VQ1LN!?2BE`{o(kER2jhC(q@PRo>0Tz`?MGhhZVZA_0a)j0`-Ud3mWt z&N+$2#i_;Y3<nq)R3|^=Qe|UjIK;>xH~Ar#++;OgAyGyKDF$u^9tH*mRt81}Rt7c( zMurKKLwOZlCo(WF@G&qmFfd3murf$7@H0p=Ok!YQ5My9sU|<knn9MMR0R#jXG#RuQ z7#SEDrZU)rbTcq8?qFbLU}s=p_%(SqZ(F@k{C0*!D;7zXZ4AjmDLWZ_nHa)#w=twi zvOw6o8KNS$GsIZ2?q-OM6iNpvW|L$CDb9o_kYv-^#gNUwu#F*Kk`<(p4JyvMiJ^EK zL#6H}hT3fml{&iH7#egyDq1!&FfcGNfV>dLP%qBFz@Wq+!l1&S%b><!%An5R$e_XC z%b>{+$)LrM&Y;7P&!Edt#h}m7#9+kG%V5kfi@}6p8G{+adIk%IT@02C#~G{`E-_d$ z+-I<5c+OzQ@Q%TO;WL9H!%qfhaF}>Nd<zW|Q--4q(-@{RFf!ybbTiDTXPC*r#L&c0 z!7z(qHUl$5FGDWF9EQ0JEDY-zycy;(%w}L^*u~($FrQ&AIQSR9f{{U+fq{V$gc05W z#Sa66H`rDlh$PfjCQ#Hv!k@u`fe{=_99ml#)a$n~v?C1Q0!sujurmaM4S_@_2h<P- z1`dYB3`-ao88{f0!rh?=wupg&Q;1^+L)T^oc93z5;NXS0M~H!$VHr5cmouzjU|<kp mU}9Lwz{s$kVIu>x7{d;RT?~5}KslX@fstW9!$F3_43Yq0H_xH~ -- GitLab