Add music
This commit is contained in:
@@ -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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Listener for handling actions triggered by the Escape key.
|
||||||
|
*/
|
||||||
|
private GameMusic music;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// Configure logging
|
// Configure logging
|
||||||
LogManager manager = LogManager.getLogManager();
|
LogManager manager = LogManager.getLogManager();
|
||||||
@@ -193,6 +198,15 @@ DialogManager getDialogManager() {
|
|||||||
return dialogManager;
|
return dialogManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the GameMusic responsible for playing music.
|
||||||
|
*
|
||||||
|
* @return The {@link GameMusic} instance.
|
||||||
|
*/
|
||||||
|
GameMusic getGameMusic() {
|
||||||
|
return music;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the game logic handler for the client.
|
* Returns the game logic handler for the client.
|
||||||
*
|
*
|
||||||
@@ -225,6 +239,8 @@ public void simpleInitApp() {
|
|||||||
setupStates();
|
setupStates();
|
||||||
setupGui();
|
setupGui();
|
||||||
serverConnection.connect();
|
serverConnection.connect();
|
||||||
|
|
||||||
|
music = new GameMusic(this, "Sound/Music/battleship.ogg");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
////////////////////////////////////////
|
||||||
|
// Programming project code
|
||||||
|
// UniBw M, 2022, 2023, 2024
|
||||||
|
// www.unibw.de/inf2
|
||||||
|
// (c) Mark Minas (mark.minas@unibw.de)
|
||||||
|
////////////////////////////////////////
|
||||||
|
|
||||||
|
package pp.battleship.client;
|
||||||
|
|
||||||
|
import com.jme3.app.Application;
|
||||||
|
import com.jme3.app.state.AbstractAppState;
|
||||||
|
import com.jme3.app.state.AppStateManager;
|
||||||
|
import com.jme3.asset.AssetLoadException;
|
||||||
|
import com.jme3.asset.AssetNotFoundException;
|
||||||
|
import com.jme3.audio.AudioData;
|
||||||
|
import com.jme3.audio.AudioNode;
|
||||||
|
import com.jme3.audio.AudioSource;
|
||||||
|
import pp.battleship.notification.GameEventListener;
|
||||||
|
import pp.battleship.notification.SoundEvent;
|
||||||
|
|
||||||
|
import java.lang.System.Logger;
|
||||||
|
import java.lang.System.Logger.Level;
|
||||||
|
import java.util.prefs.Preferences;
|
||||||
|
|
||||||
|
import static pp.util.PreferencesUtils.getPreferences;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An application state that plays music.
|
||||||
|
*/
|
||||||
|
public class GameMusic extends AbstractAppState implements GameEventListener {
|
||||||
|
private static final Logger LOGGER = System.getLogger(GameMusic.class.getName());
|
||||||
|
|
||||||
|
private static final Preferences PREFERENCES = getPreferences(GameMusic.class);
|
||||||
|
private static final String ENABLED_PREF = "toggle"; //NON-NLS
|
||||||
|
private static final String SLIDER_PREF = "slider"; //NON-NLS
|
||||||
|
|
||||||
|
private AudioNode music;
|
||||||
|
private boolean enabled;
|
||||||
|
private float volume;
|
||||||
|
|
||||||
|
public GameMusic(Application app, String musicFilePath) {
|
||||||
|
this.enabled = PREFERENCES.getBoolean(ENABLED_PREF, true);
|
||||||
|
this.volume = PREFERENCES.getFloat(SLIDER_PREF, 2.0f);
|
||||||
|
|
||||||
|
music = new AudioNode(app.getAssetManager(), musicFilePath, AudioData.DataType.Stream);
|
||||||
|
music.setLooping(true);
|
||||||
|
music.setPositional(false);
|
||||||
|
music.setVolume(1.0f);
|
||||||
|
|
||||||
|
if(enabled) {
|
||||||
|
start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if music is enabled in the preferences.
|
||||||
|
*
|
||||||
|
* @return {@code true} if music is enabled, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public static boolean enabledInPreferences() {
|
||||||
|
return PREFERENCES.getBoolean(ENABLED_PREF, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the volume value that is set in the preferences.
|
||||||
|
*
|
||||||
|
* @return {@code true} if sound is enabled, {@code false} otherwise.
|
||||||
|
*/
|
||||||
|
public static float volumeInPreferences() {
|
||||||
|
return PREFERENCES.getFloat(SLIDER_PREF, 2.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Toggles the game music on or off.
|
||||||
|
*/
|
||||||
|
public void toggleMusic() {
|
||||||
|
setEnabled(!isEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the enabled state of this AppState.
|
||||||
|
* Overrides {@link AbstractAppState#setEnabled(boolean)}
|
||||||
|
*
|
||||||
|
* @param enabled {@code true} to enable the AppState, {@code false} to disable it.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setEnabled(boolean enabled) {
|
||||||
|
super.setEnabled(enabled);
|
||||||
|
|
||||||
|
if(enabled) {
|
||||||
|
start();
|
||||||
|
} else {
|
||||||
|
stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Music enabled: {0}", enabled); //NON-NLS
|
||||||
|
PREFERENCES.putBoolean(ENABLED_PREF, enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the volume for the music
|
||||||
|
*
|
||||||
|
* @param volume the new volume to be set
|
||||||
|
*/
|
||||||
|
public void setVolume(float volume) {
|
||||||
|
this.volume = volume;
|
||||||
|
music.setVolume(volume);
|
||||||
|
|
||||||
|
LOGGER.log(Level.INFO, "Volume set to: {0}", volume); //NON-NLS
|
||||||
|
PREFERENCES.putFloat(SLIDER_PREF, volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a music from the specified file.
|
||||||
|
*
|
||||||
|
* @param app The application
|
||||||
|
* @param name The name of the sound file.
|
||||||
|
* @return The loaded AudioNode.
|
||||||
|
*/
|
||||||
|
private AudioNode loadSound(Application app, String name) {
|
||||||
|
try {
|
||||||
|
final AudioNode sound = new AudioNode(app.getAssetManager(), name, AudioData.DataType.Buffer);
|
||||||
|
sound.setLooping(false);
|
||||||
|
sound.setPositional(false);
|
||||||
|
return sound;
|
||||||
|
}
|
||||||
|
catch (AssetLoadException | AssetNotFoundException ex) {
|
||||||
|
LOGGER.log(Level.ERROR, ex.getMessage(), ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the music.
|
||||||
|
*/
|
||||||
|
public void start() {
|
||||||
|
if (enabled && (music.getStatus() == AudioSource.Status.Stopped || music.getStatus() == AudioSource.Status.Paused)) {
|
||||||
|
music.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops the music.
|
||||||
|
*/
|
||||||
|
public void stop() {
|
||||||
|
if (music.getStatus() == AudioSource.Status.Playing) {
|
||||||
|
music.stop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method returns the volume
|
||||||
|
*
|
||||||
|
* @return float the current volume
|
||||||
|
*/
|
||||||
|
public float getVolume() {
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns if music should be played or not
|
||||||
|
*
|
||||||
|
* @return boolean value if music is enabled
|
||||||
|
*/
|
||||||
|
public boolean isMusicEnabled() {
|
||||||
|
return enabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,9 +7,8 @@
|
|||||||
|
|
||||||
package pp.battleship.client;
|
package pp.battleship.client;
|
||||||
|
|
||||||
import com.simsilica.lemur.Button;
|
import com.simsilica.lemur.*;
|
||||||
import com.simsilica.lemur.Checkbox;
|
import com.simsilica.lemur.core.VersionedReference;
|
||||||
import com.simsilica.lemur.Label;
|
|
||||||
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 +33,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.
|
||||||
*
|
*
|
||||||
@@ -49,6 +50,20 @@ public Menu(BattleshipApp app) {
|
|||||||
.addClickCommands(s -> ifTopDialog(this::loadDialog));
|
.addClickCommands(s -> ifTopDialog(this::loadDialog));
|
||||||
addChild(saveButton)
|
addChild(saveButton)
|
||||||
.addClickCommands(s -> ifTopDialog(this::saveDialog));
|
.addClickCommands(s -> ifTopDialog(this::saveDialog));
|
||||||
|
|
||||||
|
Checkbox musicToggle = new Checkbox(lookup("menu.music.toggle"));
|
||||||
|
musicToggle.setChecked(app.getGameMusic().isMusicEnabled());
|
||||||
|
musicToggle.addClickCommands(s -> toggleMusic());
|
||||||
|
|
||||||
|
addChild(musicToggle);
|
||||||
|
|
||||||
|
Slider volumeSlider = new Slider(lookup("menu.music.slider"));
|
||||||
|
volumeSlider.setModel(new DefaultRangedValueModel(0.0 , 4.0, app.getGameMusic().getVolume()));
|
||||||
|
volumeSlider.setDelta(0.4);
|
||||||
|
addChild(volumeSlider);
|
||||||
|
|
||||||
|
volumeRef = volumeSlider.getModel().createReference();
|
||||||
|
|
||||||
addChild(new Button(lookup("menu.return-to-game")))
|
addChild(new Button(lookup("menu.return-to-game")))
|
||||||
.addClickCommands(s -> ifTopDialog(this::close));
|
.addClickCommands(s -> ifTopDialog(this::close));
|
||||||
addChild(new Button(lookup("menu.quit")))
|
addChild(new Button(lookup("menu.quit")))
|
||||||
@@ -57,12 +72,33 @@ public Menu(BattleshipApp app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the state of the load and save buttons based on the game logic.
|
* Updates the state of the load/save buttons and volume based on the game logic.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void update() {
|
public void update() {
|
||||||
loadButton.setEnabled(app.getGameLogic().mayLoadMap());
|
loadButton.setEnabled(app.getGameLogic().mayLoadMap());
|
||||||
saveButton.setEnabled(app.getGameLogic().maySaveMap());
|
saveButton.setEnabled(app.getGameLogic().maySaveMap());
|
||||||
|
|
||||||
|
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.getGameMusic().setVolume((float) volume);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* this method toggles the background music on and off
|
||||||
|
*/
|
||||||
|
private void toggleMusic() {
|
||||||
|
app.getGameMusic().toggleMusic();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
credit to patrickdearteaga.com
|
||||||
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 music on/off
|
||||||
|
menu.music.slider=Volumeslider
|
||||||
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=Musik an/ausschalten
|
||||||
|
menu.music.slider=Lautstärkeregler
|
||||||
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