Add GameMusic
This commit is contained in:
		@@ -1,4 +1,166 @@
 | 
			
		||||
package pp.mdga.client.Acoustic;
 | 
			
		||||
 | 
			
		||||
import com.jme3.audio.AudioNode;
 | 
			
		||||
import com.jme3.system.NanoTimer;
 | 
			
		||||
import pp.mdga.client.MdgaApp;
 | 
			
		||||
import pp.mdga.client.MdgaState;
 | 
			
		||||
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
import java.util.Collections;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Random;
 | 
			
		||||
 | 
			
		||||
public class AcousticHandler {
 | 
			
		||||
    private MdgaApp app;
 | 
			
		||||
 | 
			
		||||
    private MdgaState state = MdgaState.NONE;
 | 
			
		||||
 | 
			
		||||
    boolean playGame = false;
 | 
			
		||||
    private ArrayList<MusicAsset> gameTracks = new ArrayList<>();
 | 
			
		||||
    private Random random = new Random();
 | 
			
		||||
    private NanoTimer  trackTimer = new NanoTimer();
 | 
			
		||||
 | 
			
		||||
    private boolean fading = false;
 | 
			
		||||
    private boolean crossFading = false;
 | 
			
		||||
    private GameMusic scheduled = null;
 | 
			
		||||
    private GameMusic playing = null;
 | 
			
		||||
    private NanoTimer fadeTimer = new NanoTimer();
 | 
			
		||||
    private float fadeVolume = 1.0f;
 | 
			
		||||
    private final float FADE_DURATION = 3.0f; // Sekunden für das Fading
 | 
			
		||||
    private final float CROSSFADE_DURATION = 1.0f; // Zeit, in der beide Tracks gleichzeitig spielen
 | 
			
		||||
 | 
			
		||||
    private float mainVolume = 1.0f;
 | 
			
		||||
    private float musicVolume = 1.0f;
 | 
			
		||||
    private float soundVolume = 1.0f;
 | 
			
		||||
 | 
			
