solution for exercise 10
added BackgroundMusic which is being handled in BackgroundMusic.java changed the menu to incoporate volume controls for the music
This commit is contained in:
		
						parent
						
							d15f1a3f5f
						
					
				
				
					commit
					d471f524d0
				
			@@ -0,0 +1,101 @@
 | 
				
			|||||||
 | 
					package pp.battleship.client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.jme3.app.Application;
 | 
				
			||||||
 | 
					import com.jme3.audio.AudioData.DataType;
 | 
				
			||||||
 | 
					import com.jme3.audio.AudioNode;
 | 
				
			||||||
 | 
					import com.jme3.audio.AudioSource.Status;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.prefs.Preferences;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public class BackgroundMusic {
 | 
				
			||||||
 | 
					    private static final String VOLUME_PREF = "volume";
 | 
				
			||||||
 | 
					    private static final String MUSIC_ENABLED_PREF = "musicEnabled";
 | 
				
			||||||
 | 
					    private Preferences prefs = Preferences.userNodeForPackage(BackgroundMusic.class);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final AudioNode backgroundMusic;
 | 
				
			||||||
 | 
					    private boolean musicEnabled;
 | 
				
			||||||
 | 
					    private float volume;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Initializes and controls the BackgroundMusic
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param app The main Application
 | 
				
			||||||
 | 
					     * @param musicFilePath The Path for the specific background music
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public BackgroundMusic(Application app, String musicFilePath) {
 | 
				
			||||||
 | 
					        this.volume = prefs.getFloat(VOLUME_PREF, 1.0f);
 | 
				
			||||||
 | 
					        this.musicEnabled = prefs.getBoolean(MUSIC_ENABLED_PREF, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        backgroundMusic = new AudioNode(app.getAssetManager(), musicFilePath, DataType.Stream);
 | 
				
			||||||
 | 
					        backgroundMusic.setLooping(true);
 | 
				
			||||||
 | 
					        backgroundMusic.setPositional(false);
 | 
				
			||||||
 | 
					        backgroundMusic.setVolume(1.0f);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(musicEnabled) {
 | 
				
			||||||
 | 
					            play();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Plays the music if the music is Stopped or paused
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void play() {
 | 
				
			||||||
 | 
					        if (musicEnabled && (backgroundMusic.getStatus() == Status.Stopped || backgroundMusic.getStatus() == Status.Paused)) {
 | 
				
			||||||
 | 
					            backgroundMusic.play();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Stops the music if it is playing
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void stop(){
 | 
				
			||||||
 | 
					        if (backgroundMusic.getStatus() == Status.Playing) {
 | 
				
			||||||
 | 
					            backgroundMusic.stop();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Toggle Method to control the music
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void toogleMusic() {
 | 
				
			||||||
 | 
					        this.musicEnabled = !this.musicEnabled;
 | 
				
			||||||
 | 
					        if (musicEnabled) {
 | 
				
			||||||
 | 
					            play();
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            stop();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        prefs.putFloat(VOLUME_PREF, volume);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Method to set the volume for the music
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param volume float to transfer the new volume
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void setVolume(float volume) {
 | 
				
			||||||
 | 
					        this.volume = volume;
 | 
				
			||||||
 | 
					        backgroundMusic.setVolume(volume);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        prefs.putFloat(VOLUME_PREF, volume);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * This method retuns the volume
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return the current volume as a float
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public float getVolume() {
 | 
				
			||||||
 | 
					        return volume;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Returns if music should be played or not
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return boolean value in music should be played
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean isMusicEnabled() {
 | 
				
			||||||
 | 
					        return musicEnabled;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -122,6 +122,11 @@ public class BattleshipApp extends SimpleApplication implements BattleshipClient
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
 | 
					    private final ActionListener escapeListener = (name, isPressed, tpf) -> escape(isPressed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * The Object which handles the background music
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private BackgroundMusic backgroundMusic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static {
 | 
					    static {
 | 
				
			||||||
        // Configure logging
 | 
					        // Configure logging
 | 
				
			||||||
        LogManager manager = LogManager.getLogManager();
 | 
					        LogManager manager = LogManager.getLogManager();
 | 
				
			||||||
@@ -225,6 +230,8 @@ public void simpleInitApp() {
 | 
				
			|||||||
        setupStates();
 | 
					        setupStates();
 | 
				
			||||||
        setupGui();
 | 
					        setupGui();
 | 
				
			||||||
        serverConnection.connect();
 | 
					        serverConnection.connect();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        backgroundMusic = new BackgroundMusic(this, "Music/MainMenu/Dark_Intro.ogg");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -426,4 +433,13 @@ void errorDialog(String errorMessage) {
 | 
				
			|||||||
                     .build()
 | 
					                     .build()
 | 
				
			||||||
                     .open();
 | 
					                     .open();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * this method returns the object which handles the background music
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return BackgroundMusic
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public BackgroundMusic getBackgroundMusic(){
 | 
				
			||||||
 | 
					        return backgroundMusic;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
import com.simsilica.lemur.Button;
 | 
					import com.simsilica.lemur.Button;
 | 
				
			||||||
import com.simsilica.lemur.Checkbox;
 | 
					import com.simsilica.lemur.Checkbox;
 | 
				
			||||||
 | 
					import com.simsilica.lemur.DefaultRangedValueModel;
 | 
				
			||||||
import com.simsilica.lemur.Label;
 | 
					import com.simsilica.lemur.Label;
 | 
				
			||||||
 | 
					import com.simsilica.lemur.Slider;
 | 
				
			||||||
 | 
					import com.simsilica.lemur.core.VersionedReference;
 | 
				
			||||||
import com.simsilica.lemur.style.ElementId;
 | 
					import com.simsilica.lemur.style.ElementId;
 | 
				
			||||||
import pp.dialog.Dialog;
 | 
					import pp.dialog.Dialog;
 | 
				
			||||||
import pp.dialog.StateCheckboxModel;
 | 
					import pp.dialog.StateCheckboxModel;
 | 
				
			||||||
@@ -34,6 +37,8 @@ class Menu extends Dialog {
 | 
				
			|||||||
    private final Button loadButton = new Button(lookup("menu.map.load"));
 | 
					    private final Button loadButton = new Button(lookup("menu.map.load"));
 | 
				
			||||||
    private final Button saveButton = new Button(lookup("menu.map.save"));
 | 
					    private final Button saveButton = new Button(lookup("menu.map.save"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private final VersionedReference<Double> volumeRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Constructs the Menu dialog for the Battleship application.
 | 
					     * Constructs the Menu dialog for the Battleship application.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@@ -45,6 +50,19 @@ public Menu(BattleshipApp app) {
 | 
				
			|||||||
        addChild(new Label(lookup("battleship.name"), new ElementId("header"))); //NON-NLS
 | 
					        addChild(new Label(lookup("battleship.name"), new ElementId("header"))); //NON-NLS
 | 
				
			||||||
        addChild(new Checkbox(lookup("menu.sound-enabled"),
 | 
					        addChild(new Checkbox(lookup("menu.sound-enabled"),
 | 
				
			||||||
                              new StateCheckboxModel(app, GameSound.class)));
 | 
					                              new StateCheckboxModel(app, GameSound.class)));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Checkbox musicToggle = new Checkbox(lookup("menu.music.toggle"));
 | 
				
			||||||
 | 
					        musicToggle.setChecked(app.getBackgroundMusic().isMusicEnabled());
 | 
				
			||||||
 | 
					        musicToggle.addClickCommands(s -> toggleMusic());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        addChild(musicToggle);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Slider volumeSlider = new Slider();
 | 
				
			||||||
 | 
					        volumeSlider.setModel(new DefaultRangedValueModel(0.0 , 2.0, app.getBackgroundMusic().getVolume()));
 | 
				
			||||||
 | 
					        addChild(volumeSlider);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        volumeRef = volumeSlider.getModel().createReference();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        addChild(loadButton)
 | 
					        addChild(loadButton)
 | 
				
			||||||
                .addClickCommands(s -> ifTopDialog(this::loadDialog));
 | 
					                .addClickCommands(s -> ifTopDialog(this::loadDialog));
 | 
				
			||||||
        addChild(saveButton)
 | 
					        addChild(saveButton)
 | 
				
			||||||
@@ -56,6 +74,34 @@ public Menu(BattleshipApp app) {
 | 
				
			|||||||
        update();
 | 
					        update();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * this method is used update the volume when there is a change in the slider
 | 
				
			||||||
 | 
					     * @param tpf time per frame
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void update(float tpf){
 | 
				
			||||||
 | 
					        if(volumeRef.update()){
 | 
				
			||||||
 | 
					            double newVolume = volumeRef.get();
 | 
				
			||||||
 | 
					            adjustVolume(newVolume);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * this method adjust the volume for the background music
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param volume is the double value of the volume
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void adjustVolume(double volume) {
 | 
				
			||||||
 | 
					        app.getBackgroundMusic().setVolume((float) volume);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * this method toggles the background music on and off
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private void toggleMusic() {
 | 
				
			||||||
 | 
					        app.getBackgroundMusic().toogleMusic();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Updates the state of the load and save buttons based on the game logic.
 | 
					     * Updates the state of the load and save buttons based on the game logic.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -144,18 +144,13 @@ public Spatial visit(Battleship ship) {
 | 
				
			|||||||
     * @return the spatial representing the battleship
 | 
					     * @return the spatial representing the battleship
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    private Spatial createShip(Battleship ship) {
 | 
					    private Spatial createShip(Battleship ship) {
 | 
				
			||||||
        switch (ship.getLength()){
 | 
					        return switch (ship.getLength()) {
 | 
				
			||||||
            case 1:
 | 
					            case 1 -> createPatrolBoat(ship);
 | 
				
			||||||
                return createPatrolBoat(ship);
 | 
					            case 2 -> createModernBattleship(ship);
 | 
				
			||||||
            case 2:
 | 
					            case 3 -> createUBoat(ship);
 | 
				
			||||||
                return createModernBattleship(ship);
 | 
					            case 4 -> createBattleship(ship);
 | 
				
			||||||
            case 3:
 | 
					            default -> throw new IllegalArgumentException("Ship length must be between 1 and 4 units long");
 | 
				
			||||||
                return createUBoat(ship);
 | 
					        };
 | 
				
			||||||
            case 4:
 | 
					 | 
				
			||||||
                return createBattleship(ship);
 | 
					 | 
				
			||||||
            default:
 | 
					 | 
				
			||||||
                throw new IllegalArgumentException("Ship length must be between 1 and 4 units long");
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -210,6 +205,12 @@ private Spatial createBattleship(Battleship ship) {
 | 
				
			|||||||
        return model;
 | 
					        return model;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * creates a detailed 3D model to represent an UBoat
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ship the ship to be represented
 | 
				
			||||||
 | 
					     * @return the spatial representing the Uboat
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private Spatial createUBoat(Battleship ship) {
 | 
					    private Spatial createUBoat(Battleship ship) {
 | 
				
			||||||
        final Spatial model = app.getAssetManager().loadModel(UBOAT);
 | 
					        final Spatial model = app.getAssetManager().loadModel(UBOAT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -221,6 +222,12 @@ private Spatial createUBoat(Battleship ship) {
 | 
				
			|||||||
        return model;
 | 
					        return model;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * creates a detailed 3D model to represent the modern battleship
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ship the ship to be represented
 | 
				
			||||||
 | 
					     * @return the spatial representing the Modern Battleship
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private Spatial createModernBattleship(Battleship ship) {
 | 
					    private Spatial createModernBattleship(Battleship ship) {
 | 
				
			||||||
        final Spatial model = app.getAssetManager().loadModel(BATTLE_SHIP_MODERN);
 | 
					        final Spatial model = app.getAssetManager().loadModel(BATTLE_SHIP_MODERN);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -232,6 +239,12 @@ private Spatial createModernBattleship(Battleship ship) {
 | 
				
			|||||||
        return model;
 | 
					        return model;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * creates a detailed 3D model to represent the patrol boat
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param ship the ship to be represented
 | 
				
			||||||
 | 
					     * @return the spatial representing the patrol boat
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    private Spatial createPatrolBoat(Battleship ship) {
 | 
					    private Spatial createPatrolBoat(Battleship ship) {
 | 
				
			||||||
        final Spatial model = app.getAssetManager().loadModel(PATROL_BOAT);
 | 
					        final Spatial model = app.getAssetManager().loadModel(PATROL_BOAT);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -31,6 +31,8 @@ menu.return-to-game=Return to game
 | 
				
			|||||||
menu.sound-enabled=Sound switched on
 | 
					menu.sound-enabled=Sound switched on
 | 
				
			||||||
menu.map.load=Load map from file...
 | 
					menu.map.load=Load map from file...
 | 
				
			||||||
menu.map.save=Save map in file...
 | 
					menu.map.save=Save map in file...
 | 
				
			||||||
 | 
					menu.music.toggle=Toggle the music
 | 
				
			||||||
 | 
					menu.volume=Volume
 | 
				
			||||||
label.file=File:
 | 
					label.file=File:
 | 
				
			||||||
label.connecting=Connecting...
 | 
					label.connecting=Connecting...
 | 
				
			||||||
dialog.error=Error
 | 
					dialog.error=Error
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,8 @@ menu.return-to-game=Zurück zum Spiel
 | 
				
			|||||||
menu.sound-enabled=Sound eingeschaltet
 | 
					menu.sound-enabled=Sound eingeschaltet
 | 
				
			||||||
menu.map.load=Karte von Datei laden...
 | 
					menu.map.load=Karte von Datei laden...
 | 
				
			||||||
menu.map.save=Karte in Datei speichern...
 | 
					menu.map.save=Karte in Datei speichern...
 | 
				
			||||||
 | 
					menu.music.toggle=An/Ausschalten der Musik
 | 
				
			||||||
 | 
					menu.volume=Lautst<EFBFBD>rke
 | 
				
			||||||
label.file=Datei:
 | 
					label.file=Datei:
 | 
				
			||||||
label.connecting=Verbindung wird aufgebaut...
 | 
					label.connecting=Verbindung wird aufgebaut...
 | 
				
			||||||
dialog.error=Fehler
 | 
					dialog.error=Fehler
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user