From 4befef98f70055cb5f5c0a3242dd8d801d32893b Mon Sep 17 00:00:00 2001 From: userName Date: Tue, 24 Dec 2024 04:41:46 +0800 Subject: [PATCH] Adjust the sound volume while playing --- .idea/misc.xml | 2 +- .../controller/DinosaurController.java | 26 +- .../controller/SoundController.java | 167 ++++++++++++ .../dinosaurexploder/model/GameConstants.java | 32 +-- .../model/GreenDinoComponent.java | 5 +- .../model/PlayerComponent.java | 23 +- .../dinosaurexploder/view/DinosaurMenu.java | 76 +++--- .../dinosaurexploder/view/PauseMenu.java | 240 +++++++++++++++++- src/main/java/module-info.java | 1 + src/main/resources/Styles/styles.css | 2 +- 10 files changed, 472 insertions(+), 102 deletions(-) create mode 100644 src/main/java/com/dinosaur/dinosaurexploder/controller/SoundController.java diff --git a/.idea/misc.xml b/.idea/misc.xml index dc377ec..9dc782b 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -8,5 +8,5 @@ - + \ No newline at end of file diff --git a/src/main/java/com/dinosaur/dinosaurexploder/controller/DinosaurController.java b/src/main/java/com/dinosaur/dinosaurexploder/controller/DinosaurController.java index e9554cf..6667157 100644 --- a/src/main/java/com/dinosaur/dinosaurexploder/controller/DinosaurController.java +++ b/src/main/java/com/dinosaur/dinosaurexploder/controller/DinosaurController.java @@ -5,6 +5,8 @@ import com.dinosaur.dinosaurexploder.model.*; import com.dinosaur.dinosaurexploder.view.DinosaurGUI; import javafx.scene.input.KeyCode; +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import static com.almasb.fxgl.dsl.FXGL.*; @@ -20,7 +22,7 @@ public class DinosaurController { private Entity score; private Entity life; private int lives = 3; - + private MediaPlayer inGameSound; /** * Summary : * Detecting the player damage to decrease the lives and checking if the game is over @@ -66,13 +68,12 @@ public void initInput() { */ public void initGame() { getGameWorld().addEntityFactory(new GameEntityFactory()); - spawn("background", 0, 0); player = spawn("player", getAppCenter().getX() - 45, getAppHeight()-200); - FXGL.play(GameConstants.BACKGROUND_SOUND); + SoundController.getInstance().playInGameSound(GameConstants.BACKGROUND_SOUND, 1.0); /* * At each second that passes, we have 2 out of 3 chances of spawning a green * dinosaur @@ -83,8 +84,8 @@ public void initGame() { spawn("greenDino", random(0, getAppWidth() - 80), -50); }, seconds(0.75)); - score = spawn("Score", getAppCenter().getX() -270, getAppCenter().getY() - 320); - life = spawn("Life", getAppCenter().getX() - 260, getAppCenter().getY() - 250); + score = spawn("Score", getAppCenter().getX() -270, getAppCenter().getY() - 320); + life = spawn("Life", getAppCenter().getX() - 260, getAppCenter().getY() - 250); } /** * Summary : @@ -92,21 +93,24 @@ public void initGame() { */ public void initPhysics() { onCollisionBegin(EntityType.PROJECTILE, EntityType.GREENDINO, (projectile, greendino) -> { - FXGL.play(GameConstants.ENEMY_EXPLODE_SOUND); + SoundController.getInstance().playSoundEffect(GameConstants.ENEMY_EXPLODE_SOUND); + projectile.removeFromWorld(); greendino.removeFromWorld(); score.getComponent(ScoreComponent.class).incrementScore(1); }); - + onCollisionBegin(EntityType.ENEMYPROJECTILE, EntityType.PLAYER, (projectile, player) -> { - FXGL.play(GameConstants.PLAYER_HIT_SOUND); + SoundController.getInstance().playSoundEffect(GameConstants.PLAYER_HIT_SOUND); + projectile.removeFromWorld(); System.out.println("You got hit !\n"); damagePlayer(); }); - + onCollisionBegin(EntityType.PLAYER, EntityType.GREENDINO, (player, greendino) -> { - FXGL.play(GameConstants.PLAYER_HIT_SOUND); + SoundController.getInstance().playSoundEffect(GameConstants.PLAYER_HIT_SOUND); + greendino.removeFromWorld(); System.out.println("You touched a dino !"); damagePlayer(); @@ -122,7 +126,9 @@ public void gameOver(){ getGameController().startNewGame(); } else { getGameController().gotoMainMenu(); + SoundController.getInstance().playInGameSound(GameConstants.MAINMENU_SOUND, 1.0); } }); } } + diff --git a/src/main/java/com/dinosaur/dinosaurexploder/controller/SoundController.java b/src/main/java/com/dinosaur/dinosaurexploder/controller/SoundController.java new file mode 100644 index 0000000..d115b67 --- /dev/null +++ b/src/main/java/com/dinosaur/dinosaurexploder/controller/SoundController.java @@ -0,0 +1,167 @@ +package com.dinosaur.dinosaurexploder.controller; +import javafx.application.Platform; +import javafx.beans.value.ChangeListener; +import javafx.beans.value.ObservableValue; +import javafx.scene.control.Label; +import javafx.scene.control.Slider; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; +import javafx.scene.layout.BorderPane; +import javafx.scene.media.Media; +import javafx.scene.media.MediaPlayer; + +public class SoundController { + private static SoundController instance; + private MediaPlayer inGameSound; + private BorderPane root; + private static double volume = 1.0; + private static double prevVolume = 1.0; + private static double sfxVolume = 1.0; + private static double prevSfxVolume = 1.0; + private static Image viewImage; + private static Image viewSfxImage; + private SoundController() {} + + public static SoundController getInstance() { + if (instance == null) { + instance = new SoundController(); + } + return instance; + } + + public void playInGameSound(String musicResource, double volumeValue) { + if(inGameSound != null) + { + inGameSound.stop(); + } + Media media = new Media(getClass().getResource(musicResource).toExternalForm()); + inGameSound = new MediaPlayer(media); + inGameSound.setCycleCount(MediaPlayer.INDEFINITE); + inGameSound.setVolume(volume); + inGameSound.play(); + } + + public void stopInGameSound() { + if (inGameSound != null) { + inGameSound.stop(); + } + } + + public void muteInGameSound() { + if (inGameSound != null) { + inGameSound.setMute(true); + } + } + + public void unmuteInGameSound() { + if (inGameSound != null) { + inGameSound.setMute(false); + } + } + + public boolean isMuted() { + return inGameSound != null && inGameSound.isMute(); + } + public double getVolume() { + return volume; + } + public double getSfxVolume() { + return sfxVolume; + } + public Image getViewSfxImage() { + return viewSfxImage; + } + public Image getViewImage() { + return viewImage; + } + public void playSoundEffect(String soundResource) { + // Use the controlled volume + Media media = new Media(getClass().getResource(soundResource).toExternalForm()); + MediaPlayer sfxPlayer = new MediaPlayer(media); + sfxPlayer.setVolume(sfxVolume); + sfxPlayer.play(); + } + public double adjustInGameSFX(Slider sfxVolumeSlider, Label sfxVolumeLabel, Image sfxMute, Image sfxAudioOn, ImageView sfxImageViewPlaying) { + sfxVolumeSlider.setValue(sfxVolume); + sfxVolumeSlider.valueProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, Number oldValue, Number newValue) { + Platform.runLater(() -> { + sfxVolume = newValue.doubleValue(); + sfxVolumeLabel.setText(String.format("%.0f%%", sfxVolume * 100)); + System.out.println("VFX Volume label updated to: " + sfxVolumeLabel.getText()); + if(sfxVolume == 0.00) + { + sfxImageViewPlaying.setImage(sfxMute); + viewSfxImage = sfxMute; + } + else + { + sfxImageViewPlaying.setImage(sfxAudioOn); + viewSfxImage = sfxAudioOn; + } + }); + } + + }); + + sfxImageViewPlaying.setOnMouseClicked(mouseEvent -> { + if (sfxVolume == 0.00){ + sfxImageViewPlaying.setImage(sfxAudioOn); + sfxVolume = prevSfxVolume; + sfxVolumeSlider.setValue(sfxVolume); + viewSfxImage = sfxAudioOn; + } else { + sfxImageViewPlaying.setImage(sfxMute); + prevSfxVolume = sfxVolume; + sfxVolume = 0.00; + sfxVolumeSlider.setValue(sfxVolume); + viewSfxImage = sfxMute; + } + }); + return sfxVolume; + } + public double adjustVolume(Slider volumeSlider, Label volumeLabel, Image mute, Image audioOn, ImageView imageViewPlaying) { + volumeSlider.setValue(volume); + volumeSlider.valueProperty().addListener(new ChangeListener() { + @Override + public void changed(ObservableValue observable, Number oldValue, Number newValue) { + Platform.runLater(() -> { + + volume = newValue.doubleValue(); + inGameSound.setVolume(volume); + volumeLabel.setText(String.format("%.0f%%", volume * 100)); + System.out.println("Volume label updated to: " + volumeLabel.getText()); + if(volume == 0.00) + { + imageViewPlaying.setImage(mute); + viewImage = mute; + } + else + { + imageViewPlaying.setImage(audioOn); + viewImage = audioOn; + } + }); + } + }); + + + imageViewPlaying.setOnMouseClicked(mouseEvent -> { + if (volume == 0.00){ + imageViewPlaying.setImage(audioOn); + volume = prevVolume; + volumeSlider.setValue(volume); + viewImage = audioOn; + } else { + imageViewPlaying.setImage(mute); + prevVolume = volume; + volume = 0.00; + volumeSlider.setValue(volume); + viewImage = mute; + } + }); + + return volume; + } +} \ No newline at end of file diff --git a/src/main/java/com/dinosaur/dinosaurexploder/model/GameConstants.java b/src/main/java/com/dinosaur/dinosaurexploder/model/GameConstants.java index dd3ce49..039f9cb 100644 --- a/src/main/java/com/dinosaur/dinosaurexploder/model/GameConstants.java +++ b/src/main/java/com/dinosaur/dinosaurexploder/model/GameConstants.java @@ -9,10 +9,10 @@ * This holds every constant in the the PROJECT */ public class GameConstants { - + /* - * CONSTANTS FOR IMAGES - */ + * CONSTANTS FOR IMAGES + */ public static final String BACKGROUND_IMAGEPATH = "/assets/textures/background.png"; public static final String SPACESHIP_IMAGEPATH = "assets/textures/spaceship.png"; public static final String SPACESHIP_IMAGEFILE = "spaceship.png"; @@ -23,22 +23,22 @@ public class GameConstants { public static final String GREENDINO_IMAGEFILE = "greenDino.png"; public static final String HEART_IMAGEPATH = "assets/textures/life.png"; /* - *CONSTANTS FOR FONTS - */ + *CONSTANTS FOR FONTS + */ public static final String ARCADECLASSIC_FONTNAME = "ArcadeClassic"; /* - * SOUNDS - */ - public static final String ENEMYSHOOT_SOUND = "enemyShoot.wav"; - public static final String SHOOT_SOUND = "shoot.wav"; + * SOUNDS + */ + public static final String ENEMYSHOOT_SOUND = "/assets/sounds/enemyShoot.wav"; + public static final String SHOOT_SOUND = "/assets/sounds/shoot.wav"; public static final String MAINMENU_SOUND = "/assets/sounds/mainMenu.wav"; - public static final String BACKGROUND_SOUND ="gameBackground.wav"; - public static final String ENEMY_EXPLODE_SOUND = "enemyExplode.wav"; - public static final String PLAYER_HIT_SOUND = "playerHit.wav"; - + public static final String BACKGROUND_SOUND ="/assets/sounds/gameBackground.wav"; + public static final String ENEMY_EXPLODE_SOUND = "/assets/sounds/enemyExplode.wav"; + public static final String PLAYER_HIT_SOUND = "/assets/sounds/playerHit.wav"; + public static final String GAME_NAME = "Dinosaur Exploder"; - + public static final List AVAILABLE_LANGUAGES = List.of(Language.ENGLISH, Language.GERMAN ); - -} + +} \ No newline at end of file diff --git a/src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java b/src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java index f644f51..2bfe72a 100644 --- a/src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java +++ b/src/main/java/com/dinosaur/dinosaurexploder/model/GreenDinoComponent.java @@ -5,6 +5,7 @@ import com.almasb.fxgl.entity.SpawnData; import com.almasb.fxgl.entity.component.Component; import com.almasb.fxgl.time.LocalTimer; +import com.dinosaur.dinosaurexploder.controller.SoundController; import javafx.geometry.Point2D; import javafx.util.Duration; @@ -39,7 +40,7 @@ public void onUpdate(double ptf) { */ @Override public void shoot() { - FXGL.play(GameConstants.ENEMYSHOOT_SOUND); + SoundController.getInstance().playSoundEffect(GameConstants.ENEMYSHOOT_SOUND); Point2D center = entity.getCenter(); Vec2 direction = Vec2.fromAngle(entity.getRotation() +90); spawn("basicEnemyProjectile", @@ -47,4 +48,4 @@ public void shoot() { .put("direction", direction.toPoint2D() ) ); } -} +} \ No newline at end of file diff --git a/src/main/java/com/dinosaur/dinosaurexploder/model/PlayerComponent.java b/src/main/java/com/dinosaur/dinosaurexploder/model/PlayerComponent.java index cfe5dc0..a557c8f 100644 --- a/src/main/java/com/dinosaur/dinosaurexploder/model/PlayerComponent.java +++ b/src/main/java/com/dinosaur/dinosaurexploder/model/PlayerComponent.java @@ -8,6 +8,7 @@ import com.almasb.fxgl.entity.SpawnData; import com.almasb.fxgl.entity.component.Component; import com.almasb.fxgl.texture.Texture; +import com.dinosaur.dinosaurexploder.controller.SoundController; import com.dinosaur.dinosaurexploder.view.DinosaurGUI; import javafx.geometry.Point2D; @@ -16,7 +17,7 @@ public class PlayerComponent extends Component implements Player{ private Image spcshpImg = new Image(GameConstants.SPACESHIP_IMAGEPATH); - + int movementSpeed = 8; //entity is not initialized anywhere because it is linked in the factory /** @@ -72,28 +73,28 @@ public void moveLeft(){ * This method is overriding the superclass method to the shooting from the player and spawning of the new bullet */ public void shoot(){ - FXGL.play(GameConstants.SHOOT_SOUND); + SoundController.getInstance().playSoundEffect(GameConstants.SHOOT_SOUND); Point2D center = entity.getCenter(); Vec2 direction = Vec2.fromAngle(entity.getRotation() -90); Image projImg = new Image(GameConstants.BASE_PROJECTILE_IMAGEPATH); - + spawn("basicProjectile", new SpawnData(center.getX() - (projImg.getWidth()/2) +3, center.getY() - spcshpImg.getHeight()/2) .put("direction", direction.toPoint2D() ) ); } - - - + + + private void spawnMovementAnimation() { - + FXGL.entityBuilder() .at(getEntity().getCenter().subtract(spcshpImg.getWidth() / 2, spcshpImg.getHeight() / 2)) .view(new Texture(spcshpImg)) .with(new ExpireCleanComponent(Duration.seconds(0.15)).animateOpacity()) .buildAndAttach(); } - - - -} + + + +} \ No newline at end of file diff --git a/src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java b/src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java index 8075ee3..0c6e176 100644 --- a/src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java +++ b/src/main/java/com/dinosaur/dinosaurexploder/view/DinosaurMenu.java @@ -5,10 +5,13 @@ import com.almasb.fxgl.dsl.FXGL; import com.almasb.fxgl.scene.Scene; import com.almasb.fxgl.ui.FontType; +import com.dinosaur.dinosaurexploder.controller.SoundController; import com.dinosaur.dinosaurexploder.model.GameConstants; +import javafx.application.Platform; import javafx.scene.control.Button; import javafx.scene.image.Image; import javafx.scene.image.ImageView; +import javafx.scene.layout.Border; import javafx.scene.media.Media; import javafx.scene.media.MediaPlayer; import javafx.scene.paint.Color; @@ -26,15 +29,17 @@ import javafx.scene.layout.StackPane; public class DinosaurMenu extends FXGLMenu { - private MediaPlayer mainMenuSound; + private MediaPlayer mainMenuSound; + private Slider volumeSlider; + private Label volumeLabel; + private ImageView imageViewPlaying; + private BorderPane root; + private double volume = 1.0; public DinosaurMenu() { super(MenuType.MAIN_MENU); - Media media = new Media(getClass().getResource(GameConstants.MAINMENU_SOUND).toExternalForm()); - mainMenuSound = new MediaPlayer(media); - mainMenuSound.play(); - mainMenuSound.setCycleCount(MediaPlayer.INDEFINITE); + SoundController.getInstance().playInGameSound(GameConstants.MAINMENU_SOUND, volume); var bg = new Rectangle(getAppWidth(), getAppHeight(), Color.BLACK); @@ -42,21 +47,13 @@ public DinosaurMenu() { var startButton = new Button("Start Game"); var quitButton = new Button("Quit"); - Slider volumeSlider = new Slider(0, 1, 1); + volumeSlider = new Slider(0, 1, volume); volumeSlider.setBlockIncrement(0.01); - volumeSlider.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/styles/styles.css")).toExternalForm()); //Sets the volume label - Label volumeLabel = new Label("100%"); - volumeSlider.valueProperty().addListener(new ChangeListener() { - @Override - public void changed(ObservableValue observable, Number oldValue, Number newValue) { - mainMenuSound.setVolume(newValue.doubleValue()); - volumeLabel.setText(String.format("%.0f%%", newValue.doubleValue() * 100)); - } - }); - + volumeLabel = new Label("100%"); + volumeLabel.setText(String.format("%.0f%%", volume * 100)); try { @@ -83,18 +80,8 @@ public void changed(ObservableValue observable, Number oldValu imageView.setY(190); imageView.setPreserveRatio(true); - //adding image to manually mute music - Image mute = new Image(muteButton); - Image audioOn = new Image(soundButton); - ImageView imageViewPlaying = new ImageView(audioOn); - imageViewPlaying.setFitHeight(50); - imageViewPlaying.setFitWidth(60); - imageViewPlaying.setX(470); - imageViewPlaying.setY(20); - imageViewPlaying.setPreserveRatio(true); - startButton.setMinSize(50, 50); startButton.setPrefSize(140,60); @@ -112,13 +99,24 @@ public void changed(ObservableValue observable, Number oldValu quitButton.setTranslateX(getAppWidth() / 2 - 50); quitButton.setStyle("-fx-font-size:20"); + //adding image to manually mute music + Image mute = new Image(muteButton); + Image audioOn = new Image(soundButton); + imageViewPlaying = new ImageView(audioOn); + imageViewPlaying.setFitHeight(50); + imageViewPlaying.setFitWidth(60); + imageViewPlaying.setX(470); + imageViewPlaying.setY(20); + imageViewPlaying.setPreserveRatio(true); + volume = SoundController.getInstance().adjustVolume(volumeSlider, volumeLabel, mute, audioOn, imageViewPlaying ); + root = new BorderPane(); + BorderPane volumePane = new BorderPane(); + volumePane.setLeft(volumeLabel); + BorderPane root = new BorderPane(); root.setTop(title); BorderPane.setAlignment(title, Pos.CENTER); - - BorderPane volumePane = new BorderPane(); - volumePane.setLeft(volumeLabel); BorderPane.setAlignment(volumeLabel, Pos.CENTER); volumePane.setCenter(volumeSlider); volumeSlider.setStyle("-fx-padding: 10px;"); @@ -129,7 +127,6 @@ public void changed(ObservableValue observable, Number oldValu volumeLabel.setStyle("-fx-text-fill: #61C181;"); - root.setCenter(volumePane); root.setBottom(new BorderPane(startButton, null, quitButton, null, null)); BorderPane.setAlignment(startButton, Pos.CENTER); @@ -138,24 +135,10 @@ public void changed(ObservableValue observable, Number oldValu startButton.setOnAction(event -> { fireNewGame(); - mainMenuSound.stop(); - }); - - imageViewPlaying.setOnMouseClicked(mouseEvent -> { - if (mainMenuSound.isMute()){ - mainMenuSound.setMute(false); //False later - imageViewPlaying.setImage(audioOn); - } else { - mainMenuSound.setMute(true); - imageViewPlaying.setImage(mute); - } }); - quitButton.setOnAction(event -> fireExit()); - - getContentRoot().getChildren().addAll( - bg, title, startButton, quitButton, imageView, imageViewPlaying, volumeLabel, volumeSlider + bg, title, startButton, quitButton, imageView, imageViewPlaying, volumeSlider, volumeLabel ); } catch (FileNotFoundException e){ @@ -166,7 +149,6 @@ public void changed(ObservableValue observable, Number oldValu public void onEnteredFrom(Scene prevState) { super.onEnteredFrom(prevState); FXGL.getAudioPlayer().stopAllSounds(); - mainMenuSound.play(); + SoundController.getInstance().playInGameSound(GameConstants.MAINMENU_SOUND, volume); } - } \ No newline at end of file diff --git a/src/main/java/com/dinosaur/dinosaurexploder/view/PauseMenu.java b/src/main/java/com/dinosaur/dinosaurexploder/view/PauseMenu.java index 2f4a354..62739a3 100644 --- a/src/main/java/com/dinosaur/dinosaurexploder/view/PauseMenu.java +++ b/src/main/java/com/dinosaur/dinosaurexploder/view/PauseMenu.java @@ -2,35 +2,177 @@ import com.almasb.fxgl.app.scene.FXGLMenu; import com.almasb.fxgl.app.scene.MenuType; +import com.almasb.fxgl.audio.Sound; import com.almasb.fxgl.dsl.FXGL; import com.almasb.fxgl.ui.FontType; +import com.dinosaur.dinosaurexploder.controller.SoundController; import javafx.beans.binding.Bindings; import javafx.geometry.Pos; +import javafx.scene.control.Label; +import javafx.scene.control.Slider; +import javafx.scene.image.Image; +import javafx.scene.image.ImageView; import javafx.scene.input.KeyCode; import javafx.scene.layout.StackPane; import javafx.scene.layout.VBox; +import javafx.scene.layout.HBox; import javafx.scene.paint.Color; import javafx.scene.shape.Rectangle; import javafx.scene.text.Text; -import static com.almasb.fxgl.dsl.FXGL.*; import static com.almasb.fxgl.dsl.FXGL.getLocalizationService; import static com.almasb.fxgl.dsl.FXGLForKtKt.getUIFactoryService; import com.dinosaur.dinosaurexploder.DinosaurApp; import com.dinosaur.dinosaurexploder.model.GameConstants; +import org.jetbrains.annotations.NotNull; + +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; public class PauseMenu extends FXGLMenu { + + //These are for tracking how many times the pauseMenu has been opened. Helps in getting the mute/unmute image from SoundController + //For first time, this helps loading the unmuted icon and if count increases more than 1, it changes the icon depending on the controller + //At this point of time, I really don't have other proper method, It works so why not, But if you know any other solution please let me know and contribute + private int count = 0; + private int sfxCount = 0; public PauseMenu() { super(MenuType.GAME_MENU); - DinosaurApp.initLanguages(); - + DinosaurApp.initLanguages(); PauseButton btnBack = new PauseButton(getLocalizationService().getLocalizedString("Pause.1"),() -> fireResume()); - PauseButton btnQuitGame = new PauseButton(getLocalizationService().getLocalizedString("Pause.2"),() -> fireExitToMainMenu()); + SoundButton btnMusic = new SoundButton(getLocalizationService().getLocalizedString("Pause.2")); //need2ComeBack + + PauseButton btnQuitGame = new PauseButton(getLocalizationService().getLocalizedString("Pause.3"),() -> fireExitToMainMenu()); + + ControlButton btnControls = new ControlButton(getLocalizationService().getLocalizedString("Pause.4")); + + btnMusic.setVolume(() -> { + var bg = new Rectangle(getAppWidth(), getAppHeight(), Color.color(0, 0, 0, 0.5)); + count++; + sfxCount++; + var settingsBox = new VBox(15); + ImageView imageViewPlaying; + Slider volumeSlider; + Label volumeLabel; + ImageView sfxImageViewPlaying; + Slider sfxVolumeSlider; + Label sfxVolumeLabel; + InputStream muteButton = null; + InputStream soundButton = null; + InputStream sfxMuteButton = null; + InputStream sfxSoundButton = null; + Image mute = null; + Image audioOn = null; + Image sfxMute = null; + Image sfxAudioOn = null; + double sfxVolume = SoundController.getInstance().getSfxVolume(); + double volume = SoundController.getInstance().getVolume(); + Image sfxImage = null; + Image image = null; + + //for main background + volumeSlider = new Slider(0, 1, volume); + volumeLabel = new Label("100%"); + volumeLabel.setText(String.format("%.0f%%", volume * 100)); + imageViewPlaying = new ImageView(); + + //for sfx + sfxVolumeSlider = new Slider(0, 1, sfxVolume); + sfxVolumeLabel = new Label("100%"); + sfxVolumeLabel.setText(String.format("%.0f%%", sfxVolume * 100)); + sfxImageViewPlaying = new ImageView(); + + PauseButton backButton = new PauseButton(getLocalizationService().getLocalizedString("Pause.5"), () -> { + settingsBox.getChildren().removeAll(settingsBox.getChildren()); + removeChild(bg); + btnBack.enable(); + btnMusic.enable(); + btnQuitGame.enable(); + btnControls.enable(); + }); + + VBox volumeBox = new VBox(1); + volumeBox.getChildren().addAll(volumeLabel, volumeSlider); + + HBox audioBox = new HBox(15); + audioBox.getChildren().addAll(imageViewPlaying, volumeBox); + + VBox sfxVolumeBox = new VBox(1); + sfxVolumeBox.getChildren().addAll(sfxVolumeLabel, sfxVolumeSlider); + HBox sfxAudioBox = new HBox(15); + sfxAudioBox.getChildren().addAll(sfxImageViewPlaying, sfxVolumeBox); + + settingsBox.getChildren().addAll( + backButton, // Back button + new OptionsButton(getLocalizationService().getLocalizedString("Pause.12")), + audioBox, + new OptionsButton(getLocalizationService().getLocalizedString("Pause.13")), + sfxAudioBox + ); + + + settingsBox.setTranslateX(300); + settingsBox.setTranslateY(getAppWidth() / 2); + volumeSlider.setBlockIncrement(0.01); + volumeSlider.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/styles/styles.css")).toExternalForm()); + sfxVolumeSlider.getStylesheets().add(Objects.requireNonNull(getClass().getResource("/styles/styles.css")).toExternalForm()); - ControlButton btnControls = new ControlButton(getLocalizationService().getLocalizedString("Pause.3")); + + + try { + muteButton = getClass().getClassLoader().getResourceAsStream("assets/textures/silent.png"); + soundButton = getClass().getClassLoader().getResourceAsStream("assets/textures/playing.png"); + sfxMuteButton = getClass().getClassLoader().getResourceAsStream("assets/textures/silent.png"); + sfxSoundButton = getClass().getClassLoader().getResourceAsStream("assets/textures/playing.png"); + if (muteButton == null || soundButton == null || sfxMuteButton == null || sfxSoundButton == null) { + throw new FileNotFoundException("Resource not found: mute or play icon"); + } + } catch (FileNotFoundException e) { + System.out.println("File not found: " + e.getMessage()); + } + + // Initialize images for mute and play + mute = new Image(muteButton); + audioOn = new Image(soundButton); + if(count <= 1) + imageViewPlaying.setImage(audioOn); + imageViewPlaying.setFitHeight(35); + imageViewPlaying.setFitWidth(45); + imageViewPlaying.setPreserveRatio(true); + + // Initialize images for mute and play for SFX + sfxMute = new Image(sfxMuteButton); + sfxAudioOn = new Image(sfxSoundButton); + if(sfxCount <= 1) + sfxImageViewPlaying.setImage(sfxAudioOn); + sfxImageViewPlaying.setFitHeight(35); + sfxImageViewPlaying.setFitWidth(45); + sfxImageViewPlaying.setPreserveRatio(true); + + image = SoundController.getInstance().getViewImage(); + if(count > 1) + imageViewPlaying.setImage(image); + volume = SoundController.getInstance().adjustVolume(volumeSlider, volumeLabel, mute, audioOn, imageViewPlaying); + sfxImage = SoundController.getInstance().getViewSfxImage(); + if(sfxCount > 1) + sfxImageViewPlaying.setImage(sfxImage); + sfxVolume = SoundController.getInstance().adjustInGameSFX(sfxVolumeSlider, sfxVolumeLabel, sfxMute, sfxAudioOn, sfxImageViewPlaying); + volumeLabel.setStyle("-fx-text-fill: #61C181;"); + sfxVolumeLabel.setStyle("-fx-text-fill: #61C181;"); + + btnBack.disable(); + btnMusic.disable(); + btnQuitGame.disable(); + btnControls.disable(); + + getContentRoot().getChildren().addAll(bg, settingsBox); + }); btnControls.setControlAction(() -> { @@ -39,10 +181,11 @@ public PauseMenu() { var controlsBox = new VBox(15); controlsBox.getChildren().addAll( - new PauseButton(getLocalizationService().getLocalizedString("Pause.4"), () -> { + new PauseButton(getLocalizationService().getLocalizedString("Pause.5"), () -> { controlsBox.getChildren().removeAll(controlsBox.getChildren()); removeChild(bg); btnBack.enable(); + btnMusic.enable(); btnQuitGame.enable(); btnControls.enable(); }), @@ -52,17 +195,18 @@ public PauseMenu() { new OptionsButton("← / A : Move spaceship left"), new OptionsButton("ESC: Pause the game"), new OptionsButton("SPACE: Shoot")); - new OptionsButton(getLocalizationService().getLocalizedString("Pause.5")); - new OptionsButton(getLocalizationService().getLocalizedString("Pause.6")); - new OptionsButton(getLocalizationService().getLocalizedString("Pause.7")); - new OptionsButton(getLocalizationService().getLocalizedString("Pause.8")); - new OptionsButton(getLocalizationService().getLocalizedString("Pause.9")); - new OptionsButton(getLocalizationService().getLocalizedString("Pause.10")); + new OptionsButton(getLocalizationService().getLocalizedString("Pause.6")); + new OptionsButton(getLocalizationService().getLocalizedString("Pause.7")); + new OptionsButton(getLocalizationService().getLocalizedString("Pause.8")); + new OptionsButton(getLocalizationService().getLocalizedString("Pause.9")); + new OptionsButton(getLocalizationService().getLocalizedString("Pause.10")); + new OptionsButton(getLocalizationService().getLocalizedString("Pause.11")); controlsBox.setTranslateX(300); controlsBox.setTranslateY(getAppWidth() / 2); btnBack.disable(); + btnMusic.disable(); btnQuitGame.disable(); btnControls.disable(); @@ -78,13 +222,14 @@ public PauseMenu() { var title = FXGL.getUIFactoryService().newText(GameConstants.GAME_NAME, Color.WHITE, FontType.MONO, 35); var box = new VBox(15, btnBack, + btnMusic, btnControls, btnQuitGame); var version = FXGL.getUIFactoryService().newText("v1.0-Developer", Color.WHITE, FontType.MONO, 20); title.setTranslateX(getAppWidth() / 2 - 175); title.setTranslateY(150); - + box.setTranslateX(100); box.setTranslateY(getAppWidth() / 2 + 100); @@ -95,10 +240,15 @@ public PauseMenu() { bg,title,version, box); } + @NotNull + private static String getKey() { + return "Pause.1"; + } + private static class OptionsButton extends StackPane { private String description; - private Text text; + private Text text; public OptionsButton(String description) { this.description = description; @@ -110,6 +260,68 @@ public OptionsButton(String description) { } } + private static class VolumeOptions extends StackPane { + + private String description; + private Text text; + + public VolumeOptions(String description) { + this.description = description; + + text = getUIFactoryService().newText(description, Color.WHITE, 14.0); + setAlignment(Pos.CENTER_LEFT); + getChildren().addAll(text); + + } + } + + private static class SoundButton extends StackPane { + + private static final Color SELECTED_COLOR = Color.WHITE; + private static final Color NOT_SELECTED_COLOR = Color.GRAY; + private String name; + private Runnable action; + + private Text text; + private boolean disable = false; + + public void disable(){ + disable = true; + } + + public void enable(){ + disable = false; + } + public SoundButton(String name) { + this.name = name; + } + public void setVolume(Runnable action) + { + this.action = action; + text = getUIFactoryService().newText(name, Color.WHITE, 24.0); + text.strokeProperty().bind( + Bindings.when(focusedProperty()).then(SELECTED_COLOR).otherwise(NOT_SELECTED_COLOR) + ); + text.setStrokeWidth(0.5); + setAlignment(Pos.CENTER_LEFT); + setFocusTraversable(true); + setOnKeyPressed(e -> { + if (e.getCode() == KeyCode.ENTER & !disable) { + action.run(); + } + }); + + setOnMouseClicked(event->{ + if(!disable){ + action.run(); + } + }); + setOnMouseEntered(event -> text.setFill(Color.RED)); + setOnMouseExited(event -> text.setFill(SELECTED_COLOR)); + getChildren().addAll(text); + } + } + private static class PauseButton extends StackPane { private static final Color SELECTED_COLOR = Color.WHITE; diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index eca662b..7b32eb1 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -3,6 +3,7 @@ requires com.almasb.fxgl.all; exports com.dinosaur.dinosaurexploder; requires javafx.media; + requires annotations; opens assets.textures; opens assets.sounds; diff --git a/src/main/resources/Styles/styles.css b/src/main/resources/Styles/styles.css index df9cba9..3237287 100644 --- a/src/main/resources/Styles/styles.css +++ b/src/main/resources/Styles/styles.css @@ -13,4 +13,4 @@ .slider .thumb { -fx-background-radius: 10; -fx-background-color: #005500; -} +} \ No newline at end of file