关键点
- 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. 结语
音视频播放作为交互中重要的一环,其状态监听和回调封装将极大提升项目开发效率。希望这套封装组件可以帮助你打造更高效、模块化的多媒体播放系统。
如果你觉得有帮助,欢迎点赞、收藏并关注!