From 6e7bef8626beff06646c946e3bea5caa392e05e4 Mon Sep 17 00:00:00 2001 From: zhenyan121 <3367366583@qq.com> Date: Fri, 7 Aug 2026 08:41:56 +0800 Subject: [PATCH] feat(audio): add ambient pig sounds Add pig call audio with randomized timing, triggered by proximity to the player as 3D positional sound. --- assets/sound/creature/pig/call.mp3 | Bin 0 -> 3779 bytes .../Cubed/gameplay/client_entity_manager.hpp | 5 ++- include/Cubed/gameplay/ecs/client_entity.hpp | 5 +++ src/gameplay/client_entity_manager.cpp | 32 ++++++++++++++++-- 4 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 assets/sound/creature/pig/call.mp3 diff --git a/assets/sound/creature/pig/call.mp3 b/assets/sound/creature/pig/call.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..1075145fdb066b28e644fde6bed9991df7745d55 GIT binary patch literal 3779 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 Uz;0>Iv-1im!2e?6|JNM<0xM)JivR!s literal 0 HcmV?d00001 diff --git a/include/Cubed/gameplay/client_entity_manager.hpp b/include/Cubed/gameplay/client_entity_manager.hpp index 427e898..1230edf 100644 --- a/include/Cubed/gameplay/client_entity_manager.hpp +++ b/include/Cubed/gameplay/client_entity_manager.hpp @@ -1,6 +1,7 @@ #pragma once #include "Cubed/gameplay/ecs/entity.hpp" #include "Cubed/gameplay/gait.hpp" +#include "Cubed/tools/cubed_random.hpp" #include "glm/ext/vector_float3.hpp" #include "world/entity.pb.h" @@ -26,6 +27,8 @@ public: const entt::registry& get_registry() const; + void player_sound(float dt); + private: struct EntityCreateElement { EntityID id; @@ -52,7 +55,7 @@ private: EntityMap m_entities; std::unordered_map m_factories; tbb::concurrent_queue m_tasks; - + Random m_random; void handle_task(float dt); void handle_entity_destory(EntityID id); // not thread safe diff --git a/include/Cubed/gameplay/ecs/client_entity.hpp b/include/Cubed/gameplay/ecs/client_entity.hpp index 1b21280..7f0d98a 100644 --- a/include/Cubed/gameplay/ecs/client_entity.hpp +++ b/include/Cubed/gameplay/ecs/client_entity.hpp @@ -11,4 +11,9 @@ struct BaseClientCreature { ModelID model; }; + +struct SoundTime { + float next_call_time; +}; + } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/client_entity_manager.cpp b/src/gameplay/client_entity_manager.cpp index b8c7d11..7a0a72a 100644 --- a/src/gameplay/client_entity_manager.cpp +++ b/src/gameplay/client_entity_manager.cpp @@ -7,8 +7,8 @@ #include "Cubed/gameplay/ecs/transform.hpp" #include "Cubed/render/model_manager.hpp" #include "Cubed/tools/cubed_assert.hpp" +#include "Cubed/tools/math_tools.hpp" #include "Cubed/tools/net_utils.hpp" - using namespace google::protobuf; namespace Cubed { @@ -25,15 +25,20 @@ void ClientEntityManager::update(float dt) { c.pose.walk_time += dt; } } + + player_sound(dt); } void ClientEntityManager::init() { + m_random.init(std::random_device()()); m_factories.emplace("cubed:pig", [this](EntityID id) { BaseClientCreature c; c.model = ModelManager::instance().get_model_id("cubed:pig"); + float next_call_time = m_random.random_float(8.0f, 25.0f); create_entity_in_registry(id, Entity{id, EntityType::CREATURE}, EntityInfo{"cubed:pig", ""}, std::move(c), - PigTag{}, RenderTransform{}); + PigTag{}, RenderTransform{}, + SoundTime{next_call_time}); }); } // not thread safe @@ -157,4 +162,27 @@ void ClientEntityManager::handle_entity_destory(EntityID id) { const entt::registry& ClientEntityManager::get_registry() const { return m_registry; } + +void ClientEntityManager::player_sound(float dt) { + auto& audio = m_world.get_audio(); + auto player_pos = m_world.player_manager().get_local().get_player_pos(); + auto view = m_registry.view(); + + for (auto e : view) { + const auto [info, creature] = + view.get(e); + if (Math::distance2(player_pos, creature.transform.position.value) > + 10 * 10) { + continue; + } + auto& sound_time = view.get(e); + sound_time.next_call_time -= dt; + if (sound_time.next_call_time <= 0.0f) { + audio.play_3d("creature/pig/call.mp3", + creature.transform.position.value); + sound_time.next_call_time = m_random.random_float(8.0f, 25.0f); + } + } +} + } // namespace Cubed \ No newline at end of file