From 20cbc3a21cfc7897d08e778b8497cc94ff8e2a51 Mon Sep 17 00:00:00 2001 From: "Zed A. Shaw" Date: Sat, 22 Feb 2025 12:48:37 -0500 Subject: [PATCH] Working sound system and most enemies have a sound effect. This will make it easier to add sounds now. --- assets/config.json | 5 ++++ assets/enemies.json | 15 ++++++++---- assets/monster-16.ogg | Bin 0 -> 11383 bytes assets/sword.1.ogg | Bin 0 -> 17794 bytes components.cpp | 2 ++ components.hpp | 5 ++++ main.cpp | 2 ++ meson.build | 2 ++ sound.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++ sound.hpp | 22 +++++++++++++++++ systems.cpp | 9 +++++++ tests/sound.cpp | 15 ++++++++++++ 12 files changed, 126 insertions(+), 5 deletions(-) create mode 100644 assets/monster-16.ogg create mode 100644 assets/sword.1.ogg create mode 100644 sound.cpp create mode 100644 sound.hpp create mode 100644 tests/sound.cpp diff --git a/assets/config.json b/assets/config.json index 90d30b7..5cb049b 100644 --- a/assets/config.json +++ b/assets/config.json @@ -1,4 +1,9 @@ { + "sounds": { + "sword_1": "assets/sword.1.ogg", + "monster_16": "assets/monster-16.ogg", + "monster_1": "assets/monster-1.ogg" + }, "sprites": { "armored_knight": "assets/armored_knight_1-256.png", "sword": "assets/cinqueda_1-512.png", diff --git a/assets/enemies.json b/assets/enemies.json index 9238eae..bf48e8c 100644 --- a/assets/enemies.json +++ b/assets/enemies.json @@ -23,7 +23,8 @@ {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "Animation", "scale": 0.2, "simple": true, "frames": 10, "speed": 0.3}, - {"_type": "Sprite", "name": "armored_knight"} + {"_type": "Sprite", "name": "armored_knight"}, + {"_type": "Sound", "attack": "monster_1", "death": "monster_16"} ] }, "AXE_RANGER": { @@ -36,7 +37,8 @@ {"_type": "Motion", "dx": 0, "dy": 0, "random": true}, {"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "Sprite", "name": "axe_ranger"}, - {"_type": "Animation", "scale": 0.2, "simple": false, "frames": 10, "speed": 0.6} + {"_type": "Animation", "scale": 0.2, "simple": false, "frames": 10, "speed": 0.6}, + {"_type": "Sound", "attack": "sword_1", "death": "monster_16"} ] }, "EVIL_EYE": { @@ -49,7 +51,8 @@ {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 5}, {"_type": "Sprite", "name": "evil_eye"}, - {"_type": "Animation", "scale": 0.2, "simple": false, "frames": 10, "speed": 0.3} + {"_type": "Animation", "scale": 0.2, "simple": false, "frames": 10, "speed": 0.3}, + {"_type": "Sound", "attack": "monster_1", "death": "monster_16"} ] }, "RAT_GIANT": { @@ -62,7 +65,8 @@ {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 10}, {"_type": "Animation", "scale": 0.2, "simple": true, "frames": 10, "speed": 1.0}, - {"_type": "Sprite", "name": "rat_with_sword"} + {"_type": "Sprite", "name": "rat_with_sword"}, + {"_type": "Sound", "attack": "sword_1", "death": "monster_16"} ] }, "SPIDER_GIANT_HAIRY": { @@ -75,7 +79,8 @@ {"_type": "Motion", "dx": 0, "dy": 0, "random": false}, {"_type": "EnemyConfig", "hearing_distance": 10}, {"_type": "Animation", "scale": 0.2, "simple": true, "frames": 10, "speed": 1.0}, - {"_type": "Sprite", "name": "hairy_spider"} + {"_type": "Sprite", "name": "hairy_spider"}, + {"_type": "Sound", "attack": "sword_1", "death": "monster_16"} ] } } diff --git a/assets/monster-16.ogg b/assets/monster-16.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e723c3ce5a5fe2007c61f2909980b4c68453c297 GIT binary patch literal 11383 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 literal 0 HcmV?d00001 diff --git a/components.cpp b/components.cpp index 446f8fb..b5bde3b 100644 --- a/components.cpp +++ b/components.cpp @@ -13,6 +13,7 @@ namespace components { ENROLL_COMPONENT(Device, config, events); ENROLL_COMPONENT(Sprite, name); ENROLL_COMPONENT(Animation, scale, simple, frames, speed); + ENROLL_COMPONENT(Sound, attack, death); void configure_entity(const ComponentMap& component_map, DinkyECS::World& world, DinkyECS::Entity ent, json& data) { for (auto &i : data) { @@ -35,6 +36,7 @@ namespace components { components::enroll(component_map); components::enroll(component_map); components::enroll(component_map); + components::enroll(component_map); } void Animation::play() { diff --git a/components.hpp b/components.hpp index f93cb53..cdbc2b9 100644 --- a/components.hpp +++ b/components.hpp @@ -86,6 +86,11 @@ namespace components { string name; }; + struct Sound { + std::string attack; + std::string death; + }; + struct Animation { float scale = 0.0f; bool simple = true; diff --git a/main.cpp b/main.cpp index 9ff9d67..316fc5b 100644 --- a/main.cpp +++ b/main.cpp @@ -1,8 +1,10 @@ #include "gui_fsm.hpp" #include "textures.hpp" +#include "sound.hpp" int main() { textures::init(); + sound::init(); gui::FSM main; main.event(gui::Event::STARTED); diff --git a/meson.build b/meson.build index 9733cbb..c908058 100644 --- a/meson.build +++ b/meson.build @@ -79,6 +79,7 @@ sources = [ 'render.cpp', 'save.cpp', 'shiterator.hpp', + 'sound.cpp', 'spatialmap.cpp', 'stats.cpp', 'status_ui.cpp', @@ -104,6 +105,7 @@ executable('runtests', sources + [ 'tests/map.cpp', 'tests/matrix.cpp', 'tests/pathing.cpp', + 'tests/sound.cpp', 'tests/spatialmap.cpp', 'tests/textures.cpp', 'tests/tilemap.cpp', diff --git a/sound.cpp b/sound.cpp new file mode 100644 index 0000000..d278ec3 --- /dev/null +++ b/sound.cpp @@ -0,0 +1,54 @@ +#include "sound.hpp" +#include "dbc.hpp" +#include +#include "config.hpp" + +namespace sound { + static SoundManager SMGR; + static bool initialized = false; + + using namespace fmt; + using std::make_shared; + namespace fs = std::filesystem; + + void init() { + if(!initialized) { + Config assets("assets/config.json"); + + for(auto& el : assets["sounds"].items()) { + load(el.key(), el.value()); + } + initialized = true; + } + } + + void load(const std::string name, const std::string sound_path) { + dbc::check(fs::exists(sound_path), fmt::format("sound file {} does not exist", sound_path)); + + // create the buffer and keep in the buffer map + auto buffer = make_shared(sound_path); + + // set it on the sound and keep in the sound map + auto sound = make_shared(*buffer); + sound->setRelativeToListener(false); + sound->setPosition({0.0f, 0.0f, 1.0f}); + + SMGR.sounds.try_emplace(name, buffer, sound); + } + + void play(const std::string name) { + dbc::check(initialized, "You need to call sound::init() first"); + dbc::check(SMGR.sounds.contains(name), fmt::format("sound {} is not loaded in map", name)); + // get the sound from the sound map + auto pair = SMGR.sounds.at(name); + // play it + pair.sound->play(); + } + + void play_at(const std::string name, float x, float y, float z) { + dbc::check(initialized, "You need to call sound::init() first"); + auto pair = SMGR.sounds.at(name); + pair.sound->setPosition({x, y, z}); + pair.sound->play(); + } +} diff --git a/sound.hpp b/sound.hpp new file mode 100644 index 0000000..720a5cc --- /dev/null +++ b/sound.hpp @@ -0,0 +1,22 @@ +#pragma once +#include +#include +#include +#include +#include + +namespace sound { + struct SoundPair { + std::shared_ptr buffer; + std::shared_ptr sound; + }; + + struct SoundManager { + std::unordered_map sounds; + }; + + void init(); + void load(const std::string name, const std::string path); + void play(const std::string name); + void play_at(const std::string name, float x, float y, float z); +} diff --git a/systems.cpp b/systems.cpp index 12c0cf8..b43b6c4 100644 --- a/systems.cpp +++ b/systems.cpp @@ -8,6 +8,7 @@ #include "lights.hpp" #include "inventory.hpp" #include "events.hpp" +#include "sound.hpp" using std::string; using namespace fmt; @@ -133,6 +134,10 @@ void System::death(GameLevel &level, components::ComponentMap& components) { world.remove(ent); world.remove(ent); + if(auto snd = world.get_if(ent)) { + sound::play(snd->death); + } + auto entity_data = config.items["GRAVE_STONE"]; components::configure_entity(components, world, ent, entity_data["components"]); if(entity_data["inventory_count"] > 0) { @@ -167,6 +172,10 @@ void System::combat(GameLevel &level) { animation.play(); } + if(auto snd = world.get_if(entity)) { + sound::play(snd->attack); + } + world.send(Events::GUI::COMBAT, entity, result); } } diff --git a/tests/sound.cpp b/tests/sound.cpp new file mode 100644 index 0000000..8279141 --- /dev/null +++ b/tests/sound.cpp @@ -0,0 +1,15 @@ +#include +#include +#include +#include "sound.hpp" +#include "levelmanager.hpp" + +using namespace fmt; + +TEST_CASE("test sound manager", "[sound]") { + sound::init(); + + sound::play("sword_1"); + + sound::play_at("sword_1", 0.1, 0.1, 0.1); +}