Add GameMusic

This commit is contained in:
Felix
2024-11-15 14:39:10 +01:00
parent a3c5af58d7
commit 0bb4706fda
8 changed files with 335 additions and 11 deletions

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
package pp.mdga.client.Acoustic;
public class GameSound {
}

View File

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

View File

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

View File

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

View File

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

View File

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