【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

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

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

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

<think>好的,我现在需要帮用户解决关于UnityVideoPlayer的使用问题,他们想要一个教程或者常见问题的解决方案。首先,我得整理一下Unity VideoPlayer的基本用法,包括如何添加组件、设置视频源以及控制播放。然后,我需要考虑用户可能遇到的常见问题,比如视频不显示、声音不同步、平台兼容性等,并根据提供的引用资料给出解决方案。 首先,教程部分需要分步骤,让用户能够一步步操作。比如,添加VideoPlayer组件、选择视频源类型、处理不同平台下的路径问题。这部分要确保语言简洁,步骤明确。 接下来是常见问题。根据用户提供的引用,引用[1]提到了兼容性问题,不同平台支持的格式不同,可能需要检查编解码器。引用[2]提到了使用插件时的事件处理,比如用lambda表达式添加监测事件。引用[3]涉及到焦点恢复后的处理,比如OnApplicationFocus和生命周期方法。引用[4]提到版本差异,特别是2020版引入的新Plugin规则可能导致问题,需要调整设置。 我需要将这些问题分类,比如兼容性问题、播放控制、平台相关问题、版本差异。每个问题下给出对应的解决方案,并引用对应的参考资料。例如,视频无法播放可能是因为格式不支持,解决方案是检查编解码器,并参考引用[1]。如果使用插件时事件处理不当,参考引用[2]的建议使用lambda表达式。对于Android平台黑屏,可能需要检查焦点恢复后的处理,参考引用[3]。版本问题则参考引用[4]调整Plugin设置。 另外,用户可能还关心如何预加载视频、循环播放、全屏控制等进阶功能,这些也需要在教程或问题解决中提到。同时,确保所有代码示例正确,使用中文注释,避免语法错误。 最后,生成相关问题,帮助用户进一步探索,比如性能优化、不同平台的处理、内存管理等。这些问题需要现有内容相关,引导用户深入阅读。</think>### Unity VideoPlayer 使用教程常见问题解决方案 #### **一、基础使用教程** 1. **添加 VideoPlayer 组件** - 在 Unity 编辑器中,选中需要播放视频的 GameObject,点击菜单栏 `Component > Rendering > Video Player`。 - 设置视频源类型(Video Source): - **Video Clip**:直接拖拽 Unity 支持的视频文件(如 `.mp4`)到该字段。 - **URL**:输入视频文件的绝对路径或网络地址(需注意跨平台路径差异)。 2. **控制视频播放** ```csharp using UnityEngine; using UnityEngine.Video; public class VideoController : MonoBehaviour { public VideoPlayer videoPlayer; void Start() { videoPlayer.Play(); // 开始播放 videoPlayer.Pause(); // 暂停 videoPlayer.Stop(); // 停止 } } ``` 3. **处理视频事件** 使用委托或 lambda 表达式监听事件(如播放完成): ```csharp videoPlayer.loopPointReached += source => Debug.Log("视频播放完成"); ``` --- #### **二、常见问题解决方案** 1. **视频无法显示** - **原因**:视频格式或编解码器不兼容目标平台[^1]。 - **解决**: - 检查目标平台支持的格式(如 Android 推荐 H.264,iOS 推荐 MPEG-4)。 - 在 Unity 编辑器中选择视频文件,勾选 `Transcode` 选项进行转码适配。 2. **声音不同步或缺失** - **原因**:音频轨道未正确关联。 - **解决**: ```csharp videoPlayer.audioOutputMode = VideoAudioOutputMode.AudioSource; videoPlayer.SetTargetAudioSource(0, GetComponent<AudioSource>()); ``` 3. **Android 平台黑屏或卡顿** - **原因**:应用失去焦点后未正确处理生命周期[^3]。 - **解决**:在 `OnApplicationFocus` 中恢复播放: ```csharp void OnApplicationFocus(bool hasFocus) { if (hasFocus) videoPlayer.Play(); } ``` 4. **Unity 2020+ 版本兼容性问题** - **原因**:Plugin 文件规则变更导致加载失败[^4]。 - **解决**:将视频文件放入 `Assets/StreamingAssets` 文件夹,并使用 `Application.streamingAssetsPath` 访问路径。 5. **插件事件触发** - **原因**:委托未正确绑定[^2]。 - **解决**:使用 lambda 表达式简化事件绑定: ```csharp videoPlayer.prepareCompleted += _ => Debug.Log("视频准备完成"); ``` --- #### **三、进阶技巧** 1. **预加载视频** ```csharp videoPlayer.Prepare(); // 异步预加载 videoPlayer.prepareCompleted += _ => videoPlayer.Play(); ``` 2. **循环播放全屏控制** ```csharp videoPlayer.isLooping = true; // 开启循环 Screen.fullScreen = true; // 全屏播放 ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

EQ-雪梨蛋花汤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值