From 3b71120ab8976ca03f5b07fe9c91d033f03614f8 Mon Sep 17 00:00:00 2001 From: Ziyu Date: Sun, 15 Mar 2026 15:44:29 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0SDL3=5Fmixer=203.2=E6=AD=A3?= =?UTF-8?q?=E5=BC=8F=E7=89=88=E7=9A=84=E9=9F=B3=E9=A2=91=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 5 ++ cmake/Dependencies.cmake | 12 ++-- src/engine/audio/audio_player.cpp | 79 +++++++++++++----------- src/engine/audio/audio_player.h | 21 +++---- src/engine/component/audio_component.cpp | 10 ++- src/engine/component/audio_component.h | 5 +- src/engine/resource/audio_manager.cpp | 57 +++++++++-------- src/engine/resource/audio_manager.h | 43 ++++++------- src/engine/resource/resource_manager.cpp | 12 ++-- src/engine/resource/resource_manager.h | 17 ++--- src/game/component/ai/jump_behavior.cpp | 2 +- 11 files changed, 135 insertions(+), 128 deletions(-) diff --git a/.gitignore b/.gitignore index 5592100..048be35 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,11 @@ .DS_Store **/.DS_Store +# Agent +.agent/ +.agents/ +.claude/ + # IDE .config/ .idea/ diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 9e96aae..257735b 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -180,8 +180,8 @@ function(setup_project_dependencies) SDL3 SDL3 "https://github.com/libsdl-org/SDL.git" - "release-3.2.24" - "external/SDL-release-3.2.24" + "release-3.4.2" + "external/SDL-release-3.4.2" AUTO # 使用全局BUILD_SHARED_LIBS设置 ) @@ -195,8 +195,8 @@ function(setup_project_dependencies) SDL3_image SDL3_image "https://github.com/libsdl-org/SDL_image.git" - "release-3.2.4" - "external/SDL_image-release-3.2.4" + "release-3.4.0" + "external/SDL_image-release-3.4.0" AUTO # 使用全局BUILD_SHARED_LIBS设置 ) @@ -205,8 +205,8 @@ function(setup_project_dependencies) SDL3_mixer SDL3_mixer "https://github.com/libsdl-org/SDL_mixer.git" - "30c1301055a35ee87b8679279b6fc88e10d28fa3" - "external/SDL_mixer-30c1301" + "release-3.2.0" + "external/SDL_mixer-release-3.2.0" AUTO # 使用全局BUILD_SHARED_LIBS设置 ) diff --git a/src/engine/audio/audio_player.cpp b/src/engine/audio/audio_player.cpp index 397059c..4262fdb 100644 --- a/src/engine/audio/audio_player.cpp +++ b/src/engine/audio/audio_player.cpp @@ -1,53 +1,64 @@ #include "audio_player.h" #include "../resource/resource_manager.h" -#include +#include #include -#include namespace engine::audio { -AudioPlayer::~AudioPlayer() = default; +AudioPlayer::~AudioPlayer() { + if (music_track_) { + MIX_DestroyTrack(music_track_); + music_track_ = nullptr; + } +} AudioPlayer::AudioPlayer(engine::resource::ResourceManager* resource_manager) : resource_manager_(resource_manager) { if (!resource_manager_) { throw std::runtime_error("AudioPlayer 构造失败: 提供的 ResourceManager 指针为空。"); } + mixer_ = resource_manager_->getMixer(); + music_track_ = MIX_CreateTrack(mixer_); + if (!music_track_) { + throw std::runtime_error("AudioPlayer 构造失败: 无法创建音乐轨道: " + std::string(SDL_GetError())); + } } -int AudioPlayer::playSound(std::string_view sound_path, int channel) { +int AudioPlayer::playSound(std::string_view sound_path) { - Mix_Chunk* chunk = resource_manager_->getSound(sound_path); // 通过 ResourceManager 获取资源 - if (!chunk) { + MIX_Audio* audio = resource_manager_->getSound(sound_path); // 通过 ResourceManager 获取资源 + if (!audio) { spdlog::error("AudioPlayer: 无法获取音效 '{}' 播放。", sound_path); return -1; } - int played_channel = Mix_PlayChannel(channel, chunk, 0); // 播放音效 - if (played_channel == -1) { + if (!MIX_PlayAudio(mixer_, audio)) { // 即发即忘方式播放音效 spdlog::error("AudioPlayer: 无法播放音效 '{}': {}", sound_path, SDL_GetError()); - } else { - spdlog::trace("AudioPlayer: 播放音效 '{}' 在通道 {}。", sound_path, played_channel); + return -1; } - return played_channel; + spdlog::trace("AudioPlayer: 播放音效 '{}'。", sound_path); + return 0; } bool AudioPlayer::playMusic(std::string_view music_path, int loops, int fade_in_ms) { if (music_path == current_music_) return true; // 如果当前音乐已经在播放,则不重复播放 current_music_ = music_path; - Mix_Music* music = resource_manager_->getMusic(music_path); // 通过 ResourceManager 获取资源 + MIX_Audio* music = resource_manager_->getMusic(music_path); // 通过 ResourceManager 获取资源 if (!music) { spdlog::error("AudioPlayer: 无法获取音乐 '{}' 播放。", music_path); return false; } - Mix_HaltMusic(); // 停止之前的音乐 + MIX_StopTrack(music_track_, 0); // 立即停止之前的音乐 + MIX_SetTrackAudio(music_track_, music); // 设置音乐轨道的音频源 - bool result = false; + // 配置播放参数(循环次数、淡入时长) + SDL_PropertiesID props = SDL_CreateProperties(); + SDL_SetNumberProperty(props, MIX_PROP_PLAY_LOOPS_NUMBER, loops); if (fade_in_ms > 0) { - result = Mix_FadeInMusic(music, loops, fade_in_ms); // 淡入播放音乐 - } else { - result = Mix_PlayMusic(music, loops); + SDL_SetNumberProperty(props, MIX_PROP_PLAY_FADE_IN_MILLISECONDS_NUMBER, fade_in_ms); } + bool result = MIX_PlayTrack(music_track_, props); + SDL_DestroyProperties(props); if (!result) { spdlog::error("AudioPlayer: 无法播放音乐 '{}': {}", music_path, SDL_GetError()); @@ -58,45 +69,39 @@ bool AudioPlayer::playMusic(std::string_view music_path, int loops, int fade_in_ } void AudioPlayer::stopMusic(int fade_out_ms) { - if (fade_out_ms > 0) { - Mix_FadeOutMusic(fade_out_ms); // 淡出音乐 - } else { - Mix_HaltMusic(); - } - spdlog::trace("AudioPlayer: 停止音乐。"); + Sint64 fade_frames = (fade_out_ms > 0) ? MIX_TrackMSToFrames(music_track_, fade_out_ms) : 0; + MIX_StopTrack(music_track_, fade_frames); + current_music_.clear(); + spdlog::trace("AudioPlayer: 停止音乐。"); } void AudioPlayer::pauseMusic() { - Mix_PauseMusic(); + MIX_PauseTrack(music_track_); spdlog::trace("AudioPlayer: 暂停音乐。"); } void AudioPlayer::resumeMusic() { - Mix_ResumeMusic(); + MIX_ResumeTrack(music_track_); spdlog::trace("AudioPlayer: 恢复音乐。"); } -void AudioPlayer::setSoundVolume(float volume, int channel) { - // 将浮点音量(0-1)转换为SDL_mixer的音量(0-128) - int sdl_volume = static_cast(glm::max(0.0f, glm::min(1.0f, volume)) * MIX_MAX_VOLUME); - Mix_Volume(channel, sdl_volume); - spdlog::trace("AudioPlayer: 设置通道 {} 的音量为 {:.2f}。", channel, volume); +void AudioPlayer::setSoundVolume(float volume) { + // 通过混音器整体增益控制音效音量(0.0-1.0) + MIX_SetMixerGain(mixer_, volume); + spdlog::trace("AudioPlayer: 设置音效音量为 {:.2f}。", volume); } void AudioPlayer::setMusicVolume(float volume) { - int sdl_volume = static_cast(glm::max(0.0f, glm::min(1.0f, volume)) * MIX_MAX_VOLUME); - Mix_VolumeMusic(sdl_volume); + MIX_SetTrackGain(music_track_, volume); spdlog::trace("AudioPlayer: 设置音乐音量为 {:.2f}。", volume); } float AudioPlayer::getMusicVolume() { - // SDL_mixer的音量(0-128)转为 0~1.0 的浮点数 - return static_cast(Mix_VolumeMusic(-1)) / static_cast(MIX_MAX_VOLUME); - /* 参数 -1 表示查询当前音量 */ + return MIX_GetTrackGain(music_track_); } -float AudioPlayer::getSoundVolume(int channel) { - return static_cast(Mix_Volume(channel, -1)) / static_cast(MIX_MAX_VOLUME); +float AudioPlayer::getSoundVolume() { + return MIX_GetMixerGain(mixer_); } } // namespace engine::audio diff --git a/src/engine/audio/audio_player.h b/src/engine/audio/audio_player.h index 1ff23db..ab83232 100644 --- a/src/engine/audio/audio_player.h +++ b/src/engine/audio/audio_player.h @@ -6,8 +6,8 @@ namespace engine::resource { class ResourceManager; } -struct Mix_Chunk; -struct Mix_Music; +struct MIX_Mixer; +struct MIX_Track; namespace engine::audio { @@ -20,6 +20,8 @@ namespace engine::audio { class AudioPlayer final{ private: engine::resource::ResourceManager* resource_manager_; ///< @brief 指向 ResourceManager 的非拥有指针,用于加载和管理音频资源。 + MIX_Mixer* mixer_{nullptr}; ///< @brief SDL_mixer 混音器指针(非拥有)。 + MIX_Track* music_track_{nullptr}; ///< @brief 专用于背景音乐播放的轨道(拥有)。 std::string current_music_; ///< @brief 当前正在播放的音乐路径,用于避免重复播放同一音乐。 public: @@ -37,13 +39,12 @@ public: // --- 播放控制方法 --- /** - * @brief 播放音效(chunk)。 + * @brief 播放音效。 * 如果尚未缓存,则通过 ResourceManager 加载音效。 * @param sound_path 音效文件的路径。 - * @param channel 要播放的特定通道,或 -1 表示第一个可用通道。默认为 -1。 - * @return 音效正在播放的通道,出错时返回 -1。 + * @return 成功返回 0,出错返回 -1。 */ - int playSound(std::string_view sound_path, int channel = -1); + int playSound(std::string_view sound_path); /** * @brief 播放背景音乐。如果正在播放,则淡出之前的音乐。 @@ -72,11 +73,10 @@ public: void resumeMusic(); /** - * @brief 设置音效通道的音量。 + * @brief 设置音效音量。 * @param volume 音量级别(0.0-1.0)。 - * @param channel 通道号(-1 表示所有通道)。默认为 -1。 */ - void setSoundVolume(float volume, int channel = -1); + void setSoundVolume(float volume); /** * @brief 设置音乐通道的音量。 @@ -92,10 +92,9 @@ public: /** * @brief 获取当前音效音量。 - * @param channel 通道号(-1 表示所有通道)。默认为 -1。 * @return 音量级别(0.0-1.0)。 */ - float getSoundVolume(int channel = -1); + float getSoundVolume(); }; diff --git a/src/engine/component/audio_component.cpp b/src/engine/component/audio_component.cpp index 62ac2ed..124464d 100644 --- a/src/engine/component/audio_component.cpp +++ b/src/engine/component/audio_component.cpp @@ -27,14 +27,14 @@ void AudioComponent::init() } } -void AudioComponent::playSound(std::string_view sound_id, int channel, bool use_spatial) +void AudioComponent::playSound(std::string_view sound_id, bool use_spatial) { // 如果 sound_id 是音效 ID,则在查找在map中查找对应的路径; 没找到的话则把 sound_id 当作路径直接使用 auto sound_path = sound_id_to_path_.find(std::string(sound_id)) != sound_id_to_path_.end() ? sound_id_to_path_[std::string(sound_id)] : sound_id; if (use_spatial && transform_) { // 使用空间定位 - // TODO: (SDL_Mixer 不支持空间定位,未来更换音频库时可以方便地实现) - // 这里给一个简单的功能:150像素范围内播放,否则不播放 + // TODO: 正式版 SDL3_Mixer 已经支持空间定位,但本期课程不展开,你可以尝试自己完成。 + // 这里给一个简单的功能:150像素范围内播放,否则不播放 auto camera_center = camera_->getPosition() + camera_->getViewportSize() / 2.0f; // 相机中心 auto object_pos = transform_->getPosition(); float distance = glm::length(camera_center - object_pos); @@ -42,10 +42,8 @@ void AudioComponent::playSound(std::string_view sound_id, int channel, bool use_ spdlog::debug("AudioComponent::playSound: 音效 '{}' 超出范围,不播放。", sound_id); return; // 超出范围,不播放 } - audio_player_->playSound(sound_path, channel); - } else { // 不使用空间定位 - audio_player_->playSound(sound_path, channel); } + audio_player_->playSound(sound_path); } void AudioComponent::addSound(std::string_view sound_id, std::string_view sound_path) diff --git a/src/engine/component/audio_component.h b/src/engine/component/audio_component.h index a42aa46..8f9280e 100644 --- a/src/engine/component/audio_component.h +++ b/src/engine/component/audio_component.h @@ -39,11 +39,10 @@ public: /** * @brief 播放音效。 - * @param sound_path 音效文件的id (或路径)。 - * @param channel 要播放的特定通道,或 -1 表示第一个可用通道。 + * @param sound_id 音效文件的id (或路径)。 * @param use_spatial 是否使用空间定位。 */ - void playSound(std::string_view sound_id, int channel = -1, bool use_spatial = false); + void playSound(std::string_view sound_id, bool use_spatial = false); /** * @brief 添加音效到映射表。 diff --git a/src/engine/resource/audio_manager.cpp b/src/engine/resource/audio_manager.cpp index 326f627..3a5aaad 100644 --- a/src/engine/resource/audio_manager.cpp +++ b/src/engine/resource/audio_manager.cpp @@ -6,16 +6,16 @@ namespace engine::resource { // 构造函数:初始化SDL_mixer AudioManager::AudioManager() { - // 使用所需的格式初始化SDL_mixer(推荐OGG、MP3) - MIX_InitFlags flags = MIX_INIT_OGG | MIX_INIT_MP3; - if ((Mix_Init(flags) & flags) != flags) { - throw std::runtime_error("AudioManager 错误: Mix_Init 失败: " + std::string(SDL_GetError())); + // SDL_mixer 3.2.0 不再需要传入格式标志 + if (!MIX_Init()) { + throw std::runtime_error("AudioManager 错误: MIX_Init 失败: " + std::string(SDL_GetError())); } - // SDL3打开音频设备的方法。默认值:44100 Hz,默认格式,2声道(立体声),2048采样块大小 - if (!Mix_OpenAudio(0, nullptr)) { - Mix_Quit(); // 如果OpenAudio失败,先清理Mix_Init,再抛出异常 - throw std::runtime_error("AudioManager 错误: Mix_OpenAudio 失败: " + std::string(SDL_GetError())); + // 创建连接到默认音频输出设备的混音器 + mixer_ = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, nullptr); + if (!mixer_) { + MIX_Quit(); + throw std::runtime_error("AudioManager 错误: MIX_CreateMixerDevice 失败: " + std::string(SDL_GetError())); } spdlog::trace("AudioManager 构造成功。"); } @@ -23,44 +23,43 @@ AudioManager::AudioManager() { AudioManager::~AudioManager() { // 立即停止所有音频播放 - Mix_HaltChannel(-1); // 停止所有音效 - Mix_HaltMusic(); // 停止音乐 + MIX_StopAllTracks(mixer_, 0); // 清理资源映射(unique_ptrs会调用删除器) clearSounds(); clearMusic(); - // 关闭音频设备 - Mix_CloseAudio(); + // 销毁混音器(同时关闭音频设备) + MIX_DestroyMixer(mixer_); // 退出SDL_mixer子系统 - Mix_Quit(); + MIX_Quit(); spdlog::trace("AudioManager 析构成功。"); } // --- 音效管理 --- -Mix_Chunk* AudioManager::loadSound(std::string_view file_path) { +MIX_Audio* AudioManager::loadSound(std::string_view file_path) { // 首先检查缓存 auto it = sounds_.find(std::string(file_path)); if (it != sounds_.end()) { return it->second.get(); } - // 加载音效块 + // 加载音效块(predecode=true,预先解码为PCM,适合短音效) spdlog::debug("加载音效: {}", file_path); - Mix_Chunk* raw_chunk = Mix_LoadWAV(file_path.data()); - if (!raw_chunk) { + MIX_Audio* audio = MIX_LoadAudio(mixer_, file_path.data(), true); + if (!audio) { spdlog::error("加载音效失败: '{}': {}", file_path, SDL_GetError()); return nullptr; } // 使用unique_ptr存储在缓存中 - sounds_.emplace(file_path, std::unique_ptr(raw_chunk)); + sounds_.emplace(file_path, std::unique_ptr(audio)); spdlog::debug("成功加载并缓存音效: {}", file_path); - return raw_chunk; + return audio; } -Mix_Chunk* AudioManager::getSound(std::string_view file_path) { +MIX_Audio* AudioManager::getSound(std::string_view file_path) { auto it = sounds_.find(std::string(file_path)); if (it != sounds_.end()) { return it->second.get(); @@ -73,7 +72,7 @@ void AudioManager::unloadSound(std::string_view file_path) { auto it = sounds_.find(std::string(file_path)); if (it != sounds_.end()) { spdlog::debug("卸载音效: {}", file_path); - sounds_.erase(it); // unique_ptr处理Mix_FreeChunk + sounds_.erase(it); // unique_ptr处理MIX_DestroyAudio } else { spdlog::warn("尝试卸载不存在的音效: {}", file_path); } @@ -87,28 +86,28 @@ void AudioManager::clearSounds() { } // --- 音乐管理 --- -Mix_Music* AudioManager::loadMusic(std::string_view file_path) { +MIX_Audio* AudioManager::loadMusic(std::string_view file_path) { // 首先检查缓存 auto it = music_.find(std::string(file_path)); if (it != music_.end()) { return it->second.get(); } - // 加载音乐 + // 加载音乐(predecode=false,流式解码,适合长音乐) spdlog::debug("加载音乐: {}", file_path); - Mix_Music* raw_music = Mix_LoadMUS(file_path.data()); - if (!raw_music) { + MIX_Audio* audio = MIX_LoadAudio(mixer_, file_path.data(), false); + if (!audio) { spdlog::error("加载音乐失败: '{}': {}", file_path, SDL_GetError()); return nullptr; } // 使用unique_ptr存储在缓存中 - music_.emplace(file_path, std::unique_ptr(raw_music)); + music_.emplace(file_path, std::unique_ptr(audio)); spdlog::debug("成功加载并缓存音乐: {}", file_path); - return raw_music; + return audio; } -Mix_Music* AudioManager::getMusic(std::string_view file_path) { +MIX_Audio* AudioManager::getMusic(std::string_view file_path) { auto it = music_.find(std::string(file_path)); if (it != music_.end()) { return it->second.get(); @@ -121,7 +120,7 @@ void AudioManager::unloadMusic(std::string_view file_path) { auto it = music_.find(std::string(file_path)); if (it != music_.end()) { spdlog::debug("卸载音乐: {}", file_path); - music_.erase(it); // unique_ptr处理Mix_FreeMusic + music_.erase(it); // unique_ptr处理MIX_DestroyAudio } else { spdlog::warn("尝试卸载不存在的音乐: {}", file_path); } diff --git a/src/engine/resource/audio_manager.h b/src/engine/resource/audio_manager.h index 7083d45..7d6d57b 100644 --- a/src/engine/resource/audio_manager.h +++ b/src/engine/resource/audio_manager.h @@ -10,7 +10,7 @@ namespace engine::resource { /** - * @brief 管理 SDL_mixer 音效 (Mix_Chunk) 和音乐 (Mix_Music)。 + * @brief 管理 SDL_mixer 音效和音乐 (统一为 MIX_Audio 类型)。 * * 提供音频资源的加载和缓存功能。构造失败时会抛出异常。 * 仅供 ResourceManager 内部使用。 @@ -19,33 +19,26 @@ class AudioManager final{ friend class ResourceManager; private: - // Mix_Chunk 的自定义删除器 - struct SDLMixChunkDeleter { - void operator()(Mix_Chunk* chunk) const { - if (chunk) { - Mix_FreeChunk(chunk); + // MIX_Audio 的自定义删除器(音效和音乐统一类型) + struct MIXAudioDeleter { + void operator()(MIX_Audio* audio) const { + if (audio) { + MIX_DestroyAudio(audio); } } }; - // Mix_Music 的自定义删除器 - struct SDLMixMusicDeleter { - void operator()(Mix_Music* music) const { - if (music) { - Mix_FreeMusic(music); - } - } - }; + MIX_Mixer* mixer_{nullptr}; ///< @brief SDL_mixer 混音器实例 - // 音效存储 (文件路径 -> Mix_Chunk) - std::unordered_map> sounds_; - // 音乐存储 (文件路径 -> Mix_Music) - std::unordered_map> music_; + // 音效存储 (文件路径 -> MIX_Audio,预解码) + std::unordered_map> sounds_; + // 音乐存储 (文件路径 -> MIX_Audio,流式解码) + std::unordered_map> music_; public: /** - * @brief 构造函数。初始化 SDL_mixer 并打开音频设备。 - * @throws std::runtime_error 如果 SDL_mixer 初始化或打开音频设备失败。 + * @brief 构造函数。初始化 SDL_mixer 并创建音频设备混音器。 + * @throws std::runtime_error 如果 SDL_mixer 初始化或创建混音器失败。 */ AudioManager(); @@ -57,15 +50,17 @@ public: AudioManager(AudioManager&&) = delete; AudioManager& operator=(AudioManager&&) = delete; + MIX_Mixer* getMixer() const { return mixer_; } ///< @brief 获取混音器指针 + private: // 仅供 ResourceManager 访问的方法 - Mix_Chunk* loadSound(std::string_view file_path); ///< @brief 从文件路径加载音效 - Mix_Chunk* getSound(std::string_view file_path); ///< @brief 尝试获取已加载音效的指针,如果未加载则尝试加载 + MIX_Audio* loadSound(std::string_view file_path); ///< @brief 从文件路径加载音效(预解码) + MIX_Audio* getSound(std::string_view file_path); ///< @brief 尝试获取已加载音效的指针,如果未加载则尝试加载 void unloadSound(std::string_view file_path); ///< @brief 卸载指定的音效资源 void clearSounds(); ///< @brief 清空所有音效资源 - Mix_Music* loadMusic(std::string_view file_path); ///< @brief 从文件路径加载音乐 - Mix_Music* getMusic(std::string_view file_path); ///< @brief 尝试获取已加载音乐的指针,如果未加载则尝试加载 + MIX_Audio* loadMusic(std::string_view file_path); ///< @brief 从文件路径加载音乐(流式解码) + MIX_Audio* getMusic(std::string_view file_path); ///< @brief 尝试获取已加载音乐的指针,如果未加载则尝试加载 void unloadMusic(std::string_view file_path); ///< @brief 卸载指定的音乐资源 void clearMusic(); ///< @brief 清空所有音乐资源 diff --git a/src/engine/resource/resource_manager.cpp b/src/engine/resource/resource_manager.cpp index 6bf9260..fa56801 100644 --- a/src/engine/resource/resource_manager.cpp +++ b/src/engine/resource/resource_manager.cpp @@ -52,11 +52,11 @@ void ResourceManager::clearTextures() { } // --- 音频接口实现 --- -Mix_Chunk* ResourceManager::loadSound(std::string_view file_path) { +MIX_Audio* ResourceManager::loadSound(std::string_view file_path) { return audio_manager_->loadSound(file_path); } -Mix_Chunk* ResourceManager::getSound(std::string_view file_path) { +MIX_Audio* ResourceManager::getSound(std::string_view file_path) { return audio_manager_->getSound(file_path); } @@ -68,11 +68,11 @@ void ResourceManager::clearSounds() { audio_manager_->clearSounds(); } -Mix_Music* ResourceManager::loadMusic(std::string_view file_path) { +MIX_Audio* ResourceManager::loadMusic(std::string_view file_path) { return audio_manager_->loadMusic(file_path); } -Mix_Music* ResourceManager::getMusic(std::string_view file_path) { +MIX_Audio* ResourceManager::getMusic(std::string_view file_path) { return audio_manager_->getMusic(file_path); } @@ -84,6 +84,10 @@ void ResourceManager::clearMusic() { audio_manager_->clearMusic(); } +MIX_Mixer* ResourceManager::getMixer() { + return audio_manager_->getMixer(); +} + // --- 字体接口实现 --- TTF_Font* ResourceManager::loadFont(std::string_view file_path, int point_size) { return font_manager_->loadFont(file_path, point_size); diff --git a/src/engine/resource/resource_manager.h b/src/engine/resource/resource_manager.h index ca78661..68f30c1 100644 --- a/src/engine/resource/resource_manager.h +++ b/src/engine/resource/resource_manager.h @@ -7,8 +7,8 @@ // 前向声明 SDL 类型 struct SDL_Renderer; struct SDL_Texture; -struct Mix_Chunk; -struct Mix_Music; +struct MIX_Audio; +struct MIX_Mixer; struct TTF_Font; namespace engine::resource { @@ -54,18 +54,21 @@ public: glm::vec2 getTextureSize(std::string_view file_path); ///< @brief 获取指定纹理的尺寸 void clearTextures(); ///< @brief 清空所有纹理资源 - // -- Sound Effects (Chunks) -- - Mix_Chunk* loadSound(std::string_view file_path); ///< @brief 载入音效资源 - Mix_Chunk* getSound(std::string_view file_path); ///< @brief 尝试获取已加载音效的指针,如果未加载则尝试加载 + // -- Sound Effects -- + MIX_Audio* loadSound(std::string_view file_path); ///< @brief 载入音效资源 + MIX_Audio* getSound(std::string_view file_path); ///< @brief 尝试获取已加载音效的指针,如果未加载则尝试加载 void unloadSound(std::string_view file_path); ///< @brief 卸载指定的音效资源 void clearSounds(); ///< @brief 清空所有音效资源 // -- Music -- - Mix_Music* loadMusic(std::string_view file_path); ///< @brief 载入音乐资源 - Mix_Music* getMusic(std::string_view file_path); ///< @brief 尝试获取已加载音乐的指针,如果未加载则尝试加载 + MIX_Audio* loadMusic(std::string_view file_path); ///< @brief 载入音乐资源 + MIX_Audio* getMusic(std::string_view file_path); ///< @brief 尝试获取已加载音乐的指针,如果未加载则尝试加载 void unloadMusic(std::string_view file_path); ///< @brief 卸载指定的音乐资源 void clearMusic(); ///< @brief 清空所有音乐资源 + // -- Mixer -- + MIX_Mixer* getMixer(); ///< @brief 获取 SDL_mixer 混音器指针 + // -- Fonts -- TTF_Font* loadFont(std::string_view file_path, int point_size); ///< @brief 载入字体资源 TTF_Font* getFont(std::string_view file_path, int point_size); ///< @brief 尝试获取已加载字体的指针,如果未加载则尝试加载 diff --git a/src/game/component/ai/jump_behavior.cpp b/src/game/component/ai/jump_behavior.cpp index e1d3f1f..e24bcc2 100644 --- a/src/game/component/ai/jump_behavior.cpp +++ b/src/game/component/ai/jump_behavior.cpp @@ -45,7 +45,7 @@ void JumpBehavior::update(float delta_time, AIComponent& ai_component) { auto is_on_ground = physics_component->hasCollidedBelow(); // 着地标志 if (is_on_ground) { // 如果在地面上 if (audio_component && jump_timer_ < 0.001f) { // 刚刚落地时(进入idle状态),如果有音频组件,播放音效 - audio_component->playSound("cry", -1, true); // 使用空间音频 + audio_component->playSound("cry", true); // 使用空间音频 } jump_timer_ += delta_time; // 增加跳跃计时器 physics_component->velocity_.x = 0.0f; // 停止水平移动(否则会有惯性)