Commit fbaeac21 authored by Florian Oetke's avatar Florian Oetke
Browse files

Merge branch 'feature/16-sound-effects' into 'develop'

Resolve "Sound-Effects"

Closes #16

See merge request !19
parents 6e24ab00 4a27b29b
Pipeline #3360 passed with stage
in 8 minutes and 31 seconds
#include "sound_manager.hpp"
#include "audio_asset.hpp"
#include "../messages.hpp"
#include <mirrage/utils/random.hpp>
#include <context.hpp>
namespace phase_shifter::audio {
struct Effect_file {
std::unordered_map<std::string, std::vector<std::string>> effects;
};
sf2_structDef(Effect_file, effects);
Sound_manager::Sound_manager(eam::audio& audio,
mirrage::util::Message_bus& bus,
mirrage::asset::Asset_manager& assets)
: _audio(audio), _mailbox(bus), _assets(assets), _random_gen(mirrage::util::construct_random_engine())
{
_mailbox.subscribe_to([&](Play_sound_msg& e) { play_effect(e.id); });
}
void Sound_manager::load_effects_file(const mirrage::asset::AID& aid)
{
auto file = _assets.load<Effect_file>(aid, false);
for(auto&& [id, paths] : file.get_blocking().effects) {
for(auto&& path : paths)
register_effect(Sound_effect_id(id), mirrage::asset::AID("audio"_strid, path));
}
}
void Sound_manager::effect_volume(float v) { _effect_volume = v; }
void Sound_manager::pause()
{
// TODO
}
void Sound_manager::resume()
{
// TODO
}
void Sound_manager::update(mirrage::util::Time dt) { _mailbox.update_subscriptions(); }
void Sound_manager::register_effect(Sound_effect_id id, const mirrage::asset::AID& aid)
{
LOG(plog::info) << "Loading sound " << aid.str();
auto effect = _assets.load<std::shared_ptr<eam::opus>>(aid).get_blocking();
auto entry = _sound_effects.find(id);
if(entry != _sound_effects.end())
entry->second.raw_vector().emplace_back(std::move(effect));
else {
auto effects = Sound_effect_set();
effects.raw_vector().emplace_back(std::move(effect));
_sound_effects.emplace(id, std::move(effects));
}
}
void Sound_manager::unregister_effect(Sound_effect_id id) { _sound_effects.erase(id); }
void Sound_manager::play_effect(Sound_effect_id id)
{
auto effect = _sound_effects.find(id);
if(effect != _sound_effects.end()) {
auto ctx = _audio.generate_context(effect->second.get_random(_random_gen));
ctx.get_object()->set_loops(0);
ctx.get_object()->set_volume(_effect_volume * 100);
ctx.play();
}
}
} // namespace phase_shifter::audio
#pragma once
#include "../util/random_vector.hpp"
#include <mirrage/asset/asset_manager.hpp>
#include <mirrage/utils/messagebus.hpp>
#include <mirrage/utils/str_id.hpp>
#include <mirrage/utils/units.hpp>
#include <audio.hpp>
#include <sources/opus.hpp>
#include <memory>
#include <random>
#include <string>
#include <unordered_map>
namespace phase_shifter::audio {
using Sound_effect_id = mirrage::util::Str_id;
class Sound_manager {
public:
Sound_manager(eam::audio& audio, mirrage::util::Message_bus&, mirrage::asset::Asset_manager&);
void load_effects_file(const mirrage::asset::AID& aid);
void effect_volume(float);
auto effect_volume() const -> float { return _effect_volume; }
void pause();
void resume();
void update(mirrage::util::Time dt);
void register_effect(Sound_effect_id id, const mirrage::asset::AID& aid);
void unregister_effect(Sound_effect_id id);
void play_effect(Sound_effect_id id);
private:
using Sound_effect = std::shared_ptr<eam::opus>;
using Sound_effect_set = utils::Random_vector<Sound_effect>;
eam::audio& _audio;
mirrage::util::Mailbox_collection _mailbox;
mirrage::asset::Asset_manager& _assets;
float _effect_volume = 1.f;
std::mt19937_64 _random_gen;
std::unordered_map<Sound_effect_id, Sound_effect_set> _sound_effects;
};
} // namespace phase_shifter::audio
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
#include "beat_system.hpp" #include "beat_system.hpp"
#include "combat_system.hpp" #include "combat_system.hpp"
#include "movement_comp.hpp" #include "movement_comp.hpp"
#include "player_comp.hpp"
#include "rigid_body_comp.hpp" #include "rigid_body_comp.hpp"
#include "../level/level_system.hpp" #include "../level/level_system.hpp"
...@@ -67,12 +68,20 @@ namespace phase_shifter::gameplay { ...@@ -67,12 +68,20 @@ namespace phase_shifter::gameplay {
if(aim_len < 0.0001f) { if(aim_len < 0.0001f) {
// TODO: attack // TODO: attack
move.attack = true; move.attack = true;
if(entity.has<Player_comp>()) {
_bus.send<Play_sound_msg>("attack"_strid);
}
} else { } else {
// start movement // start movement
move.step_time_left = beat.avg_beat_time * move.step_time_percentage; move.step_time_left = beat.avg_beat_time * move.step_time_percentage;
move.step_time = move.step_time_left; move.step_time = move.step_time_left;
move.last_step = move.last_step =
(aim_len > 1.f ? move.aim / aim_len : move.aim) * move.distance_per_step; (aim_len > 1.f ? move.aim / aim_len : move.aim) * move.distance_per_step;
if(entity.has<Player_comp>()) {
_bus.send<Play_sound_msg>("dash"_strid);
}
} }
} else { } else {
......
#pragma once #pragma once
#include <mirrage/ecs/types.hpp> #include <mirrage/ecs/types.hpp>
#include <mirrage/utils/str_id.hpp>
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
...@@ -20,4 +21,8 @@ namespace phase_shifter { ...@@ -20,4 +21,8 @@ namespace phase_shifter {
glm::vec3 attack_direction; glm::vec3 attack_direction;
}; };
struct Play_sound_msg {
mirrage::util::Str_id id;
};
} // namespace phase_shifter } // namespace phase_shifter
#include "meta_system.hpp" #include "meta_system.hpp"
#include "audio/audio_asset.hpp" #include "audio/audio_asset.hpp"
#include "audio/sound_manager.hpp"
#include "game_engine.hpp" #include "game_engine.hpp"
#include "gameplay/beat_system.hpp" #include "gameplay/beat_system.hpp"
#include "gameplay/camera_system.hpp" #include "gameplay/camera_system.hpp"
#include "gameplay/combat_system.hpp" #include "gameplay/combat_system.hpp"
#include "gameplay/dash_system.hpp" #include "gameplay/dash_system.hpp"
#include "gameplay/stationary_attack_system.hpp"
#include "gameplay/enemy_system.hpp" #include "gameplay/enemy_system.hpp"
#include "gameplay/killable_comp.hpp" #include "gameplay/killable_comp.hpp"
#include "gameplay/movement_system.hpp" #include "gameplay/movement_system.hpp"
#include "gameplay/stationary_attack_system.hpp"
#include "helper/attachment_system.hpp" #include "helper/attachment_system.hpp"
#include "input/input_system.hpp" #include "input/input_system.hpp"
#include "level/level_system.hpp" #include "level/level_system.hpp"
...@@ -34,6 +35,7 @@ namespace phase_shifter { ...@@ -34,6 +35,7 @@ namespace phase_shifter {
, _audio() , _audio()
, _renderer(engine.renderer_factory().create_renderer(_entities, engine.render_pass_mask())) , _renderer(engine.renderer_factory().create_renderer(_entities, engine.render_pass_mask()))
, _model_loading(std::make_unique<renderer::Loading_system>(_entities, engine.assets())) , _model_loading(std::make_unique<renderer::Loading_system>(_entities, engine.assets()))
, _sound_manager(std::make_unique<audio::Sound_manager>(_audio, engine.bus(), engine.assets()))
, _beat_system(std::make_unique<gameplay::Beat_system>(engine.bus(), engine.assets())) , _beat_system(std::make_unique<gameplay::Beat_system>(engine.bus(), engine.assets()))
, _level_system(std::make_unique<level::Level_system>(_entities, engine.assets())) , _level_system(std::make_unique<level::Level_system>(_entities, engine.assets()))
, _movement_system(std::make_unique<gameplay::Movement_system>( , _movement_system(std::make_unique<gameplay::Movement_system>(
...@@ -45,9 +47,12 @@ namespace phase_shifter { ...@@ -45,9 +47,12 @@ namespace phase_shifter {
, _camera_system(std::make_unique<gameplay::Camera_system>(_entities)) , _camera_system(std::make_unique<gameplay::Camera_system>(_entities))
, _enemy_system(std::make_unique<gameplay::Enemy_system>(engine.bus(), _entities, *_beat_system)) , _enemy_system(std::make_unique<gameplay::Enemy_system>(engine.bus(), _entities, *_beat_system))
, _dash_system(std::make_unique<gameplay::Dash_system>(engine.bus(), _entities)) , _dash_system(std::make_unique<gameplay::Dash_system>(engine.bus(), _entities))
, _stationary_attack_system(std::make_unique<gameplay::Stationary_attack_system>(engine.bus(), _entities)) , _stationary_attack_system(
std::make_unique<gameplay::Stationary_attack_system>(engine.bus(), _entities))
, _effect_system(std::make_unique<ui::Effect_system>(engine.bus(), _entities)) , _effect_system(std::make_unique<ui::Effect_system>(engine.bus(), _entities))
{ {
_sound_manager->load_effects_file("cfg:sound_effects"_aid);
_entities.register_component_type<ecs::components::Transform_comp>(); _entities.register_component_type<ecs::components::Transform_comp>();
//auto s = _renderer->settings(); //auto s = _renderer->settings();
...@@ -130,6 +135,7 @@ namespace phase_shifter { ...@@ -130,6 +135,7 @@ namespace phase_shifter {
_model_loading->update(dt); _model_loading->update(dt);
_renderer->update(dt * _beat_system->graphic_time_scale()); _renderer->update(dt * _beat_system->graphic_time_scale());
_sound_manager->update(dt);
} }
void Meta_system::draw() void Meta_system::draw()
{ {
...@@ -138,8 +144,16 @@ namespace phase_shifter { ...@@ -138,8 +144,16 @@ namespace phase_shifter {
} }
void Meta_system::pause() { _input_system->disable(); } void Meta_system::pause()
void Meta_system::resume() { _input_system->enable(); } {
_input_system->disable();
_sound_manager->pause();
}
void Meta_system::resume()
{
_input_system->enable();
_sound_manager->resume();
}
void Meta_system::shrink_to_fit() { _renderer->shrink_to_fit(); } void Meta_system::shrink_to_fit() { _renderer->shrink_to_fit(); }
......
...@@ -19,6 +19,9 @@ namespace mirrage { ...@@ -19,6 +19,9 @@ namespace mirrage {
namespace phase_shifter { namespace phase_shifter {
class Game_engine; class Game_engine;
namespace audio {
class Sound_manager;
}
namespace gameplay { namespace gameplay {
class Beat_system; class Beat_system;
class Movement_system; class Movement_system;
...@@ -64,6 +67,7 @@ namespace phase_shifter { ...@@ -64,6 +67,7 @@ namespace phase_shifter {
eam::audio _audio; eam::audio _audio;
std::unique_ptr<mirrage::renderer::Deferred_renderer> _renderer; std::unique_ptr<mirrage::renderer::Deferred_renderer> _renderer;
std::unique_ptr<mirrage::renderer::Loading_system> _model_loading; std::unique_ptr<mirrage::renderer::Loading_system> _model_loading;
std::unique_ptr<audio::Sound_manager> _sound_manager;
std::unique_ptr<gameplay::Beat_system> _beat_system; std::unique_ptr<gameplay::Beat_system> _beat_system;
std::unique_ptr<level::Level_system> _level_system; std::unique_ptr<level::Level_system> _level_system;
......
#include "effect_system.hpp" #include "effect_system.hpp"
#include "../gameplay/combat_system.hpp"
#include "../gameplay/player_comp.hpp"
#include "../messages.hpp" #include "../messages.hpp"
#include <mirrage/ecs/entity_manager.hpp> #include <mirrage/ecs/entity_manager.hpp>
...@@ -13,6 +15,8 @@ namespace phase_shifter::ui { ...@@ -13,6 +15,8 @@ namespace phase_shifter::ui {
: _bus(bus), _mailbox(bus), _ecs(ecs) : _bus(bus), _mailbox(bus), _ecs(ecs)
{ {
_mailbox.subscribe_to([&](Enemy_killed_msg& e) { _mailbox.subscribe_to([&](Enemy_killed_msg& e) {
_bus.send<Play_sound_msg>("enemy_hit"_strid);
auto entity = _ecs.entity_builder("enemy_tombstone") auto entity = _ecs.entity_builder("enemy_tombstone")
.rotation(glm::rotation( .rotation(glm::rotation(
glm::vec3{1.f, 0.f, 0.f}, glm::vec3{1.f, 0.f, 0.f},
...@@ -20,17 +24,22 @@ namespace phase_shifter::ui { ...@@ -20,17 +24,22 @@ namespace phase_shifter::ui {
.position(e.position) .position(e.position)
.create(); .create();
_actions.defer(5_s, [&, entity] { _actions.defer(5_s, [&, entity] { _ecs.erase(entity); });
_ecs.erase(entity); });
LOG(plog::debug) << "erased";
_mailbox.subscribe_to([&](gameplay::Damaged_msg& e) {
_ecs.get(e.entity).process([&](auto& entity) {
entity.process([&](gameplay::Player_comp&) { _bus.send<Play_sound_msg>("damaged"_strid); });
}); });
}); });
_mailbox.subscribe_to([&](Win_msg& e) { _mailbox.subscribe_to([&](Win_msg& e) {
_bus.send<Play_sound_msg>("win"_strid);
// TODO // TODO
}); });
_mailbox.subscribe_to([&](Lose_msg& e) { _mailbox.subscribe_to([&](Lose_msg& e) {
_bus.send<Play_sound_msg>("gameover"_strid);
// TODO // TODO
}); });
} }
......
#pragma once
#include <algorithm>
#include <random>
#include <vector>
namespace phase_shifter::utils {
template <class T>
class Random_vector {
public:
Random_vector(std::vector<T> data = {}) : _data(std::move(data)) {}
auto raw_vector() -> std::vector<T>& { return _data; }
auto empty() const { return _data.empty(); }
template <class RNG>
auto get_random(RNG& gen) -> T&
{
if(_data.size() <= 1)
return _data.front();
if(_next_index < _data.size())
return _data[_next_index++];
if(_data.size() > 2) {
auto low = static_cast<std::size_t>(std::ceil(_data.size() / 4.f));
auto high = static_cast<std::size_t>(std::floor(_data.size() / 4.f * 3.f));
std::shuffle(_data.begin(), _data.begin() + high, gen);
std::shuffle(_data.begin() + low, _data.end(), gen);
}
_next_index = 1;
return _data[0];
}
private:
std::vector<T> _data;
std::size_t _next_index = 0;
};
} // namespace phase_shifter::utils
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment