關鍵點
- Unity VideoPlayer 播放結束事件
- Unity AudioSource 播放檢測
Unity音視頻播放監聽器封裝筆記:VideoPlayer + AudioSource事件觸發與編輯器擴展
在 Unity 的多媒體開發中,我們經常需要監聽 VideoPlayer 或 AudioSource 的播放狀態,以便在開始播放或播放結束時觸發一系列操作,例如切換 UI、播放動畫、調用某腳本的方法等。
為了提升開發效率與復用性,本文記錄如何封裝 可復用、可配置、可掛載 UnityEvent 的監聽器組件,并通過 自定義 Inspector 實現良好的編輯器體驗。
1. 監聽 VideoPlayer 播放事件并觸發腳本方法
Unity 的 VideoPlayer
提供了兩個關鍵事件:
started
:視頻開始播放loopPointReached
:視頻播放完成(非循環模式)
我們封裝一個腳本 VideoPlayerEventListener.cs
來監聽上述事件,并掛載 UnityEvent,供你在 Inspector 中拖拽執行目標方法(如 腳本A.Exec()
)。
VideoPlayerEventListener.cs
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Video;[RequireComponent(typeof(VideoPlayer))]
public class VideoPlayerEventListener : MonoBehaviour
{[Header("視頻開始播放時觸發")]public UnityEvent onVideoStarted;[Header("視頻播放完成時觸發")]public UnityEvent onVideoEnded;private VideoPlayer videoPlayer;private bool hasStarted = false;void Awake(){videoPlayer = GetComponent<VideoPlayer>();}void OnEnable(){videoPlayer.started += OnVideoStarted;videoPlayer.loopPointReached += OnVideoEnded;}void OnDisable(){videoPlayer.started -= OnVideoStarted;videoPlayer.loopPointReached -= OnVideoEnded;}private void OnVideoStarted(VideoPlayer vp){if (!hasStarted){hasStarted = true;onVideoStarted?.Invoke();}}private void OnVideoEnded(VideoPlayer vp){hasStarted = false;onVideoEnded?.Invoke();}
}
2. 自定義 Inspector 提升編輯器體驗
為了讓 UnityEvent 在 Inspector 中更直觀易用,我們還封裝了一個自定義編輯器:
VideoPlayerEventListenerEditor.cs
using UnityEditor;
using UnityEngine;[CustomEditor(typeof(VideoPlayerEventListener))]
public class VideoPlayerEventListenerEditor : Editor
{SerializedProperty onVideoStarted;SerializedProperty onVideoEnded;void OnEnable(){onVideoStarted = serializedObject.FindProperty("onVideoStarted");onVideoEnded = serializedObject.FindProperty("onVideoEnded");}public override void OnInspectorGUI(){serializedObject.Update();var videoPlayer = (target as VideoPlayerEventListener).GetComponent<UnityEngine.Video.VideoPlayer>();if (videoPlayer == null){EditorGUILayout.HelpBox("缺少 VideoPlayer 組件。", MessageType.Error);}else{EditorGUILayout.HelpBox("監聽 VideoPlayer 播放狀態,并觸發 UnityEvent。", MessageType.Info);EditorGUILayout.PropertyField(onVideoStarted, new GUIContent("🎬 視頻開始播放"));EditorGUILayout.PropertyField(onVideoEnded, new GUIContent("🏁 視頻播放結束"));}serializedObject.ApplyModifiedProperties();}
}
將此腳本放入
Editor
文件夾中即可自動生效。
3. 監聽 AudioSource 音頻播放狀態
不同于 VideoPlayer
,AudioSource
并沒有原生的播放完成事件。因此我們通過 Update()
方法持續檢測播放狀態,并提供播放進度(progress
)供 UI 顯示。
AudioSourceEventListener.cs
using UnityEngine;
using UnityEngine.Events;[RequireComponent(typeof(AudioSource))]
public class AudioSourceEventListener : MonoBehaviour
{[Header("音頻開始播放時觸發")]public UnityEvent onAudioStarted;[Header("音頻播放完成時觸發")]public UnityEvent onAudioEnded;[Range(0f, 1f), Tooltip("當前播放進度 (僅查看)")]public float progress;private AudioSource audioSource;private bool hasStarted = false;private bool hasEnded = false;void Awake(){audioSource = GetComponent<AudioSource>();}void Update(){if (audioSource.clip == null)return;if (!hasStarted && audioSource.isPlaying){hasStarted = true;hasEnded = false;onAudioStarted?.Invoke();}if (audioSource.isPlaying){progress = audioSource.time / audioSource.clip.length;}if (hasStarted && !audioSource.isPlaying && !hasEnded && audioSource.time >= audioSource.clip.length){hasEnded = true;onAudioEnded?.Invoke();}}
}
AudioSourceEventListenerEditor.cs
using UnityEditor;
using UnityEngine;[CustomEditor(typeof(AudioSourceEventListener))]
public class AudioSourceEventListenerEditor : Editor
{SerializedProperty onAudioStarted;SerializedProperty onAudioEnded;SerializedProperty progress;void OnEnable(){onAudioStarted = serializedObject.FindProperty("onAudioStarted");onAudioEnded = serializedObject.FindProperty("onAudioEnded");progress = serializedObject.FindProperty("progress");}public override void OnInspectorGUI(){serializedObject.Update();EditorGUILayout.HelpBox("監聽 AudioSource 播放狀態,并觸發 UnityEvent。", MessageType.Info);EditorGUILayout.PropertyField(onAudioStarted, new GUIContent("🎧 音頻開始播放"));EditorGUILayout.PropertyField(onAudioEnded, new GUIContent("🏁 音頻播放結束"));EditorGUILayout.Space();EditorGUILayout.LabelField("📊 播放進度", EditorStyles.boldLabel);EditorGUI.ProgressBar(EditorGUILayout.GetControlRect(), progress.floatValue, $"{(progress.floatValue * 100f):0.0}%");serializedObject.ApplyModifiedProperties();}
}
4. 使用示例
- 在一個 GameObject 上添加
VideoPlayerEventListener
或AudioSourceEventListener
。 - 選擇你需要監聽的事件(開始/結束)。
- 點擊
+
添加響應函數(如某個腳本的Exec()
方法)。 - 運行時自動回調,不需要手動注冊監聽器。
5.總結與拓展建議
通過以上封裝,我們實現了可復用的播放監聽邏輯,統一用 UnityEvent 掛載,完全無需寫代碼也能實現播放回調,特別適合策劃/UI 場景中使用。
📌 推薦進一步拓展:
- 播放進度回調事件(支持 float 參數)。
- 播放完自動播放下一個文件。
- 可視化播放進度 UI(Slider/圓環等)。
- 支持 AssetBundle 動態加載音視頻資源。
6. 結語
音視頻播放作為交互中重要的一環,其狀態監聽和回調封裝將極大提升項目開發效率。希望這套封裝組件可以幫助你打造更高效、模塊化的多媒體播放系統。
如果你覺得有幫助,歡迎點贊、收藏并關注!