feat: add PlayOnTrigger for music-synced audio playback

- Add PlayOnTrigger method to AudioSystem for scheduling audio playback on music sync events (beat/bar/grid)
- Rename ButtonInvoker to SetStateBind for better clarity
- Update PlaySoundBind to support both direct playback and trigger-based playback with callback flags
- Add CallbackFlags enum (MusicSyncBeat, MusicSyncBar, MusicSyncGrid)
- Update Metronome demo to use new callback flag naming convention
- Add test audio file sfx_notice_test.wav
- Update scene UI to demonstrate PlayOnTrigger functionality
This commit is contained in:
2026-04-16 14:39:58 +08:00
parent 0fb0c51f65
commit 813f4254c9
11 changed files with 99 additions and 127 deletions
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,23 @@
fileFormatVersion: 2
guid: 7fd46c0791afd4242a0ac5913b1be63b
AudioImporter:
externalObjects: {}
serializedVersion: 7
defaultSettings:
serializedVersion: 2
loadType: 0
sampleRateSetting: 0
sampleRateOverride: 44100
compressionFormat: 1
quality: 1
conversionMode: 0
preloadAudioData: 0
platformSettingOverrides: {}
forceToMono: 0
normalize: 1
loadInBackground: 0
ambisonic: 0
3D: 1
userData:
assetBundleName:
assetBundleVariant:
+9 -116
View File
@@ -1298,7 +1298,7 @@ MonoBehaviour:
m_HorizontalOverflow: 0
m_VerticalOverflow: 0
m_LineSpacing: 1
m_Text: PlaySound Direct
m_Text: PlaySound OnTrigger
--- !u!222 &1193187745
CanvasRenderer:
m_ObjectHideFlags: 0
@@ -1319,7 +1319,6 @@ GameObject:
- component: {fileID: 1371927796}
- component: {fileID: 1371927795}
- component: {fileID: 1371927794}
- component: {fileID: 1371927798}
- component: {fileID: 1371927797}
m_Layer: 5
m_Name: PlaySoundDirect
@@ -1327,7 +1326,7 @@ GameObject:
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 0
m_IsActive: 1
--- !u!224 &1371927793
RectTransform:
m_ObjectHideFlags: 0
@@ -1343,9 +1342,9 @@ RectTransform:
- {fileID: 1193187743}
m_Father: {fileID: 1667985901}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_AnchorMin: {x: 0, y: 1}
m_AnchorMax: {x: 0, y: 1}
m_AnchoredPosition: {x: 150, y: -608.3334}
m_AnchorMin: {x: 0, y: 0}
m_AnchorMax: {x: 0, y: 0}
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 160, y: 30}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!114 &1371927794
@@ -1392,21 +1391,9 @@ MonoBehaviour:
m_OnClick:
m_PersistentCalls:
m_Calls:
- m_Target: {fileID: 1371927798}
m_TargetAssemblyTypeName: UnityEngine.AudioSource, UnityEngine
m_MethodName: Play
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine
m_IntArgument: 0
m_FloatArgument: 0
m_StringArgument:
m_BoolArgument: 0
m_CallState: 2
- m_Target: {fileID: 1371927797}
m_TargetAssemblyTypeName: PlaySoundBind, Assembly-CSharp
m_MethodName: OnButtonPressed
m_MethodName: PlaySoundOnTrigger
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
@@ -1466,103 +1453,8 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3bdbaddf2c05142e19686a9a82ef92c3, type: 3}
m_Name:
m_EditorClassIdentifier:
callbackFlags: 2
inputField: {fileID: 1490886059}
--- !u!82 &1371927798
AudioSource:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1371927792}
m_Enabled: 1
serializedVersion: 4
OutputAudioMixerGroup: {fileID: -1744738308437188463, guid: 11793d92750e64286bcdd6a61eeec520, type: 2}
m_audioClip: {fileID: 8300000, guid: 95f3e694b4c5b4892871f69fd96b4b7f, type: 3}
m_PlayOnAwake: 0
m_Volume: 1
m_Pitch: 1
Loop: 0
Mute: 0
Spatialize: 0
SpatializePostEffects: 0
Priority: 128
DopplerLevel: 1
MinDistance: 1
MaxDistance: 500
Pan2D: 0
rolloffMode: 0
BypassEffects: 0
BypassListenerEffects: 0
BypassReverbZones: 0
rolloffCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
- serializedVersion: 3
time: 1
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
panLevelCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spreadCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 0
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
reverbZoneMixCustomCurve:
serializedVersion: 2
m_Curve:
- serializedVersion: 3
time: 0
value: 1
inSlope: 0
outSlope: 0
tangentMode: 0
weightedMode: 0
inWeight: 0.33333334
outWeight: 0.33333334
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
--- !u!1 &1394234347
GameObject:
m_ObjectHideFlags: 0
@@ -1649,7 +1541,7 @@ MonoBehaviour:
m_Calls:
- m_Target: {fileID: 1394234352}
m_TargetAssemblyTypeName: PlaySoundBind, Assembly-CSharp
m_MethodName: OnButtonPressed
m_MethodName: PlaySound
m_Mode: 1
m_Arguments:
m_ObjectArgument: {fileID: 0}
@@ -1709,6 +1601,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 3bdbaddf2c05142e19686a9a82ef92c3, type: 3}
m_Name:
m_EditorClassIdentifier:
callbackFlags: 0
inputField: {fileID: 1490886059}
--- !u!1 &1490886057
GameObject:
@@ -103,6 +103,7 @@ public static class AudioObjectDefinitions
{ "au_sfx_ui_button_corePlay_clear_cloud1", 70 },
{ "au_sfx_ui_button_corePlay_clear_cloud2", 70 },
{ "au_sfx_ui_button_corePlay_clear_cloud3", 70 },
{ "sfx_notice_test", 71 },
};
public static readonly HashSet<string> AmbiguousNames = new()
@@ -127,6 +127,49 @@ namespace OCES.Audio
ActiveStates = this.m_musicSystem.ActiveStates;
}
public void PlayOnTrigger(uint audioId, CallbackFlags callbackFlags)
{
Action<uint> callback = null;
callback = (id) =>
{
// 播放音效
Play(audioId);
// 取消订阅,确保只触发一次
switch (callbackFlags)
{
case CallbackFlags.MusicSyncBeat:
OnBeat -= callback;
break;
case CallbackFlags.MusicSyncBar:
OnBar -= callback;
break;
case CallbackFlags.MusicSyncGrid:
OnGrid -= callback;
break;
}
};
// 订阅对应的事件
switch (callbackFlags)
{
case CallbackFlags.MusicSyncBeat:
OnBeat += callback;
break;
case CallbackFlags.MusicSyncBar:
OnBar += callback;
break;
case CallbackFlags.MusicSyncGrid:
OnGrid += callback;
break;
default:
Debug.LogWarning($"[AudioSystem] Unknown callback flag '{callbackFlags}'." +
$"Audio Container with ID {audioId} will be ignored.");
break;
}
}
// ─────────────────────────────────────────────
// 初始化
// ─────────────────────────────────────────────
@@ -86,9 +86,10 @@ namespace OCES.Audio
public partial class MusicPath : IPathEntry { }
public partial class AmbiencePath : IPathEntry { }
public class SwitchEntry
public enum CallbackFlags
{
public uint SwitchValue;
public uint AudioObjectId;
MusicSyncBeat = 1,
MusicSyncBar = 2,
MusicSyncGrid = 3,
}
}
+7 -3
View File
@@ -3,6 +3,10 @@ using UnityEngine;
namespace OCES
{
/// <summary>
/// Drag this component to any game object.
/// Then you will get a metronome :)
/// </summary>
public class Metronome : MonoBehaviour
{
void Start()
@@ -10,17 +14,17 @@ namespace OCES
AudioSystem.Instance.OnBeat += u =>
{
AudioSystem.Instance.Play(52);
Debug.Log($"Container {u} is OnBeat");
Debug.Log($"Container {u} is MusicSyncBeat");
};
AudioSystem.Instance.OnBar += u =>
{
AudioSystem.Instance.Play(53);
Debug.Log($"Container {u} is OnBar");
Debug.Log($"Container {u} is MusicSyncBar");
};
AudioSystem.Instance.OnGrid += u =>
{
AudioSystem.Instance.Play(54);
Debug.Log($"Container {u} is OnGrid");
Debug.Log($"Container {u} is MusicSyncGrid");
};
}
}
+11 -4
View File
@@ -2,16 +2,23 @@ using System.Collections;
using System.Collections.Generic;
using OCES.Audio;
using UnityEngine;
using UnityEngine.Serialization;
using UnityEngine.UI;
public class PlaySoundBind : MonoBehaviour
{
public CallbackFlags callbackFlags;
public InputField inputField;
public void OnButtonPressed()
public void PlaySound()
{
uint.TryParse(this.inputField.text, out uint hapticId);
AudioSystem.Instance.Play(hapticId);
uint.TryParse(this.inputField.text, out uint audioId);
AudioSystem.Instance.Play(audioId);
}
public void PlaySoundOnTrigger()
{
uint.TryParse(this.inputField.text, out uint audioId);
AudioSystem.Instance.PlayOnTrigger(audioId, this.callbackFlags);
}
}
@@ -5,7 +5,7 @@ using UnityEngine.Audio;
namespace OCES
{
public class ButtonInvoker : MonoBehaviour
public class SetStateBind : MonoBehaviour
{
public GameState targetGameState;
public bool enableLowpass;