更新SDL3_mixer 3.2正式版的音频接口

This commit is contained in:
Ziyu
2026-03-15 16:22:51 +08:00
parent 42d796bb83
commit 3b71120ab8
11 changed files with 135 additions and 128 deletions
+5
View File
@@ -2,6 +2,11 @@
.DS_Store
**/.DS_Store
# Agent
.agent/
.agents/
.claude/
# IDE
.config/
.idea/
+6 -6
View File
@@ -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设置
)
+42 -37
View File
@@ -1,53 +1,64 @@
#include "audio_player.h"
#include "../resource/resource_manager.h"
#include <SDL3_mixer/SDL_mixer.h>
#include <SDL3_mixer/SDL_mixer.h>
#include <spdlog/spdlog.h>
#include <glm/common.hpp>
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<int>(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<int>(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<float>(Mix_VolumeMusic(-1)) / static_cast<float>(MIX_MAX_VOLUME);
/* 参数 -1 表示查询当前音量 */
return MIX_GetTrackGain(music_track_);
}
float AudioPlayer::getSoundVolume(int channel) {
return static_cast<float>(Mix_Volume(channel, -1)) / static_cast<float>(MIX_MAX_VOLUME);
float AudioPlayer::getSoundVolume() {
return MIX_GetMixerGain(mixer_);
}
} // namespace engine::audio
+10 -11
View File
@@ -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();
};
+4 -6
View File
@@ -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)
+2 -3
View File
@@ -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 添加音效到映射表。
+28 -29
View File
@@ -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<Mix_Chunk, SDLMixChunkDeleter>(raw_chunk));
sounds_.emplace(file_path, std::unique_ptr<MIX_Audio, MIXAudioDeleter>(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<Mix_Music, SDLMixMusicDeleter>(raw_music));
music_.emplace(file_path, std::unique_ptr<MIX_Audio, MIXAudioDeleter>(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);
}
+19 -24
View File
@@ -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<std::string, std::unique_ptr<Mix_Chunk, SDLMixChunkDeleter>> sounds_;
// 音乐存储 (文件路径 -> Mix_Music)
std::unordered_map<std::string, std::unique_ptr<Mix_Music, SDLMixMusicDeleter>> music_;
// 音效存储 (文件路径 -> MIX_Audio,预解码)
std::unordered_map<std::string, std::unique_ptr<MIX_Audio, MIXAudioDeleter>> sounds_;
// 音乐存储 (文件路径 -> MIX_Audio,流式解码)
std::unordered_map<std::string, std::unique_ptr<MIX_Audio, MIXAudioDeleter>> 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 清空所有音乐资源
+8 -4
View File
@@ -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);
+10 -7
View File
@@ -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 尝试获取已加载字体的指针,如果未加载则尝试加载
+1 -1
View File
@@ -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; // 停止水平移动(否则会有惯性)