【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. 结语

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

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

相关推荐
Zik----14 分钟前
简单的Unity漫游场景搭建
unity·游戏引擎
崎岖Qiu18 分钟前
【计算机网络 | 第十篇】以太网的 MAC 层
网络·笔记·计算机网络·mac地址
愚公搬代码20 分钟前
【愚公系列】《AI短视频创作一本通》020-AI短视频创作实例精解(文旅宣传AI短视频实例精解)
人工智能·音视频
有位神秘人25 分钟前
Android获取设备中本地音频
android·音视频
BlackWolfSky26 分钟前
鸿蒙高级课程笔记2—应用性能优化
笔记·华为·harmonyos
硫酸锌0127 分钟前
使用ffmpeg合并文件夹内的所有*.mp4格式视频
ffmpeg·音视频
玄同76534 分钟前
Python Random 模块深度解析:从基础 API 到 AI / 大模型工程化实践
人工智能·笔记·python·学习·算法·语言模型·llm
符哥200838 分钟前
C++ 适合初学者的学习笔记整理
c++·笔记·学习
ujainu42 分钟前
让笔记触手可及:为 Flutter + OpenHarmony 鸿蒙记事本添加实时搜索(二)
笔记·flutter·openharmony
源文雨44 分钟前
shell调用ffmpeg递归转换所有wav至flac的脚本
ffmpeg·bash·音视频·音频·unix·shell·音频编码