# 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` 本身也是同步回调的 Container(Beat/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) //设置音乐音量 (-80~0) AudioSystem.Instance.SetSFXVolume(float tatgetVolume) //设置音效音量 (-80~0) 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 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.0,1.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(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 回调自动禁用。