使用 Unity VideoPlayer 在按键时缓慢 pause/resume 视频

Using Unity VideoPlayer to slowly pause/resume the videos when key pressed

我正在编写一个脚本,其中有一个视频分为 3 个部分,分别有 3 个音频,运行 一个在前一个完成后(视频和音频),但是视频只需要在按住键时播放(在我的例子中是 "space")我在按下 space:

时成功地播放了视频和音频
if (Input.GetButton ("Jump")) {
                vp.Play ();
                if (!ASource.isPlaying) {
                    ASource.Play ();
                }

不在时暂停:

else {
                vp.Pause ();
                ASource.Pause ();

            }

但这很难,我正在寻找一种使其顺利进行的方法pause/resume,我尝试制作一个函数:

public void videoPause() {
        for (i = 0; i < 10; i++) {
            vp.playbackSpeed = vp.playbackSpeed / i;
        }

    }

与简历相同,但使用 * 而不是和 i-- 但它没有用,请知道如何让它工作吗?

看到这个:

for (i = 0; i < 10; i++) {
    vp.playbackSpeed = vp.playbackSpeed / i;
}

您在一帧中执行所有这些操作,因此无法看到效果。将其移至协程函数,然后在每个 for 循环后 yield 然后您将看到效果。

像这样:

for (i = 0; i < 10; i++) {
    vp.playbackSpeed = vp.playbackSpeed / i;
    yield return null; //Wait for a frame
    //OR
    yield return new WaitForSeconds(0.1f); //Wait for 0.1 sec
}

您现在应该可以看到该代码的效果,但它不会流畅。


做什么:

lerp 函数通常用于这样的事情。 Mathf.Lerp 适合这个。

VideoPlayer.playbackSpeed 的 default/normal 值为 12的值比较快,0的值比较慢。

  • 当你想暂停 VideoPlayer 时,从 10 到 放慢速度然后暂停。
  • 当你想恢复 VideoPlayer 时,慢慢恢复然后从 01

这里有两个协同程序函数,它们应该缓慢而平稳地处理暂停和恢复功能。

IEnumerator SmoothlyPauseOverTimeCOR(VideoPlayer targetVp, float duration)
{
    float counter = 0;
    //Get the current playbackSpeed of the VideoPlayer 
    float startSpeed = targetVp.playbackSpeed;

    //We want to go to 0 but within duration
    float endSpeed = 0;

    //Normal speed to slow speed
    while (counter < duration)
    {
        counter += Time.deltaTime;
        targetVp.playbackSpeed = Mathf.Lerp(startSpeed, endSpeed, counter / duration);
        yield return null;
    }
    //Now, do the actual pause
    targetVp.Pause();
    executingPause = false;
}

IEnumerator SmoothlyResumeOverTimeCOR(VideoPlayer targetVp, float duration)
{
    float counter = 0;
    //Get the current playbackSpeed of the VideoPlayer 
    //float startSpeed = targetVp.playbackSpeed;
    float startSpeed = 0f;

    //We want to go to 1 but within duration
    float endSpeed = 1;


    //Do the actual resume
    targetVp.Play();

    //Slow speed to normal Speed
    while (counter < duration)
    {
        counter += Time.deltaTime;
        targetVp.playbackSpeed = Mathf.Lerp(startSpeed, endSpeed, counter / duration);
        yield return null;
    }
}

在开始新协程之前,您需要确保之前的协程函数不是运行。停止旧的,然后在需要时启动新的。下面的两个函数应该处理这个问题并能够安全地调用上面的函数:

Coroutine pauseCoroutine;
Coroutine resumeCoroutine;

bool executingPause = false;

void SmoothlyPauseOverTime(VideoPlayer targetVp, float duration)
{
    //Stop old coroutines before starting a new one
    if (pauseCoroutine != null)
        StopCoroutine(pauseCoroutine);

    if (resumeCoroutine != null)
        StopCoroutine(resumeCoroutine);


    executingPause = true;
    pauseCoroutine = StartCoroutine(SmoothlyPauseOverTimeCOR(targetVp, duration));
}

void SmoothlyResumeOverTime(VideoPlayer targetVp, float duration)
{
    if (pauseCoroutine != null)
        StopCoroutine(pauseCoroutine);

    //Stop old coroutines before starting a new one
    if (resumeCoroutine != null)
        StopCoroutine(resumeCoroutine);

    resumeCoroutine = StartCoroutine(SmoothlyResumeOverTimeCOR(targetVp, duration));
}

你的 Update 函数:

void Update()
{
    if (Input.GetButton("Jump"))
    {
        if (!vp.isPlaying)
        {
            Debug.Log("Resumed Playing");
            SmoothlyResumeOverTime(vp, 0.8f);
        }
    }
    else
    {
        if (!executingPause && vp.isPlaying)
        {
            Debug.Log("Paused Playing");
            SmoothlyPauseOverTime(vp, 0.8f);
        }
    }
}

你的 Start 函数:

基于 。它准备视频但不播放它,直到在上面的 Update 函数中按下 Space 键:

//Raw Image to Show Video Images [Assign from the Editor]
public RawImage image;
//Video To Play [Assign from the Editor]
public VideoClip videoToPlay;

private VideoPlayer vp;
private VideoSource videoSource;

//Audio
private AudioSource aS;

// Use this for initialization
void Start()
{
    Application.runInBackground = true;
    StartCoroutine(playVideo());
}

IEnumerator playVideo()
{
    //Add VideoPlayer to the GameObject
    vp = gameObject.AddComponent<VideoPlayer>();

    //Add AudioSource
    aS = gameObject.AddComponent<AudioSource>();

    //Disable Play on Awake for both Video and Audio
    vp.playOnAwake = false;
    aS.playOnAwake = false;

    //We want to play from video clip not from url
    vp.source = VideoSource.VideoClip;

    //Set Audio Output to AudioSource
    vp.audioOutputMode = VideoAudioOutputMode.AudioSource;

    //Assign the Audio from Video to AudioSource to be played
    vp.EnableAudioTrack(0, true);
    vp.SetTargetAudioSource(0, aS);

    //Set video To Play then prepare Audio to prevent Buffering
    vp.clip = videoToPlay;
    vp.Prepare();

    //Wait until video is prepared
    while (!vp.isPrepared)
    {
        Debug.Log("Preparing Video");
        yield return null;
    }

    Debug.Log("Done Preparing Video");

    //Assign the Texture from Video to RawImage to be displayed
    image.texture = vp.texture;
}

用法:

public VideoPlayer vp;

.......

将在 0.8 秒内缓慢暂停

SmoothlyPauseOverTime(vp, 0.8f);

将在 0.8 秒内缓慢恢复

SmoothlyResumeOverTime(vp, 0.8f);

videoPause 方法中的 for 循环将 运行 一次全部完成,而不是按照您想要的方式顺利进行。您可以尝试在一段时间内(比如 5 秒)在更新方法中更新播放速度。像这样

// set when the pause is triggered
videoPauseTime = Time.realtimeSinceStartup;
// duration in seconds to smoothen the pause
duration = 5

public void Update() {
    float t = (Time.realtimeSinceStartup - videoPauseTime) / duration;
    if(t>1.0f)
        t = 1.0f;
    vp.playbackSpeed = Mathf.Lerp (vp.playbackSpeed,0.0f,t)
}

请注意,此代码仅供说明之用,t 将超过 1.0,这是您不想要的;因此条件 t > 1.0f。另外,我假设 playbackSpeed 为 0 会使视频停止播放。