From 95e1e52205aea0753c8230c49525293c586456f5 Mon Sep 17 00:00:00 2001 From: jzitnik-dev Date: Wed, 26 Mar 2025 18:11:00 +0100 Subject: [PATCH] feat(sounds): Added simple sounds --- src/main/java/cz/jzitnik/game/Game.java | 13 +++++ .../jzitnik/game/annotations/MineSound.java | 15 ++++++ .../game/annotations/SoundRegistry.java | 18 +++++++ .../cz/jzitnik/game/config/Configuration.java | 10 ++++ .../cz/jzitnik/game/core/sound/Sound.java | 50 +++++++++++++++++++ .../cz/jzitnik/game/core/sound/SoundKey.java | 5 ++ .../cz/jzitnik/game/core/sound/SoundType.java | 5 ++ .../core/sound/registry/DirtMineSound.java | 9 ++++ .../jzitnik/game/entities/Dependencies.java | 2 + .../registry/blocks/blocks/DirtBlock.java | 3 ++ src/main/java/cz/jzitnik/tui/SoundPlayer.java | 32 ++++++++++++ 11 files changed, 162 insertions(+) create mode 100644 src/main/java/cz/jzitnik/game/annotations/MineSound.java create mode 100644 src/main/java/cz/jzitnik/game/annotations/SoundRegistry.java create mode 100644 src/main/java/cz/jzitnik/game/config/Configuration.java create mode 100644 src/main/java/cz/jzitnik/game/core/sound/Sound.java create mode 100644 src/main/java/cz/jzitnik/game/core/sound/SoundKey.java create mode 100644 src/main/java/cz/jzitnik/game/core/sound/SoundType.java create mode 100644 src/main/java/cz/jzitnik/game/core/sound/registry/DirtMineSound.java create mode 100644 src/main/java/cz/jzitnik/tui/SoundPlayer.java diff --git a/src/main/java/cz/jzitnik/game/Game.java b/src/main/java/cz/jzitnik/game/Game.java index 39f14f4..2def062 100644 --- a/src/main/java/cz/jzitnik/game/Game.java +++ b/src/main/java/cz/jzitnik/game/Game.java @@ -13,8 +13,10 @@ import cz.jzitnik.game.sprites.Breaking; import cz.jzitnik.game.sprites.Steve.SteveState; import cz.jzitnik.game.annotations.AutoTransient; import cz.jzitnik.game.annotations.BreaksByPlace; +import cz.jzitnik.game.annotations.MineSound; import cz.jzitnik.game.blocks.Chest; import cz.jzitnik.game.blocks.Furnace; +import cz.jzitnik.game.config.Configuration; import cz.jzitnik.game.core.autotransient.AutoTransientSupport; import cz.jzitnik.game.core.autotransient.initilizers.GameMiningInitializer; import cz.jzitnik.game.core.autotransient.initilizers.GameWindowInitializer; @@ -48,6 +50,7 @@ public class Game extends AutoTransientSupport { private transient GameStates gameStates = new GameStates(this); @Setter private int daytime = 0; // 0-600 + private Configuration configuration = new Configuration(); public Game() { Generation.generateWorld(this); @@ -272,6 +275,16 @@ public class Game extends AutoTransientSupport { gameStates.dependencies.eventHandlerProvider.handleMine(screenRenderer, this, x, y); + for (Block block : blocksCopy) { + if (block.getClass().isAnnotationPresent(MineSound.class)) { + var key = block.getClass().getAnnotation(MineSound.class).value(); + + new Thread(() -> { + gameStates.dependencies.sound.playSound(configuration, key); + }).start(); + } + } + screenRenderer.render(this); update(screenRenderer); diff --git a/src/main/java/cz/jzitnik/game/annotations/MineSound.java b/src/main/java/cz/jzitnik/game/annotations/MineSound.java new file mode 100644 index 0000000..b359716 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/annotations/MineSound.java @@ -0,0 +1,15 @@ +package cz.jzitnik.game.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import cz.jzitnik.game.core.sound.SoundKey; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@RequireAnnotation(BlockRegistry.class) +public @interface MineSound { + SoundKey value(); +} diff --git a/src/main/java/cz/jzitnik/game/annotations/SoundRegistry.java b/src/main/java/cz/jzitnik/game/annotations/SoundRegistry.java new file mode 100644 index 0000000..9ff46af --- /dev/null +++ b/src/main/java/cz/jzitnik/game/annotations/SoundRegistry.java @@ -0,0 +1,18 @@ +package cz.jzitnik.game.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import cz.jzitnik.game.core.sound.SoundKey; +import cz.jzitnik.game.core.sound.SoundType; + +import java.lang.annotation.ElementType; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface SoundRegistry { + SoundKey key(); + SoundType type(); + String resourceLocation(); +} diff --git a/src/main/java/cz/jzitnik/game/config/Configuration.java b/src/main/java/cz/jzitnik/game/config/Configuration.java new file mode 100644 index 0000000..dfca34c --- /dev/null +++ b/src/main/java/cz/jzitnik/game/config/Configuration.java @@ -0,0 +1,10 @@ +package cz.jzitnik.game.config; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class Configuration { + private int soundVolume = 100; // 0-100 +} diff --git a/src/main/java/cz/jzitnik/game/core/sound/Sound.java b/src/main/java/cz/jzitnik/game/core/sound/Sound.java new file mode 100644 index 0000000..dc159be --- /dev/null +++ b/src/main/java/cz/jzitnik/game/core/sound/Sound.java @@ -0,0 +1,50 @@ +package cz.jzitnik.game.core.sound; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Set; + +import javax.sound.sampled.Clip; +import javax.sound.sampled.LineUnavailableException; +import javax.sound.sampled.UnsupportedAudioFileException; + +import org.reflections.Reflections; + +import cz.jzitnik.game.annotations.SoundRegistry; +import cz.jzitnik.game.config.Configuration; +import cz.jzitnik.tui.SoundPlayer; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class Sound { + private HashMap map = new HashMap<>(); + + public Sound() { + register(); + } + + private void register() { + Reflections reflections = new Reflections("cz.jzitnik.game.core.sound.registry"); + Set> handlerClasses = reflections.getTypesAnnotatedWith(SoundRegistry.class); + + for (Class clazz : handlerClasses) { + log.info("Loaded sound {}", clazz.getSimpleName()); + var annotation = clazz.getAnnotation(SoundRegistry.class); + + map.put(annotation.key(), annotation); + } + } + + public void playSound(Configuration configuration, SoundKey soundKey) { + var volume = configuration.getSoundVolume(); + + var annotation = map.get(soundKey); + + try { + Clip clip = SoundPlayer.playSound(annotation.resourceLocation(), volume); + } catch (LineUnavailableException | IOException | UnsupportedAudioFileException | InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} diff --git a/src/main/java/cz/jzitnik/game/core/sound/SoundKey.java b/src/main/java/cz/jzitnik/game/core/sound/SoundKey.java new file mode 100644 index 0000000..0ee3e6a --- /dev/null +++ b/src/main/java/cz/jzitnik/game/core/sound/SoundKey.java @@ -0,0 +1,5 @@ +package cz.jzitnik.game.core.sound; + +public enum SoundKey { + DIRT_MINE +} diff --git a/src/main/java/cz/jzitnik/game/core/sound/SoundType.java b/src/main/java/cz/jzitnik/game/core/sound/SoundType.java new file mode 100644 index 0000000..66d4077 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/core/sound/SoundType.java @@ -0,0 +1,5 @@ +package cz.jzitnik.game.core.sound; + +public enum SoundType { + BLOCK +} diff --git a/src/main/java/cz/jzitnik/game/core/sound/registry/DirtMineSound.java b/src/main/java/cz/jzitnik/game/core/sound/registry/DirtMineSound.java new file mode 100644 index 0000000..fd22b45 --- /dev/null +++ b/src/main/java/cz/jzitnik/game/core/sound/registry/DirtMineSound.java @@ -0,0 +1,9 @@ +package cz.jzitnik.game.core.sound.registry; + +import cz.jzitnik.game.annotations.SoundRegistry; +import cz.jzitnik.game.core.sound.SoundKey; +import cz.jzitnik.game.core.sound.SoundType; + +@SoundRegistry(key = SoundKey.DIRT_MINE, resourceLocation = "dirt_mine.wav", type = SoundType.BLOCK) +public class DirtMineSound { +} diff --git a/src/main/java/cz/jzitnik/game/entities/Dependencies.java b/src/main/java/cz/jzitnik/game/entities/Dependencies.java index 4391c66..0f15ec3 100644 --- a/src/main/java/cz/jzitnik/game/entities/Dependencies.java +++ b/src/main/java/cz/jzitnik/game/entities/Dependencies.java @@ -1,6 +1,7 @@ package cz.jzitnik.game.entities; import cz.jzitnik.game.GameSaver; +import cz.jzitnik.game.core.sound.Sound; import cz.jzitnik.game.handlers.events.EventHandlerProvider; import cz.jzitnik.game.handlers.pickup.PickupHandlerProvider; import cz.jzitnik.game.handlers.place.PlaceHandler; @@ -18,4 +19,5 @@ public class Dependencies { public EventHandlerProvider eventHandlerProvider = new EventHandlerProvider(); public Smelting smelting = new Smelting(); public ToolUseProvider toolUseProvider = new ToolUseProvider(); + public Sound sound = new Sound(); } diff --git a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/blocks/DirtBlock.java b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/blocks/DirtBlock.java index 9b04789..e137f2f 100644 --- a/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/blocks/DirtBlock.java +++ b/src/main/java/cz/jzitnik/game/entities/items/registry/blocks/blocks/DirtBlock.java @@ -2,13 +2,16 @@ package cz.jzitnik.game.entities.items.registry.blocks.blocks; import cz.jzitnik.game.SpriteLoader; import cz.jzitnik.game.annotations.BlockRegistry; +import cz.jzitnik.game.annotations.MineSound; import cz.jzitnik.game.annotations.ResetDataOnMine; +import cz.jzitnik.game.core.sound.SoundKey; import cz.jzitnik.game.entities.Block; import cz.jzitnik.game.entities.items.ItemType; import cz.jzitnik.game.logic.services.grass.GrassDirtData; import java.util.ArrayList; +@MineSound(SoundKey.DIRT_MINE) @ResetDataOnMine @BlockRegistry("dirt") public class DirtBlock extends Block { diff --git a/src/main/java/cz/jzitnik/tui/SoundPlayer.java b/src/main/java/cz/jzitnik/tui/SoundPlayer.java new file mode 100644 index 0000000..adb77c7 --- /dev/null +++ b/src/main/java/cz/jzitnik/tui/SoundPlayer.java @@ -0,0 +1,32 @@ +package cz.jzitnik.tui; + +import javax.sound.sampled.*; + +import lombok.extern.slf4j.Slf4j; + +import java.io.IOException; + +@Slf4j +public class SoundPlayer { + public static Clip playSound(String filePath, int volume) + throws LineUnavailableException, IOException, UnsupportedAudioFileException, InterruptedException { + log.info("Loading resource: {}", "sounds/" + filePath); + var soundFile = SoundPlayer.class.getClassLoader().getResourceAsStream("sounds/" + filePath); + AudioInputStream audioStream = AudioSystem.getAudioInputStream(soundFile); + Clip clip = AudioSystem.getClip(); + clip.open(audioStream); + + FloatControl volumeControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN); + float min = volumeControl.getMinimum(); + float max = volumeControl.getMaximum(); + float gain = min + (max - min) * (volume / 100.0f); + volumeControl.setValue(gain); + + log.info("Starting to play {}", filePath); + clip.start(); + + // Thread.sleep(clip.getMicrosecondLength() / 1000); + + return clip; + } +}