【Unity笔记】Unity音视频播放监听器封装笔记:VideoPlayer + AudioSource事件触发与编辑器扩展

关键点

  • Unity VideoPlayer 播放结束事件
  • Unity AudioSource 播放检测

Unity音视频播放监听器封装笔记:VideoPlayer + AudioSource事件触发与编辑器扩展

在 Unity 的多媒体开发中,我们经常需要监听 VideoPlayerAudioSource 的播放状态,以便在开始播放或播放结束时触发一系列操作,例如切换 UI、播放动画、调用某脚本的方法等。

为了提升开发效率与复用性,本文记录如何封装 可复用、可配置、可挂载 UnityEvent 的监听器组件 ,并通过 自定义 Inspector 实现良好的编辑器体验。


1. 监听 VideoPlayer 播放事件并触发脚本方法

Unity 的 VideoPlayer 提供了两个关键事件:

  • started:视频开始播放
  • loopPointReached:视频播放完成(非循环模式)

我们封装一个脚本 VideoPlayerEventListener.cs 来监听上述事件,并挂载 UnityEvent,供你在 Inspector 中拖拽执行目标方法(如 脚本A.Exec())。

VideoPlayerEventListener.cs

csharp 复制代码
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

csharp 复制代码
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 音频播放状态

不同于 VideoPlayerAudioSource 并没有原生的播放完成事件。因此我们通过 Update() 方法持续检测播放状态,并提供播放进度(progress)供 UI 显示。

AudioSourceEventListener.cs

csharp 复制代码
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

csharp 复制代码
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. 使用示例

  1. 在一个 GameObject 上添加 VideoPlayerEventListenerAudioSourceEventListener
  2. 选择你需要监听的事件(开始/结束)。
  3. 点击 + 添加响应函数(如某个脚本的 Exec() 方法)。
  4. 运行时自动回调,不需要手动注册监听器。

5.总结与拓展建议

通过以上封装,我们实现了可复用的播放监听逻辑,统一用 UnityEvent 挂载,完全无需写代码也能实现播放回调,特别适合策划/UI 场景中使用。

📌 推荐进一步拓展:

  • 播放进度回调事件(支持 float 参数)。
  • 播放完自动播放下一个文件。
  • 可视化播放进度 UI(Slider/圆环等)。
  • 支持 AssetBundle 动态加载音视频资源。

6. 结语

音视频播放作为交互中重要的一环,其状态监听和回调封装将极大提升项目开发效率。希望这套封装组件可以帮助你打造更高效、模块化的多媒体播放系统。

如果你觉得有帮助,欢迎点赞、收藏并关注!

相关推荐
wuxuanok几秒前
Web后端开发-分层解耦
java·笔记·后端·学习
wuxuanok44 分钟前
Web后端开发-请求响应
java·开发语言·笔记·学习
Thomas_YXQ1 小时前
Unity3D游戏内存优化指南
游戏·unity·职场和发展·性能优化·蓝桥杯·游戏引擎·unity3d
chillxiaohan1 小时前
Unity接入Steamworks.NET实现通信功能
unity
诗句藏于尽头1 小时前
内网使用rustdesk搭建远程桌面详细版
笔记
蜡笔小电芯1 小时前
【C语言】指针与回调机制学习笔记
c语言·笔记·学习
丰锋ff2 小时前
瑞斯拜考研词汇课笔记
笔记
DKPT3 小时前
Java享元模式实现方式与应用场景分析
java·笔记·学习·设计模式·享元模式
KoiHeng6 小时前
操作系统简要知识
linux·笔记
karmueo466 小时前
视频序列和射频信号多模态融合算法Fusion-Vital解读
算法·音视频·多模态