Add subVolume and delay

This commit is contained in:
Felix
2024-11-16 13:07:39 +01:00
parent b317bb957a
commit b509ab772d
10 changed files with 177 additions and 154 deletions

View File

@@ -1,8 +1,6 @@
package pp.mdga.client.Acoustic;
import com.jme3.audio.AudioNode;
import com.jme3.system.NanoTimer;
import pp.mdga.client.Board.Asset;
import pp.mdga.client.MdgaApp;
import pp.mdga.client.MdgaState;
@@ -13,17 +11,12 @@ public class AcousticHandler {
private MdgaState state = MdgaState.NONE;
boolean playGame = false;
private 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;
private final float CROSSFADE_DURATION = 1.5f;
@@ -31,24 +24,15 @@ public class AcousticHandler {
private float musicVolume = 1.0f;
private float soundVolume = 1.0f;
private GameMusic scheduled = null;
private GameMusic playing = null;
private ArrayList<GameSound> sounds = new ArrayList<>();
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();
@@ -59,29 +43,31 @@ public void update() {
Iterator<GameSound> iterator = sounds.iterator();
while (iterator.hasNext()) {
GameSound s = iterator.next();
s.update(getSoundVolumeTotal());
if (!s.isPlaying()) {
iterator.remove();
}
}
}
public void playSound(Sound sound) {
ArrayList<SoundAsset> assets = new ArrayList<SoundAsset>();
public void playSound(MdgaSound sound) {
ArrayList<SoundAssetDelayVolume> assets = new ArrayList<SoundAssetDelayVolume>();
switch (sound) {
case LOST:
assets.add(SoundAsset.LOST);
assets.add(new SoundAssetDelayVolume(SoundAsset.LOST, 1.0f, 0.0f));
break;
case VICTORY:
assets.add(SoundAsset.VICTORY);
assets.add(new SoundAssetDelayVolume(SoundAsset.VICTORY, 1.0f, 2.0f));
break;
default:
break;
}
for (SoundAsset a : assets) {
GameSound gameSound = new GameSound(app, a, getSoundVolume() * getMainVolume());
gameSound.play();
for (SoundAssetDelayVolume sawd : assets) {
GameSound gameSound = new GameSound(app, sawd.asset(), getSoundVolumeTotal(), sawd.subVolume(), sawd.delay());
sounds.add(gameSound);
}
}
@@ -105,6 +91,7 @@ public void playState(MdgaState state) {
case GAME:
addGameTracks();
playGame = true;
assert(gameTracks.size() > 0) : "no more game music available";
asset = gameTracks.remove(0);
break;
case CEREMONY:
@@ -115,7 +102,7 @@ public void playState(MdgaState state) {
assert(null != asset) : "music sceduling went wrong";
scheduled = new GameMusic(app, asset, getMusicVolume() * getMainVolume(), asset.getLoop());
scheduled = new GameMusic(app, asset, getMusicVolumeTotal(), asset.getSubVolume(), asset.getLoop());
}
private float lerp(float start, float end, float t) {
@@ -126,7 +113,6 @@ private void updateVolumeAndTrack() {
if (playing == null && scheduled != null && !fading) {
playing = scheduled;
scheduled = null;
fadeVolume = 1.0f;
playing.play();
return;
}
@@ -143,7 +129,7 @@ private void updateVolumeAndTrack() {
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);
playing.update(getMusicVolumeTotal()* oldVolume);
}
}
@@ -154,7 +140,7 @@ private void updateVolumeAndTrack() {
if (!scheduled.isPlaying()) {
scheduled.play();
}
scheduled.update(getMusicVolume() * getMainVolume() * newVolume);
scheduled.update(getMusicVolumeTotal() * newVolume);
}
if (time > FADE_DURATION + CROSSFADE_DURATION) {
@@ -164,15 +150,16 @@ private void updateVolumeAndTrack() {
playing = scheduled;
scheduled = null;
fadeVolume = 1.0f;
fading = false;
}
} else if (playing != null) {
playing.update(getMusicVolume() * getMainVolume());
playing.update(getMusicVolumeTotal());
}
}
private void addGameTracks() {
Random random = new Random();
for (int i = 1; i <= 6; i++) {
gameTracks.add(MusicAsset.valueOf("GAME_" + i));
}
@@ -189,7 +176,30 @@ private void updateGameTracks() {
MusicAsset nextTrack = gameTracks.remove(0);
scheduled = new GameMusic(app, nextTrack, getMusicVolume() * getMainVolume(), nextTrack.getLoop());
scheduled = new GameMusic(app, nextTrack, getMusicVolumeTotal(), nextTrack.getSubVolume(), nextTrack.getLoop());
}
}
public float getMainVolume() {
return mainVolume;
}
public float getMusicVolume() {
return musicVolume;
}
public float getSoundVolume() {
return soundVolume;
}
public float getMusicVolumeTotal() {
return getMusicVolume() * getMainVolume();
}
public float getSoundVolumeTotal() {
return getSoundVolume() * getMainVolume();
}
}

View File

@@ -5,17 +5,20 @@
import com.jme3.audio.AudioSource;
import pp.mdga.client.MdgaApp;
public class GameMusic {
private final MdgaApp app;
class GameMusic {
private float volume;
private AudioNode music;
private final float subVolume;
GameMusic(MdgaApp app, MusicAsset asset, float volume, boolean loop) {
this.app = app;
private final AudioNode music;
GameMusic(MdgaApp app, MusicAsset asset, float volume, float subVolume, boolean loop) {
this.volume = volume;
this.subVolume = subVolume;
loadMusic(asset.getPath());
music = new AudioNode(app.getAssetManager(), asset.getPath(), AudioData.DataType.Stream);
music.setPositional(false);
music.setDirectional(false);
music.setVolume(volume * subVolume);
music.setLooping(loop);
}
@@ -36,15 +39,8 @@ void pause() {
music.stop();
}
void reset() {
if(null == music) {
return;
}
music.setTimeOffset(0);
}
boolean isPlaying() {
return music.getStatus() == AudioSource.Status.Playing;
}
@@ -68,14 +64,7 @@ boolean nearEnd(float thresholdSeconds) {
void update(float newVolume) {
if(volume != newVolume) {
volume = newVolume;
music.setVolume(volume);
music.setVolume(volume * subVolume);
}
}
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

@@ -3,37 +3,56 @@
import com.jme3.audio.AudioData;
import com.jme3.audio.AudioNode;
import com.jme3.audio.AudioSource;
import com.jme3.system.NanoTimer;
import pp.mdga.client.MdgaApp;
public class GameSound {
private final MdgaApp app;
class GameSound {
private float volume;
private SoundAsset asset;
final private float subVolume;
private AudioNode sound;
private final AudioNode sound;
GameSound(MdgaApp app, SoundAsset asset, float volume) {
this.app = app;
private boolean playing = false;
private boolean finished = false;
private float delay = 0.0f;
private NanoTimer timer = null;
GameSound(MdgaApp app, SoundAsset asset, float volume, float subVolume, float delay) {
this.volume = volume;
this.subVolume = subVolume;
this.delay = delay;
loadMusic(asset.getPath());
}
void play() {
sound.play();
}
boolean isPlaying() {
return sound != null && sound.getStatus() == AudioSource.Status.Playing;
}
private void loadMusic(String path) {
sound = new AudioNode(app.getAssetManager(), path, AudioData.DataType.Buffer);
sound.setVolume(volume);
sound = new AudioNode(app.getAssetManager(), asset.getPath(), AudioData.DataType.Buffer);
sound.setPositional(false);
sound.setDirectional(false);
sound.setLooping(false);
sound.setVolume(volume * subVolume);
timer = new NanoTimer();
}
boolean isPlaying() {
return !finished;
}
void update(float newVolume) {
if(!playing && timer.getTimeInSeconds() > delay) {
sound.play();
playing = true;
}
if(!playing) {
return;
}
if(volume != newVolume) {
volume = newVolume;
sound.setVolume(volume * subVolume);
}
if(sound != null && sound.getStatus() == AudioSource.Status.Playing) {
finished = true;
}
}
}

View File

@@ -1,6 +1,6 @@
package pp.mdga.client.Acoustic;
public enum Sound {
public enum MdgaSound {
DICE_ROLL,
TURN_START,
TURN_END,

View File

@@ -1,32 +1,41 @@
package pp.mdga.client.Acoustic;
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);
MAIN_MENU("Spaceship.wav", 1.0f),
LOBBY("DeadPlanet.wav", 1.0f),
CEREMONY("80s,Disco,Life.wav", 1.0f),
GAME_1("NeonRoadTrip.wav", false, 1.0f),
GAME_2("NoPressureTrance.wav", false, 1.0f),
GAME_3("TheSynthRave.wav", false, 1.0f),
GAME_4("LaserParty.wav", false, 1.0f),
GAME_5("RetroNoir.wav", false, 1.0f),
GAME_6("SpaceInvaders.wav", false, 1.0f);
private final String path;
private final boolean loop;
private final float subVolume;
MusicAsset(String name) {
MusicAsset(String name, float subVolume) {
this.path = "music/" + name;
this.loop = false;
this.subVolume = subVolume;
}
MusicAsset(String name, boolean loop) {
MusicAsset(String name, boolean loop, float subVolume) {
this.path = "music/" + name;
this.loop = loop;
this.subVolume = subVolume;
}
public String getPath() {
return path;
}
public boolean getLoop() { return loop; }
public boolean getLoop() {
return loop;
}
public float getSubVolume() {
return subVolume;
}
}

View File

@@ -0,0 +1,4 @@
package pp.mdga.client.Acoustic;
record SoundAssetDelayVolume(SoundAsset asset, float subVolume, float delay) {
}

View File

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

View File

@@ -1,9 +1,13 @@
package pp.mdga.client.Board;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Spatial;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import pp.mdga.client.MdgaApp;
import java.util.ArrayList;
@@ -14,7 +18,7 @@ public class BoardView {
private static final float GRID_ELEVATION = 0.0f;
private static final String MAP_NAME = "circle_map.mdga";
private final MdgaApp mdgaApp;
private final MdgaApp app;
private PileControl drawPile = new PileControl();
private PileControl discardPile = new PileControl();
@@ -22,23 +26,45 @@ public class BoardView {
private ArrayList<NodeControl> infield = new ArrayList<NodeControl>(40);
private ArrayList<PieceControl> pieces;
public BoardView(MdgaApp mdgaApp) {
assert(mdgaApp != null) : "app is null";
public BoardView(MdgaApp app) {
assert(app != null) : "app is null";
this.mdgaApp = mdgaApp;
this.app = app;
pieces = new ArrayList<PieceControl>(4 * 4);
initMap();
initCamera();
}
private void initCamera() {
app.getFlyByCamera().setEnabled(true);
int zoom = 20;
app.getCamera().setLocation(new Vector3f(zoom,0,zoom));
app.getCamera().lookAt(new Vector3f(0,0,0), new Vector3f(0,0,1));
DirectionalLight sun = new DirectionalLight();
sun.setColor(ColorRGBA.White);
sun.setDirection(new Vector3f(-1,0,-1));
app.getRootNode().addLight(sun);
AmbientLight ambient = new AmbientLight();
ambient.setColor(new ColorRGBA(0.3f,0.3f,0.3f,1));
app.getRootNode().addLight(ambient);
final int SHADOWMAP_SIZE= 1024 * 8;
DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(app.getAssetManager(), SHADOWMAP_SIZE, 4);
dlsr.setLight(sun);
app.getViewPort().addProcessor(dlsr);
}
private void initMap() {
List<AssetOnMap> assetOnMaps = new MapLoader().loadMap(MAP_NAME);
List<AssetOnMap> assetsOnMap = MapLoader.loadMap(MAP_NAME);
for (AssetOnMap assetOnMap : assetOnMaps){
int x = assetOnMap.x();
int y = assetOnMap.y();
Spatial model = createModel(assetOnMap.asset());
for (AssetOnMap aom : assetsOnMap){
int x = aom.x();
int y = aom.y();
Spatial model = createModel(aom.asset());
model.setLocalTranslation(gridToWorld(x,y));
}
}
@@ -46,14 +72,14 @@ private void initMap() {
private Spatial createModel(Asset asset){
String modelName = asset.getModelPath();
String texName = asset.getDiffPath();
Spatial model = mdgaApp.getAssetManager().loadModel(modelName);
Spatial model = app.getAssetManager().loadModel(modelName);
model.scale(asset.getSize());
model.rotate((float) Math.toRadians(0), 0, (float) Math.toRadians(90));
model.setShadowMode(RenderQueue.ShadowMode.CastAndReceive);
Material mat = new Material(mdgaApp.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", mdgaApp.getAssetManager().loadTexture(texName));
Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Light/Lighting.j3md");
mat.setTexture("DiffuseMap", app.getAssetManager().loadTexture(texName));
model.setMaterial(mat);
mdgaApp.getRootNode().attachChild(model);
app.getRootNode().attachChild(model);
return model;
}

View File

@@ -8,13 +8,10 @@
import java.util.List;
public class MapLoader {
public MapLoader(){
}
public List<AssetOnMap> loadMap(String mapName) {
static public List<AssetOnMap> loadMap(String mapName) {
List<AssetOnMap> assetsOnMap = new ArrayList<>();
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(mapName);
try (InputStream inputStream = ClassLoader.getSystemClassLoader().getResourceAsStream(mapName);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
while (true) {
@@ -40,16 +37,14 @@ public List<AssetOnMap> loadMap(String mapName) {
Asset asset = getLoadedAsset(assetName);
assetsOnMap.add(new AssetOnMap(asset, x, y));
}
} catch (IOException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
} catch (Exception e) {
e.printStackTrace();
}
return assetsOnMap;
}
private Asset getLoadedAsset(String assetName) {
static private Asset getLoadedAsset(String assetName) {
return switch(assetName){
case "node" -> Asset.node_normal;
case "node_start" -> Asset.node_start;
@@ -59,7 +54,14 @@ private Asset getLoadedAsset(String assetName) {
case "node_home_black" -> Asset.node_home_black;
case "node_home_green" -> Asset.node_home_green;
case "world" -> Asset.world;
default -> throw new IllegalStateException("Unexpected value: " + assetName);
case "tent_big" -> Asset.bigTent;
case "tent_small" -> Asset.smallTent;
case "stack" -> Asset.cardStack;
case "jet" -> Asset.jet;
case "radar" -> Asset.radar;
case "ship" -> Asset.ship;
case "tank" -> Asset.tank;
default -> throw new IllegalStateException("Unexpected asset in .mdga file: " + assetName);
};
}
}

View File

@@ -3,25 +3,12 @@
import com.jme3.app.SimpleApplication;
import com.jme3.system.NanoTimer;
import pp.mdga.client.Acoustic.AcousticHandler;
import pp.mdga.client.Acoustic.Sound;
import pp.mdga.client.Acoustic.MdgaSound;
import pp.mdga.client.Animation.AnimationHandler;
import com.jme3.light.AmbientLight;
import com.jme3.light.DirectionalLight;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.renderer.queue.RenderQueue;
import com.jme3.scene.Spatial;
import com.jme3.shadow.DirectionalLightShadowRenderer;
import com.jme3.system.AppSettings;
import pp.mdga.client.Board.Asset;
import pp.mdga.client.Board.AssetOnMap;
import pp.mdga.client.Board.BoardView;
import pp.mdga.client.Board.MapLoader;
import pp.mdga.client.Dialog.DialogView;
import java.util.List;
public class MdgaApp extends SimpleApplication {
private AnimationHandler animationHandler;
private AcousticHandler acousticHandler;
@@ -54,27 +41,8 @@ public void simpleInitApp() {
//dialogView.mainMenu();
//acousticHandler.playState(MdgaState.GAME);
acousticHandler.playSound(Sound.LOST);
acousticHandler.playSound(Sound.VICTORY);
flyCam.setEnabled(true);
int zoom = 20;
cam.setLocation(new Vector3f(zoom,0,zoom));
cam.lookAt(new Vector3f(0,0,0), new Vector3f(0,0,1));
DirectionalLight sun = new DirectionalLight();
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;
DirectionalLightShadowRenderer dlsr = new DirectionalLightShadowRenderer(assetManager, SHADOWMAP_SIZE, 4);
dlsr.setLight(sun);
viewPort.addProcessor(dlsr);
acousticHandler.playSound(MdgaSound.LOST);
acousticHandler.playSound(MdgaSound.VICTORY);
}
@Override