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