一、功能概述
本笔记记录直接修改插件自带的场景播放其中 原始的 MediaPlayerUI 脚本,实现激活时自动重置播放器的功能。 我用的插件版本是 AVPro Video - Ultra Edition 2.7.3
修改后的脚本将具备以下特性:
-
激活 GameObject 时自动重置播放位置到开头
-
可配置是否在重置后自动开始播放
-
可配置重置前的延迟时间
-
视频播放结束后自动回到开头
-
保留原始脚本所有功能
二、修改步骤
1. 添加新变量
在类变量声明区域添加以下变量:
[Header("Activation Behavior")]
[Tooltip("Reset playback to beginning when enabled")]
[SerializeField] bool _resetOnEnable = true;
[Tooltip("Automatically start playback after reset")]
[SerializeField] bool _playOnReset = true;
[Tooltip("Delay before resetting after enable (seconds)")]
[SerializeField] float _resetDelay = 0.1f;
private Coroutine _resetCoroutine;
2. 添加 ResetPlayer 方法
在 Start()
方法后添加:
/// <summary>
/// Resets the player to beginning and optionally starts playback
/// </summary>
public void ResetPlayer()
{
if (_mediaPlayer == null || _mediaPlayer.Control == null)
{
Debug.LogWarning("MediaPlayer or Control is not available", this);
return;
}
// Reset playback position
_mediaPlayer.Control.Seek(0);
// Reset audio state
_audioVolume = 1f;
_audioFade = 1f;
_isAudioFadingUpToPlay = true;
_audioFadeTime = 0f;
ApplyAudioVolume();
// Update UI
UpdateVolumeSlider();
// Start playback if configured to do so
if (_playOnReset)
{
_mediaPlayer.Play();
// Trigger play feedback if overlay manager exists
if (_overlayManager)
{
_overlayManager.TriggerFeedback(OverlayManager.Feedback.Play);
}
}
else
{
_mediaPlayer.Pause();
}
// Ensure controls are visible
_controlsFade = 1f;
if (_controlsGroup != null)
{
_controlsGroup.alpha = 1f;
_controlsGroup.gameObject.SetActive(true);
}
// Update timeline slider
if (_sliderTime != null)
{
_sliderTime.value = 0f;
}
}
3. 修改/添加 OnEnable 方法
private void OnEnable()
{
if (_resetOnEnable)
{
// Start reset coroutine with small delay to ensure everything is initialized
if (_resetCoroutine != null)
{
StopCoroutine(_resetCoroutine);
}
_resetCoroutine = StartCoroutine(DelayedReset());
}
}
4. 添加 OnDisable 方法
private void OnDisable()
{
if (_resetCoroutine != null)
{
StopCoroutine(_resetCoroutine);
_resetCoroutine = null;
}
}
5. 添加 DelayedReset 协程
private IEnumerator DelayedReset()
{
yield return new WaitForSeconds(_resetDelay);
ResetPlayer();
}
6. 修改 Update 方法
// Check if video has finished playing
if (_mediaPlayer != null && _mediaPlayer.Control != null &&
_mediaPlayer.Control.IsFinished())
{
// Reset to beginning but don't auto-play
_mediaPlayer.Control.Seek(0);
_mediaPlayer.Pause();
// Update timeline slider
if (_sliderTime != null)
{
_sliderTime.value = 0f;
}
}
7. 修改 Awake 方法(可选)
void Awake()
{
#if UNITY_IOS
Application.targetFrameRate = 60;
#endif
// 确保在第一次启用时也会重置
if (_resetOnEnable && enabled && gameObject.activeInHierarchy)
{
StartCoroutine(DelayedReset());
}
}
三、使用说明
1. Inspector 配置
修改后,脚本的 Inspector 面板将显示新的配置选项:
-
Reset On Enable:是否在激活时重置
-
Play On Reset:重置后是否自动播放
-
Reset Delay:重置前的延迟时间(秒)
2. 代码调用
可以通过代码调用 ResetPlayer()
方法手动重置播放器:
GetComponent<MediaPlayerUI>().ResetPlayer();
3. 注意事项
-
修改后的脚本保留了所有原始功能
-
重置操作包括:播放位置、音频状态、UI 控件状态
-
视频播放结束后会自动回到开头并暂停
四、实现原理
-
激活重置:通过
OnEnable
触发重置协程 -
延迟处理:使用
DelayedReset
协程确保组件完全初始化 -
完整重置:
ResetPlayer
方法处理所有重置逻辑 -
播放结束检测:在
Update
中检测播放结束状态
五、适用场景
-
需要重复播放视频的场景
-
视频播放器需要频繁激活/禁用的场景
-
需要精确控制播放初始状态的场景
六、完整代码
// UnityEngine.UI was moved to a package in 2019.2.0
// Unfortunately no way to test for this across all Unity versions yet
// You can set up the asmdef to reference the new package, but the package doesn't
// existing in Unity 2017 etc, and it throws an error due to missing reference
#define AVPRO_PACKAGE_UNITYUI
#if (UNITY_2019_2_OR_NEWER && AVPRO_PACKAGE_UNITYUI) || (!UNITY_2019_2_OR_NEWER)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using RenderHeads.Media.AVProVideo;
using RenderHeads.Media.AVProVideo.Demos.UI;
//-----------------------------------------------------------------------------
// Copyright 2018-2021 RenderHeads Ltd. All rights reserved.
//-----------------------------------------------------------------------------
namespace RenderHeads.Media.AVProVideo.Demos
{
public class MediaPlayerUI : MonoBehaviour
{
[SerializeField] MediaPlayer _mediaPlayer = null;
[Header("Options")]
[SerializeField] float _keyVolumeDelta = 0.05f;
[SerializeField] float _jumpDeltaTime = 5f;
[SerializeField] bool _showOptions = true;
[SerializeField] bool _autoHide = true;
[SerializeField] float _userInactiveDuration = 1.5f;
[SerializeField] bool _useAudioFading = true;
[Header("Keyboard Controls")]
[SerializeField] bool _enableKeyboardControls = true;
[SerializeField] KeyCode KeyVolumeUp = KeyCode.UpArrow;
[SerializeField] KeyCode KeyVolumeDown = KeyCode.DownArrow;
[SerializeField] KeyCode KeyTogglePlayPause = KeyCode.Space;
[SerializeField] KeyCode KeyToggleMute = KeyCode.M;
[SerializeField] KeyCode KeyJumpForward = KeyCode.RightArrow;
[SerializeField] KeyCode KeyJumpBack = KeyCode.LeftArrow;
[Header("Optional Components")]
[SerializeField] OverlayManager _overlayManager = null;
[SerializeField] MediaPlayer _thumbnailMediaPlayer = null;
[SerializeField] RectTransform _timelineTip = null;
[Header("UI Components")]
[SerializeField] RectTransform _canvasTransform = null;
//[SerializeField] Image image = null;
[SerializeField] Slider _sliderTime = null;
[SerializeField] EventTrigger _videoTouch = null;
[SerializeField] CanvasGroup _controlsGroup = null;
[Header("UI Components (Optional)")]
[SerializeField] GameObject _liveItem = null;
[SerializeField] Text _textMediaName = null;
[SerializeField] Text _textTimeDuration = null;
[SerializeField] Slider _sliderVolume = null;
[SerializeField] Button _buttonPlayPause = null;
[SerializeField] Button _buttonVolume = null;
[SerializeField] Button _buttonSubtitles = null;
[SerializeField] Button _buttonOptions = null;
[SerializeField] Button _buttonTimeBack = null;
[SerializeField] Button _buttonTimeForward = null;
[SerializeField] RawImage _imageAudioSpectrum = null;
[SerializeField] GameObject _optionsMenuRoot = null;
[SerializeField] HorizontalSegmentsPrimitive _segmentsSeek = null;
[SerializeField] HorizontalSegmentsPrimitive _segmentsBuffered = null;
[SerializeField] HorizontalSegmentsPrimitive _segmentsProgress = null;
private bool _wasPlayingBeforeTimelineDrag;
private float _controlsFade = 1f;
private Material _playPauseMaterial;
private Material _volumeMaterial;
private Material _subtitlesMaterial;
private Material _optionsMaterial;
private Material _audioSpectrumMaterial;
private float[] _spectrumSamples = new float[128];
private float[] _spectrumSamplesSmooth = new float[128];
private float _maxValue = 1f;
private float _audioVolume = 1f;
private float _audioFade = 0f;
private bool _isAudioFadingUpToPlay = true;
private const float AudioFadeDuration = 0.25f;
private float _audioFadeTime = 0f;
private readonly LazyShaderProperty _propMorph = new LazyShaderProperty("_Morph");
private readonly LazyShaderProperty _propMute = new LazyShaderProperty("_Mute");
private readonly LazyShaderProperty _propVolume = new LazyShaderProperty("_Volume");
private readonly LazyShaderProperty _propSpectrum = new LazyShaderProperty("_Spectrum");
private readonly LazyShaderProperty _propSpectrumRange = new LazyShaderProperty("_SpectrumRange");
//cyqq
[Header("Activation Behavior")]
[Tooltip("Reset playback to beginning when enabled")]
[SerializeField] bool _resetOnEnable = true;
[Tooltip("Automatically start playback after reset")]
[SerializeField] bool _playOnReset = true;
[Tooltip("Delay before resetting after enable (seconds)")]
[SerializeField] float _resetDelay = 0.1f;
private Coroutine _resetCoroutine;
void Awake()
{
#if UNITY_IOS
Application.targetFrameRate = 60;
#endif
// 确保在第一次启用时也会重置
if (_resetOnEnable && enabled &