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:
Hanno Fleischer hanno.fleischer@unibw.de
2024-10-03 17:39:54 +02:00
parent d15f1a3f5f
commit d471f524d0
9 changed files with 192 additions and 12 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}
} }

View File

@@ -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.
*/ */

View File

@@ -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);

View File

@@ -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

View File

@@ -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