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

发布于:2025-04-22 ⋅ 阅读:(11) ⋅ 点赞:(0)

关键点

  • 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

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 音频播放状态

不同于 VideoPlayerAudioSource 并没有原生的播放完成事件。因此我们通过 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. 使用示例

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

5.总结与拓展建议

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

📌 推荐进一步拓展:

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

6. 结语

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

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


网站公告

今日签到

点亮在社区的每一天
去签到