Extra2D/docs/API_Tutorial/08_Audio_System.md

370 lines
8.1 KiB
Markdown
Raw Normal View History

2026-02-11 19:40:26 +08:00
# 08. 音频系统
Extra2D 提供了基于 SDL2_mixer 的音频播放系统,支持音效播放。
## 音频引擎
通过 `Application::instance().audio()` 访问音频引擎:
```cpp
auto& audio = Application::instance().audio();
```
## 播放音效
### 基本用法
```cpp
// 加载音效
auto sound = audio.loadSound("assets/audio/jump.wav");
// 播放音效
sound->play();
// 设置音量 (0.0 - 1.0)
sound->setVolume(0.8f);
```
### 音效控制
```cpp
// 停止播放
sound->stop();
// 暂停
sound->pause();
// 恢复
sound->resume();
// 循环播放
sound->setLooping(true);
// 检查播放状态
bool playing = sound->isPlaying();
bool paused = sound->isPaused();
```
### 音调和播放位置
```cpp
// 设置音调(当前实现不支持)
sound->setPitch(1.0f);
// 获取/设置播放位置(当前实现不支持)
float cursor = sound->getCursor();
sound->setCursor(0.0f);
// 获取音频时长(当前实现不支持)
float duration = sound->getDuration();
```
## 全局音量控制
```cpp
// 设置主音量
audio.setMasterVolume(0.8f);
// 获取主音量
float volume = audio.getMasterVolume();
```
## 全局播放控制
```cpp
// 暂停所有音效
audio.pauseAll();
// 恢复所有音效
audio.resumeAll();
// 停止所有音效
audio.stopAll();
// 卸载指定音效
audio.unloadSound("jump");
// 卸载所有音效
audio.unloadAllSounds();
```
## 完整示例
### Flappy Bird 音效管理器
参考 `examples/flappy_bird/ResLoader.h/cpp`
```cpp
// ResLoader.h
#pragma once
#include <extra2d/extra2d.h>
#include <map>
namespace flappybird {
enum class MusicType {
Click, // 按键声音
Hit, // 小鸟死亡声音
Fly, // 小鸟飞翔声音
Point, // 得分声音
Swoosh // 转场声音
};
class ResLoader {
public:
static void init();
static void playMusic(MusicType type);
private:
static std::map<MusicType, extra2d::Ptr<extra2d::Sound>> soundMap_;
};
} // namespace flappybird
```
```cpp
// ResLoader.cpp
#include "ResLoader.h"
namespace flappybird {
std::map<MusicType, extra2d::Ptr<extra2d::Sound>> ResLoader::soundMap_;
void ResLoader::init() {
auto &resources = extra2d::Application::instance().resources();
// 加载所有音效
soundMap_[MusicType::Click] = resources.loadSound("assets/sound/click.wav");
soundMap_[MusicType::Hit] = resources.loadSound("assets/sound/hit.wav");
soundMap_[MusicType::Fly] = resources.loadSound("assets/sound/fly.wav");
soundMap_[MusicType::Point] = resources.loadSound("assets/sound/point.wav");
soundMap_[MusicType::Swoosh] = resources.loadSound("assets/sound/swoosh.wav");
}
void ResLoader::playMusic(MusicType type) {
auto it = soundMap_.find(type);
if (it != soundMap_.end() && it->second) {
it->second->play();
}
}
} // namespace flappybird
```
### 在游戏中使用
```cpp
// GameScene.cpp - 得分时播放音效
if (pipeX <= birdX) {
score_++;
scoreNumber_->setNumber(score_);
firstPipe->scored = true;
ResLoader::playMusic(MusicType::Point); // 播放得分音效
}
// bird.cpp - 跳跃时播放音效
void Bird::jump() {
velocity_.y = jumpForce_;
ResLoader::playMusic(MusicType::Fly); // 播放飞翔音效
}
// GameOverLayer.cpp - 按钮点击时播放音效
restartBtn_->setOnClick([]() {
ResLoader::playMusic(MusicType::Click); // 播放点击音效
auto &app = extra2d::Application::instance();
app.scenes().replaceScene(extra2d::makePtr<GameScene>(),
extra2d::TransitionType::Fade, 0.5f);
});
```
### 推箱子音效管理器
2026-02-11 19:40:26 +08:00
```cpp
// audio_manager.h
#pragma once
#include <extra2d/extra2d.h>
namespace pushbox {
class AudioManager {
public:
static AudioManager& instance() {
static AudioManager instance;
return instance;
}
void init();
void setEnabled(bool enabled);
void playMoveSound();
void playBoxMoveSound();
void playWinSound();
private:
AudioManager() = default;
bool enabled_ = true;
extra2d::Ptr<extra2d::Sound> moveSound_;
extra2d::Ptr<extra2d::Sound> boxMoveSound_;
extra2d::Ptr<extra2d::Sound> winSound_;
};
} // namespace pushbox
```
```cpp
// audio_manager.cpp
#include "audio_manager.h"
namespace pushbox {
void AudioManager::init() {
auto& audio = extra2d::Application::instance().audio();
// 加载音效
moveSound_ = audio.loadSound("move", "assets/audio/manmove.wav");
boxMoveSound_ = audio.loadSound("boxmove", "assets/audio/boxmove.wav");
winSound_ = audio.loadSound("win", "assets/audio/win.wav");
}
void AudioManager::setEnabled(bool enabled) {
enabled_ = enabled;
if (!enabled) {
extra2d::Application::instance().audio().stopAll();
}
}
void AudioManager::playMoveSound() {
if (enabled_ && moveSound_) {
moveSound_->play();
}
}
void AudioManager::playBoxMoveSound() {
if (enabled_ && boxMoveSound_) {
boxMoveSound_->play();
}
}
void AudioManager::playWinSound() {
if (enabled_ && winSound_) {
winSound_->play();
}
}
} // namespace pushbox
```
## 使用音频管理器
```cpp
// main.cpp
int main(int argc, char** argv) {
// ... 初始化应用 ...
// 初始化音频管理器
pushbox::AudioManager::instance().init();
// ... 运行应用 ...
}
// PlayScene.cpp
void PlayScene::move(int dx, int dy, int direct) {
// ... 移动逻辑 ...
if (isBoxMoved) {
// 播放推箱子音效
pushbox::AudioManager::instance().playBoxMoveSound();
} else {
// 播放移动音效
pushbox::AudioManager::instance().playMoveSound();
}
}
```
## 音频开关控制
```cpp
// 在菜单中切换音效
void StartScene::onUpdate(float dt) {
auto& input = Application::instance().input();
// X键切换音效
if (input.isButtonPressed(GamepadButton::X)) {
g_SoundOpen = !g_SoundOpen;
AudioManager::instance().setEnabled(g_SoundOpen);
updateSoundIcon();
}
}
```
## 支持的音频格式
- WAV
- OGG
- MP3需要 SDL2_mixer 支持)
## 最佳实践
1. **使用单例管理器** - 集中管理音频资源
2. **预加载常用音效** - 在初始化时加载
3. **提供开关选项** - 让用户控制音效
4. **合理设置音量** - 避免音量过大
5. **及时卸载不用的音效** - 释放内存资源
## API 参考
### Sound 类
| 方法 | 说明 |
|------|------|
| `play()` | 播放音效 |
| `pause()` | 暂停播放 |
| `resume()` | 恢复播放 |
| `stop()` | 停止播放 |
| `isPlaying()` | 是否正在播放 |
| `isPaused()` | 是否已暂停 |
| `setVolume(float)` | 设置音量 (0.0-1.0) |
| `getVolume()` | 获取音量 |
| `setLooping(bool)` | 设置循环播放 |
| `isLooping()` | 是否循环播放 |
| `setPitch(float)` | 设置音调(当前不支持) |
| `getPitch()` | 获取音调 |
| `getDuration()` | 获取时长(当前不支持) |
| `getCursor()` | 获取播放位置(当前不支持) |
| `setCursor(float)` | 设置播放位置(当前不支持) |
### AudioEngine 类
| 方法 | 说明 |
|------|------|
| `getInstance()` | 获取单例实例 |
| `initialize()` | 初始化音频引擎 |
| `shutdown()` | 关闭音频引擎 |
| `loadSound(path)` | 加载音效(以路径为名称) |
| `loadSound(name, path)` | 加载音效(指定名称) |
| `getSound(name)` | 获取已加载的音效 |
| `unloadSound(name)` | 卸载指定音效 |
| `unloadAllSounds()` | 卸载所有音效 |
| `setMasterVolume(float)` | 设置主音量 |
| `getMasterVolume()` | 获取主音量 |
| `pauseAll()` | 暂停所有音效 |
| `resumeAll()` | 恢复所有音效 |
| `stopAll()` | 停止所有音效 |
## 总结
至此,你已经学习了 Extra2D 引擎的核心功能:
1. [快速开始](./01_Quick_Start.md) - 引擎基础
2. [场景系统](./02_Scene_System.md) - 场景管理
3. [节点系统](./03_Node_System.md) - 游戏对象
4. [资源管理](./04_Resource_Management.md) - 资源加载
5. [输入处理](./05_Input_Handling.md) - 输入控制
6. [碰撞检测](./06_Collision_Detection.md) - 空间索引
7. [UI 系统](./07_UI_System.md) - 界面控件
8. [音频系统](./08_Audio_System.md) - 音频播放
开始你的游戏开发之旅吧!