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);
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Listener for handling actions triggered by the Escape key.
 | 
			
		||||
     */
 | 
			
		||||
    private GameMusic music;
 | 
			
		||||
 | 
			
		||||
    static {
 | 
			
		||||
        // Configure logging
 | 
			
		||||
        LogManager manager = LogManager.getLogManager();
 | 
			
		||||
@@ -193,6 +198,15 @@ DialogManager getDialogManager() {
 | 
			
		||||
        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.
 | 
			
		||||
     *
 | 
			
		||||
@@ -225,6 +239,8 @@ public void simpleInitApp() {
 | 
			
		||||
        setupStates();
 | 
			
		||||
        setupGui();
 | 
			
		||||
        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;
 | 
			
		||||
 | 
			
		||||
import com.simsilica.lemur.Button;
 | 
			
		||||
import com.simsilica.lemur.Checkbox;
 | 
			
		||||
import com.simsilica.lemur.Label;
 | 
			
		||||
import com.simsilica.lemur.*;
 | 
			
		||||
import com.simsilica.lemur.core.VersionedReference;
 | 
			
		||||
import com.simsilica.lemur.style.ElementId;
 | 
			
		||||
import pp.dialog.Dialog;
 | 
			
		||||
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 saveButton = new Button(lookup("menu.map.save"));
 | 
			
		||||
 | 
			
		||||
    private final VersionedReference<Double> volumeRef;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Constructs the Menu dialog for the Battleship application.
 | 
			
		||||
     *
 | 
			
		||||
@@ -49,6 +50,20 @@ public Menu(BattleshipApp app) {
 | 
			
		||||
                .addClickCommands(s -> ifTopDialog(this::loadDialog));
 | 
			
		||||
        addChild(saveButton)
 | 
			
		||||
                .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")))
 | 
			
		||||
                .addClickCommands(s -> ifTopDialog(this::close));
 | 
			
		||||
        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
 | 
			
		||||
    public void update() {
 | 
			
		||||
        loadButton.setEnabled(app.getGameLogic().mayLoadMap());
 | 
			
		||||
        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.map.load=Load map from file...
 | 
			
		||||
menu.map.save=Save map in file...
 | 
			
		||||
menu.music.toggle=Toggle music on/off
 | 
			
		||||
menu.music.slider=Volumeslider
 | 
			
		||||
label.file=File:
 | 
			
		||||
label.connecting=Connecting...
 | 
			
		||||
dialog.error=Error
 | 
			
		||||
 
 | 
			
		||||
@@ -31,6 +31,8 @@ menu.return-to-game=Zurück zum Spiel
 | 
			
		||||
menu.sound-enabled=Sound eingeschaltet
 | 
			
		||||
menu.map.load=Karte von Datei laden...
 | 
			
		||||
menu.map.save=Karte in Datei speichern...
 | 
			
		||||
menu.music.toggle=Musik an/ausschalten
 | 
			
		||||
menu.music.slider=Lautstärkeregler
 | 
			
		||||
label.file=Datei:
 | 
			
		||||
label.connecting=Verbindung wird aufgebaut...
 | 
			
		||||
dialog.error=Fehler
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user