		||||
    public AcousticHandler(MdgaApp app) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float getMainVolume() {
 | 
			
		||||
        return  mainVolume;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float getMusicVolume() {
 | 
			
		||||
        return musicVolume;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public float getSoundVolume() {
 | 
			
		||||
        return soundVolume;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void update() {
 | 
			
		||||
        updateVolumeAndTrack();
 | 
			
		||||
 | 
			
		||||
        if(playGame) {
 | 
			
		||||
            updateGameTracks();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void playState(MdgaState state) {
 | 
			
		||||
        if(this.state == state) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        MusicAsset asset = null;
 | 
			
		||||
 | 
			
		||||
        switch (state) {
 | 
			
		||||
            case MAIN:
 | 
			
		||||
                playGame = false;
 | 
			
		||||
                asset = MusicAsset.MAIN_MENU;
 | 
			
		||||
                break;
 | 
			
		||||
            case LOBBY:
 | 
			
		||||
                playGame = false;
 | 
			
		||||
                asset = MusicAsset.LOBBY;
 | 
			
		||||
                break;
 | 
			
		||||
            case GAME:
 | 
			
		||||
                addGameTracks();
 | 
			
		||||
                playGame = true;
 | 
			
		||||
                asset = gameTracks.remove(0);
 | 
			
		||||
                break;
 | 
			
		||||
            case CEREMONY:
 | 
			
		||||
                playGame = false;
 | 
			
		||||
                asset = MusicAsset.CEREMONY;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        assert(null != asset) : "music sceduling went wrong";
 | 
			
		||||
 | 
			
		||||
        scheduled = new GameMusic(app, asset.getPath(), getMusicVolume() * getMainVolume(), asset.getLoop());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private float lerp(float start, float end, float t) {
 | 
			
		||||
        return start + t * (end - start);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateVolumeAndTrack() {
 | 
			
		||||
        if (playing == null && scheduled != null && !fading) {
 | 
			
		||||
            playing = scheduled;
 | 
			
		||||
            scheduled = null;
 | 
			
		||||
            fadeVolume = 1.0f;
 | 
			
		||||
            playing.play();
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (scheduled != null && !fading) {
 | 
			
		||||
            fading = true;
 | 
			
		||||
            fadeTimer.reset();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (fading) {
 | 
			
		||||
            float time = fadeTimer.getTimeInSeconds();
 | 
			
		||||
 | 
			
		||||
            if (time <= FADE_DURATION) {
 | 
			
		||||
                float t = Math.min(time / FADE_DURATION, 1.0f);
 | 
			
		||||
                float oldVolume = lerp(1.0f, 0.0f, t);
 | 
			
		||||
                if (playing != null) {
 | 
			
		||||
                    playing.update(getMusicVolume() * getMainVolume() * oldVolume);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (time > FADE_DURATION && time <= FADE_DURATION + CROSSFADE_DURATION) {
 | 
			
		||||
                float t = Math.min((time - FADE_DURATION) / CROSSFADE_DURATION, 1.0f);
 | 
			
		||||
                float newVolume = lerp(0.0f, 1.0f, t);
 | 
			
		||||
 | 
			
		||||
                if (!scheduled.isPlaying()) {
 | 
			
		||||
                    scheduled.play();
 | 
			
		||||
                }
 | 
			
		||||
                scheduled.update(getMusicVolume() * getMainVolume() * newVolume);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (time > FADE_DURATION + CROSSFADE_DURATION) {
 | 
			
		||||
                if (playing != null) {
 | 
			
		||||
                    playing.pause();
 | 
			
		||||
                }
 | 
			
		||||
                playing = scheduled;
 | 
			
		||||
                scheduled = null;
 | 
			
		||||
 | 
			
		||||
                fadeVolume = 1.0f;
 | 
			
		||||
                fading = false;
 | 
			
		||||
            }
 | 
			
		||||
        } else if (playing != null) {
 | 
			
		||||
            playing.update(getMusicVolume() * getMainVolume());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void addGameTracks() {
 | 
			
		||||
        for (int i = 1; i <= 6; i++) {
 | 
			
		||||
            gameTracks.add(MusicAsset.valueOf("GAME_" + i));
 | 
			
		||||
        }
 | 
			
		||||
        Collections.shuffle(gameTracks, random);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void updateGameTracks() {
 | 
			
		||||
        if (playing != null && playing.nearEnd(3) && trackTimer.getTimeInSeconds() > 20) {
 | 
			
		||||
            trackTimer.reset();
 | 
			
		||||
 | 
			
		||||
            if (gameTracks.isEmpty()) {
 | 
			
		||||
                addGameTracks();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            MusicAsset nextTrack = gameTracks.remove(0);
 | 
			
		||||
 | 
			
		||||
            scheduled = new GameMusic(app, nextTrack.getPath(), getMusicVolume() * getMainVolume(), nextTrack.getLoop());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,81 @@
 | 
			
		||||
package pp.mdga.client.Acoustic;
 | 
			
		||||
 | 
			
		||||
import com.jme3.audio.AudioData;
 | 
			
		||||
import com.jme3.audio.AudioNode;
 | 
			
		||||
import com.jme3.audio.AudioSource;
 | 
			
		||||
import pp.mdga.client.MdgaApp;
 | 
			
		||||
 | 
			
		||||
public class GameMusic {
 | 
			
		||||
    private final MdgaApp app;
 | 
			
		||||
 | 
			
		||||
    private float volume;
 | 
			
		||||
    private AudioNode music;
 | 
			
		||||
 | 
			
		||||
    GameMusic(MdgaApp app, String path, float volume, boolean loop) {
 | 
			
		||||
        this.app = app;
 | 
			
		||||
        this.volume = volume;
 | 
			
		||||
 | 
			
		||||
        loadMusic(path);
 | 
			
		||||
 | 
			
		||||
        music.setLooping(loop);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void play() {
 | 
			
		||||
        if(null == music) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        music.play();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void pause() {
 | 
			
		||||
        if(null == music) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        music.stop();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void reset() {
 | 
			
		||||
        if(null == music) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        music.setTimeOffset(0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean isPlaying() {
 | 
			
		||||
        return music.getStatus() == AudioSource.Status.Playing;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    boolean nearEnd(float thresholdSeconds) {
 | 
			
		||||
        if (music == null || !isPlaying()) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        float currentTime = music.getPlaybackTime(); // Current playback time in seconds
 | 
			
		||||
        float duration = music.getAudioData().getDuration(); // Total duration in seconds
 | 
			
		||||
 | 
			
		||||
        if (duration <= 0) {
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        float remainingTime = duration - currentTime;
 | 
			
		||||
 | 
			
		||||
        return remainingTime <= thresholdSeconds;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void update(float newVolume) {
 | 
			
		||||
        if(volume != newVolume) {
 | 
			
		||||
            volume = newVolume;
 | 
			
		||||
            music.setVolume(volume);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void loadMusic(String path) {
 | 
			
		||||
        music = new AudioNode(app.getAssetManager(), path, AudioData.DataType.Stream);
 | 
			
		||||
        music.setVolume(volume);
 | 
			
		||||
        music.setPositional(false);
 | 
			
		||||
        music.setDirectional(false);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,4 @@
 | 
			
		||||
package pp.mdga.client.Acoustic;
 | 
			
		||||
 | 
			
		||||
public class GameSound {
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,32 @@
 | 
			
		||||
package pp.mdga.client.Acoustic;
 | 
			
		||||
 | 
			
		||||
public enum MusicAsset {
 | 
			
		||||
    MAIN_MENU("Spaceship.wav"),
 | 
			
		||||
    LOBBY("DeadPlanet.wav"),
 | 
			
		||||
    CEREMONY("80s,Disco,Life.wav"),
 | 
			
		||||
    GAME_1("NeonRoadTrip.wav", false),
 | 
			
		||||
    GAME_2("NoPressureTrance.wav", false),
 | 
			
		||||
    GAME_3("TheSynthRave.wav", false),
 | 
			
		||||
    GAME_4("LaserParty.wav", false),
 | 
			
		||||
    GAME_5("RetroNoir.wav", false),
 | 
			
		||||
    GAME_6("SpaceInvaders.wav", false);
 | 
			
		||||
 | 
			
		||||
    private final String path;
 | 
			
		||||
    private final boolean loop;
 | 
			
		||||
 | 
			
		||||
    MusicAsset(String name) {
 | 
			
		||||
        this.path = "music/" + name;
 | 
			
		||||
        this.loop = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    MusicAsset(String name, boolean loop) {
 | 
			
		||||
        this.path = "music/" + name;
 | 
			
		||||
        this.loop = loop;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public String getPath() {
 | 
			
		||||
        return path;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public boolean getLoop() { return loop; }
 | 
			
		||||
}
 | 
			
		||||
@@ -23,8 +23,9 @@ public class BoardView {
 | 
			
		||||
    private ArrayList<PieceControl> pieces;
 | 
			
		||||
 | 
			
		||||
    public BoardView(int playerCount, MdgaApp mdgaApp) {
 | 
			
		||||
        assert(2 <= playerCount && playerCount <= 4);
 | 
			
		||||
        assert(mdgaApp != null);
 | 
			
		||||
        assert(2 <= playerCount && playerCount <= 4) : "invalid player count";
 | 
			
		||||
        assert(mdgaApp != null) : "app is null";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        this.mdgaApp = mdgaApp;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -27,12 +27,12 @@ public List<AssetOnMap> loadMap(String mapName) {
 | 
			
		||||
                if(entry.charAt(0) == '#') continue;
 | 
			
		||||
 | 
			
		||||
                String[] parts = entry.trim().split(" ");
 | 
			
		||||
                if(parts.length != 2) throw  new RuntimeException();
 | 
			
		||||
                assert(parts.length == 2) : "parts.lenghth != 2";
 | 
			
		||||
 | 
			
		||||
                String assetName = parts[0];
 | 
			
		||||
                String[] coordinates = parts[1].split(",");
 | 
			
		||||
 | 
			
		||||
                if(coordinates.length != 2) throw new RuntimeException();
 | 
			
		||||
                assert(coordinates.length == 2) : "coordinates.lenghth != 2";
 | 
			
		||||
 | 
			
		||||
                int x = Integer.parseInt(coordinates[0]);
 | 
			
		||||
                int y = Integer.parseInt(coordinates[1]);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,8 @@
 | 
			
		||||
package pp.mdga.client;
 | 
			
		||||
 | 
			
		||||
import com.jme3.app.SimpleApplication;
 | 
			
		||||
import com.jme3.system.NanoTimer;
 | 
			
		||||
import pp.mdga.client.Acoustic.AcousticHandler;
 | 
			
		||||
import pp.mdga.client.Animation.AnimationHandler;
 | 
			
		||||
import com.jme3.light.AmbientLight;
 | 
			
		||||
import com.jme3.light.DirectionalLight;
 | 
			
		||||
@@ -20,15 +22,20 @@
 | 
			
		||||
 | 
			
		||||
public class MdgaApp extends SimpleApplication {
 | 
			
		||||
    private AnimationHandler animationHandler;
 | 
			
		||||
    private AcousticHandler acousticHandler;
 | 
			
		||||
    private BoardView boardView;
 | 
			
		||||
 | 
			
		||||
    NanoTimer test = new NanoTimer();
 | 
			
		||||
    private MdgaState testState = MdgaState.MAIN;
 | 
			
		||||
 | 
			
		||||
    public static void main(String[] args) {
 | 
			
		||||
        MdgaApp app = new MdgaApp();
 | 
			
		||||
        AppSettings settings = new AppSettings(true);
 | 
			
		||||
        settings.setSamples(128);
 | 
			
		||||
        settings.setCenterWindow(true);
 | 
			
		||||
        settings.setWidth(1300);
 | 
			
		||||
        settings.setHeight(1000);
 | 
			
		||||
        settings.setWidth(1280);
 | 
			
		||||
        settings.setHeight(720);
 | 
			
		||||
 | 
			
		||||
        MdgaApp app = new MdgaApp();
 | 
			
		||||
        app.setSettings(settings);
 | 
			
		||||
        app.setShowSettings(false);
 | 
			
		||||
        app.start();
 | 
			
		||||
@@ -37,8 +44,11 @@ public static void main(String[] args) {
 | 
			
		||||
    @Override
 | 
			
		||||
    public void simpleInitApp() {
 | 
			
		||||
        animationHandler = new AnimationHandler(this);
 | 
			
		||||
        acousticHandler = new AcousticHandler(this);
 | 
			
		||||
        boardView = new BoardView(4,this);
 | 
			
		||||
 | 
			
		||||
        acousticHandler.playState(MdgaState.GAME);
 | 
			
		||||
 | 
			
		||||
        flyCam.setEnabled(true);
 | 
			
		||||
        int zoom = 20;
 | 
			
		||||
        cam.setLocation(new Vector3f(zoom,0,zoom));
 | 
			
		||||
@@ -48,20 +58,48 @@ public void simpleInitApp() {
 | 
			
		||||
        sun.setColor(ColorRGBA.White);
 | 
			
		||||
        sun.setDirection(new Vector3f(-1,0,-1));
 | 
			
		||||
        rootNode.addLight(sun);
 | 
			
		||||
 | 
			
		||||
        AmbientLight ambient = new AmbientLight();
 | 
			
		||||
        ambient.setColor(new ColorRGBA(0.3f,0.3f,0.3f,1));
 | 
			
		||||
        rootNode.addLight(ambient);
 | 
			
		||||
 | 
			
		||||
        final int SHADOWMAP_SIZE=1024*8;
 | 
			
		||||
        final int SHADOWMAP_SIZE= 1024 * 8;
 | 
			
		||||
        DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 4);
 | 
			
		||||
        dlsr.setLight(sun);
 | 
			
		||||
        viewPort.addProcessor(dlsr);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void simpleUpdate(float tpf) {
 | 
			
		||||
        //this method will be called every game tick and can be used to make updates
 | 
			
		||||
        acousticHandler.update();
 | 
			
		||||
 | 
			
		||||
        test.reset();
 | 
			
		||||
        if(test.getTimeInSeconds() > 10){
 | 
			
		||||
            if(testState == MdgaState.MAIN) {
 | 
			
		||||
                testState = MdgaState.LOBBY;
 | 
			
		||||
                acousticHandler.playState(MdgaState.MAIN);
 | 
			
		||||
            } else if (testState == MdgaState.LOBBY) {
 | 
			
		||||
                testState = MdgaState.CEREMONY;
 | 
			
		||||
                acousticHandler.playState(MdgaState.LOBBY);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                testState = MdgaState.MAIN;
 | 
			
		||||
                acousticHandler.playState(MdgaState.CEREMONY);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            test.reset();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AnimationHandler getAnimationHandler() {
 | 
			
		||||
        return animationHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public AcousticHandler getAcousticHandler() {
 | 
			
		||||
        return acousticHandler;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public BoardView getBoardView() {
 | 
			
		||||
        return boardView;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,12 @@
 | 
			
		||||
import pp.mdga.notification.PlayerInGameNotification;
 | 
			
		||||
 | 
			
		||||
public enum MdgaState {
 | 
			
		||||
    NONE {
 | 
			
		||||
        @Override
 | 
			
		||||
        void handleNotification(MdgaApp app, Notification notification) {
 | 
			
		||||
            throw new RuntimeException("unexpected notification");
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
    MAIN {
 | 
			
		||||
        @Override
 | 
			
		||||
        void handleNotification(MdgaApp app, Notification notification) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user