#include "behavior.h" #include #include #include #include #include UF_BEHAVIOR_REGISTER_CPP(ext::SoundEmitterBehavior) UF_BEHAVIOR_TRAITS_CPP(ext::SoundEmitterBehavior, ticks = true, renders = false, multithread = true) #define this ((uf::Object*) &self) void ext::SoundEmitterBehavior::initialize( uf::Object& self ) { auto& metadata = this->getComponent(); auto& emitter = this->getComponent(); auto& sounds = emitter.get(); auto& scene = uf::scene::getCurrentScene(); auto& assetLoader = scene.getComponent(); if ( !metadata["audio"]["epsilon"].is() ) metadata["audio"]["epsilon"] = 0.001f; this->addHook( "sound:Stop.%UID%", [&](ext::json::Value& json){ uf::stl::string filename = json["filename"].as(); for ( size_t i = 0; i < sounds.size(); ++i ) { if ( sounds[i].getFilename() != filename ) continue; sounds[i].destroy(); sounds.erase(sounds.begin() + i); metadata["sounds"].erase(i); } }); this->addHook( "sound:Emit.%UID%", [&](ext::json::Value& json){ if ( ext::json::isNull(json["volume"]) ) json["volume"] = metadata["audio"]["volume"]; if ( ext::json::isNull(json["pitch"]) ) json["pitch"] = metadata["audio"]["pitch"]; if ( ext::json::isNull(json["gain"]) ) json["gain"] = metadata["audio"]["gain"]; if ( ext::json::isNull(json["rolloffFactor"]) ) json["rolloffFactor"] = metadata["audio"]["rolloffFactor"]; if ( ext::json::isNull(json["maxDistance"]) ) json["maxDistance"] = metadata["audio"]["maxDistance"]; if ( ext::json::isNull(json["epsilon"]) ) json["epsilon"] = metadata["audio"]["epsilon"]; if ( ext::json::isNull(json["loop"]) ) json["loop"] = metadata["audio"]["loop"]; if ( ext::json::isNull(json["streamed"]) ) json["streamed"] = metadata["audio"]["streamed"]; if ( ext::json::isNull(json["unique"]) ) json["unique"] = metadata["audio"]["unique"]; metadata["sounds"].emplace_back(json); uf::stl::string filename = json["filename"].as(); bool unique = json["unique"].as(); bool exists = unique && emitter.has( filename ); uf::Audio& audio = exists ? emitter.get( filename ) : emitter.add(); if ( !exists ) { if ( assetLoader.has(filename) ) { audio = std::move( assetLoader.get(filename) ); assetLoader.remove(filename); } else { audio.open( filename, json["streamed"].as() ); } } if ( json["pitch"].is() ) audio.setPitch(json["pitch"].as()); if ( json["gain"].is() ) audio.setGain(json["gain"].as()); if ( json["rolloffFactor"].is() ) audio.setRolloffFactor(json["rolloffFactor"].as()); if ( json["maxDistance"].is() ) audio.setMaxDistance(json["maxDistance"].as()); if ( json["loop"].is() ) audio.loop(json["loop"].as()); float volume = 1.0f; if ( json["volume"].is() ) volume = json["volume"].as(); else if ( json["volume"].is() ) { uf::stl::string key = json["volume"].as(); #if UF_AUDIO_MAPPED_VOLUMES if ( uf::audio::volumes.count(key) > 0 ) volume = uf::audio::volumes.at(key); #else if ( key == "bgm" ) volume = uf::audio::volumes::bgm; else if ( key == "sfx" ) volume = uf::audio::volumes::sfx; else if ( key == "voice" ) volume = uf::audio::volumes::voice; #endif } audio.setVolume(volume); audio.play(); }); this->addHook( "asset:Load.%UID%", [&](pod::payloads::assetLoad& payload){ if ( !uf::Asset::isExpected( payload, uf::Asset::Type::AUDIO ) ) return; if ( !assetLoader.has(payload.filename) ) return; ext::json::Value json = metadata["audio"]; json["filename"] = payload.filename; this->lazyCallHook("sound:Emit.%UID%", json); }); } void ext::SoundEmitterBehavior::tick( uf::Object& self ) { auto& transform = this->getComponent>(); auto flatten = uf::transform::flatten( transform ); auto& metadata = this->getComponent(); auto& emitter = this->getComponent(); auto& sounds = emitter.get(); for ( size_t i = 0; i < sounds.size(); ++i ) { auto& audio = sounds[i]; auto& json = metadata["sounds"][i]; if ( json["spatial"].as() && audio.playing() ) { audio.setPosition( flatten.position ); audio.setOrientation( flatten.orientation ); } if ( audio.loops() && !audio.playing() ) { audio.destroy(); sounds.erase(sounds.begin() + i); metadata["sounds"].erase(i); } } } void ext::SoundEmitterBehavior::render( uf::Object& self ){} void ext::SoundEmitterBehavior::destroy( uf::Object& self ){} void ext::SoundEmitterBehavior::Metadata::serialize( uf::Object& self, uf::Serializer& serializer ){} void ext::SoundEmitterBehavior::Metadata::deserialize( uf::Object& self, uf::Serializer& serializer ){} #undef this