diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/AcousticHandler.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/AcousticHandler.java index 5160d2ae..dd5dbc70 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/AcousticHandler.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/AcousticHandler.java @@ -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 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 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 iterator = sounds.iterator(); while (iterator.hasNext()) { GameSound s = iterator.next(); + + s.update(getSoundVolumeTotal()); + if (!s.isPlaying()) { iterator.remove(); } } } - public void playSound(Sound sound) { - ArrayList assets = new ArrayList(); + public void playSound(MdgaSound sound) { + ArrayList assets = new ArrayList(); 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(); + } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/GameMusic.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/GameMusic.java index eb04bbb2..fcec1842 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/GameMusic.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/GameMusic.java @@ -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); - } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/GameSound.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/GameSound.java index 1a6083a3..a3148726 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/GameSound.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/GameSound.java @@ -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; + } } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/Sound.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/MdgaSound.java similarity index 88% rename from Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/Sound.java rename to Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/MdgaSound.java index 1db39770..7d6cad91 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/Sound.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/MdgaSound.java @@ -1,6 +1,6 @@ package pp.mdga.client.Acoustic; -public enum Sound { +public enum MdgaSound { DICE_ROLL, TURN_START, TURN_END, diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/MusicAsset.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/MusicAsset.java index c1a100fc..4e15b53e 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/MusicAsset.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/MusicAsset.java @@ -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; + } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/SoundAssetDelayVolume.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/SoundAssetDelayVolume.java new file mode 100644 index 00000000..c0b7fa59 --- /dev/null +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Acoustic/SoundAssetDelayVolume.java @@ -0,0 +1,4 @@ +package pp.mdga.client.Acoustic; + +record SoundAssetDelayVolume(SoundAsset asset, float subVolume, float delay) { +} diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/BoardCamera.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/BoardCamera.java deleted file mode 100644 index 61fe3fa4..00000000 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/BoardCamera.java +++ /dev/null @@ -1,4 +0,0 @@ -package pp.mdga.client.Board; - -public class BoardCamera { -} diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/BoardView.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/BoardView.java index 3cbc46fc..edd27466 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/BoardView.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/BoardView.java @@ -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 infield = new ArrayList(40); private ArrayList 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(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 assetOnMaps = new MapLoader().loadMap(MAP_NAME); + List 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; } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/MapLoader.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/MapLoader.java index 0b07bcd0..ffa38da5 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/MapLoader.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/Board/MapLoader.java @@ -8,13 +8,10 @@ import java.util.List; public class MapLoader { - public MapLoader(){ - - } - public List loadMap(String mapName) { + static public List loadMap(String mapName) { List 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 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); }; } } diff --git a/Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java b/Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java index d4f2ce06..b4b9e2bf 100644 --- a/Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java +++ b/Projekte/mdga/client/src/main/java/pp/mdga/client/MdgaApp.java @@ -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