Files
2026-06-04 19:10:50 +08:00

237 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AudioSystem 使用说明
## 播放音效
### 基本播放
```csharp
// 通过 uint audioID 播放(推荐)
AudioSystem.Instance.Play(Cues.Play_sfx_ui_button_common);
// 通过 int 播放(便捷重载,内部转为 uint)
AudioSystem.Instance.Play(3);
// 带回调的播放(音频启动后回调)
AudioSystem.Instance.Play(Cues.Play_sfx_ui_button_common, () => Debug.Log("音效开始播放"));
```
`OCES.Audio.Cues` 类提供所有可用 audioID 常量,例如 `Cues.Play_sfx_ui_button_common`。通过代码补全即可快速访问全部已注册音效。
### 通过字符串播放(已废弃)
```csharp
[Obsolete("Use Play(uint) instead")]
AudioSystem.Instance.Play("sfx_ui_button_common");
```
字符串接口仅用于向后兼容。同名或容器内共享 ID 的资源会产生歧义,请始终使用 `uint` ID。
### 直接传入 AudioObject 播放
```csharp
AudioObject obj = /* 从某处获取 */;
AudioSystem.Instance.Play(obj, () => Debug.Log("播放完毕"));
```
Switch 类型的 Container 会自动解析当前状态对应的子节点。
### 在拍子/小节/网格上播放
```csharp
// CallbackFlags 可选值: MusicSyncBeat | MusicSyncBar | MusicSyncGrid
AudioSystem.Instance.PlayOnTrigger(Cues.Play_Beat, CallbackFlags.MusicSyncBeat);
```
音效会等到下一次对应节拍回调时播放。如果 `audioId` 本身也是同步回调的 ContainerBeat/Bar/Grid),该音效会被忽略,避免自触发循环。
---
## 停止音效
```csharp
AudioSystem.Instance.Stop(audioId);
```
停止指定 audioID 的所有正在播放的活跃实例。
---
## 修改游戏状态(驱动音乐/环境音)
```csharp
// 泛型接口,支持任意已注册的枚举类型
AudioSystem.Instance.SetState(Parameters.GameState.Game);
AudioSystem.Instance.SetState(MyCustomEnum.SomeState); // 需先通过 StateGroupRegistry 注册
```
`SetState` 内部触发 `MusicStateRouter` 全量匹配,根据 `MusicPath` / `AmbiencePath` 表格切换到对应的音乐与环境音 Container。
### 启动时的默认状态
- 在 Inspector 设置 `startWithMusic = true` 并指定 `startMusicWith`GameState 枚举值),`AudioSystem.Start()` 会自动调用 `SetState`
- 游戏启动时的首次状态设置**必须放在 `Start` 内**,晚一点可以,早了容易出问题。
- 若需在其他位置进行首次初始化,请注释掉 `AudioSystem.Start()` 中的相关代码。
### 开关
```csharp
AudioSystem.Instance.SetMusicVolume(float tatgetVolume) //设置音乐音量 -800
AudioSystem.Instance.SetSFXVolume(float tatgetVolume) //设置音效音量 -800
AudioSystem.Instance.SetMusicState(bool enable) // 启用/禁用音乐
AudioSystem.Instance.SetSFXState(bool enable) // 启用/禁用音效
HapticSytem.Instance.EnableHaptic(bool enable) // 启用/禁用触感系统
```
### Inspector 参数
| 字段 | 说明 |
|------|------|
| `startWithMusic` | 是否在 Start 时自动设置初始状态 |
| `startMusicWith` | 初始 GameState 值 |
| `logLevel` | 控制台日志级别(`Off` / `Log` / `Warning` / `Error` |
---
## 音乐同步回调
```csharp
// 订阅节拍回调(参数为当前正在播放的 ContainerId
AudioSystem.Instance.OnBeat += containerId => { };
AudioSystem.Instance.OnBar += containerId => { };
AudioSystem.Instance.OnGrid += containerId => { };
```
- **Beat**:每拍触发
- **Bar**:每小节触发(根据 `MusicContainer.TimeSig` 计算)
- **Grid**:每 N 小节触发(根据 `MusicContainer.Grid` 字段)
Blend Container 内如果有多个不同 BPM 的子段,回调会自动禁用。
---
## 获取当前活跃状态
```csharp
IReadOnlyDictionary<Type, Enum> states = AudioSystem.Instance.ActiveStates;
```
返回 `SetState` 设置的所有枚举类型及其当前值。可用于 Switch Container 的运行时状态查询。
---
## 设置高切(Lowpass Filter
```csharp
AudioSystem.Instance.SetLowpass(true); // 启用高切(440Hz
AudioSystem.Instance.SetLowpass(false); // 恢复正常(22000Hz
```
在需要凸显某个音效时,调用 `SetLowpass(true)` 将其它声音"放远"。切换过程中有平滑 Tween(时长由 `AudioExtendSettings.lowpassTweenDuration` 控制)。
---
## 修改音效播放属性
### 音量
```csharp
// 设置音量 (0.0 ~ 1.0)
AudioSystem.Instance.SetVolume(audioId, 0.5f);
// int 重载
AudioSystem.Instance.SetVolume(3, 0.8f);
// 重置为默认值
AudioSystem.Instance.ResetVolume(audioId);
```
`SetVolume` 会实时修改指定 audioID 的**所有活跃实例**的音量。超出 `[0, 1]` 范围会打印 Warning 并忽略。
### 音高
```csharp
// 设置音高 (-3.0 ~ 3.01.0 为正常音高)
AudioSystem.Instance.SetPitch(audioId, 1.5f);
// int 重载
AudioSystem.Instance.SetPitch(3, 0.8f);
// 重置为默认值
AudioSystem.Instance.ResetPitch(audioId);
```
`SetPitch` 会实时修改指定 audioID 的**所有活跃实例**的音高。**
**注意**`LoadType``Streaming` 的 AudioClip **不支持将 Pitch 设置为负值**
---
## 触感反馈(HapticSystem
触感系统由音效系统自动驱动(`AudioObject.Haptic` 配置不为空时自动触发)。手动调用仅用于调试:
```csharp
// 手动触发触感(调试用,会打印 Warning)
HapticSystem.Instance.Play(hapticId);
// 停止当前触感
HapticSystem.Instance.Stop();
```
四种触感类型:`Preset``Emphasis``Constant``Advance`
---
## MonoBehaviour 辅助组件
### PlaySoundBind
绑定 UI 事件以播放/停止/节拍触发音效:
- `PlaySound()` — 播放 `InputField` 中的 audioID
- `StopSound()` — 停止 `InputField` 中的 audioID
- `PlaySoundOnTrigger()` — 在节拍/小节/网格上播放(通过 `callbackFlags` 选择回调类型)
- Inspector 字段:`inputField`InputField 引用)、`callbackFlags`CallbackFlags
### SetStateBind
绑定按钮以切换游戏状态:
- `OnButtonPressed()` — 调用 `SetState(targetGameState)` + `SetLowpass(enableLowpass)`
- Inspector 字段:`targetGameState`Parameters.GameState)、`enableLowpass`bool)、`buttonText`Text 引用,自动替换占位符)
### SetPropertyBind
绑定 UI 事件以修改音效属性:
- `SetVolume()` — 设置音量
- `SetPitch()` — 设置音高
- `ResetVolume()` — 重置音量
- `ResetPitch()` — 重置音高
- Inspector 字段:`inputField`InputField 引用,填写 audioID)、`targetValue`float,目标值)
---
## 添加新的状态枚举
如果你的游戏需要自定义状态枚举(除 `Parameters.GameState` 外),需要:
1. 在 Excel 表格中配置对应的 `MusicPath` / `AmbiencePath` 条目,指定 `TypeId`
2. 在代码中注册:
```csharp
StateGroupRegistry.Register<MyCustomEnum>(typeId);
```
`Parameters.EnumIds.RegisterAllGameState()``AudioSystem.Awake()` 中自动调用,已注册默认的 `GameState`(TypeId=1)。自定义枚举的注册请在 `Awake` 或更早时机完成。
---
## 常见注意事项
1. **始终使用 uint ID 播放**:字符串接口已废弃,Container 内共享 ID 的 AudioClip 只能通过 ID 精确访问。
2. **Streaming 音频不支持负 Pitch**`SetPitch` 传入负值时 Streaming 剪辑无声。
3. **首次 SetState 放在 Start 里**:晚一点没问题,放在 `Awake` 中可能因初始化未完成而出错。
4. **Switch Container 依赖 ActiveStates**:确保在播放 Switch 类型 AudioObject 之前已调用 `SetState` 设置所需状态。
5. **Blend Container 内 BPM 不一致**:会导致 Beat/Bar/Grid 回调自动禁用。