使用 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 值为 1
。 2
的值比较快,0
的值比较慢。
- 当你想暂停
VideoPlayer
时,从 1
到 0
到
放慢速度然后暂停。
- 当你想恢复
VideoPlayer
时,慢慢恢复然后从 0
到 1
。
这里有两个协同程序函数,它们应该缓慢而平稳地处理暂停和恢复功能。
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 会使视频停止播放。
我正在编写一个脚本,其中有一个视频分为 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 值为 1
。 2
的值比较快,0
的值比较慢。
- 当你想暂停
VideoPlayer
时,从1
到0
到 放慢速度然后暂停。 - 当你想恢复
VideoPlayer
时,慢慢恢复然后从0
到1
。
这里有两个协同程序函数,它们应该缓慢而平稳地处理暂停和恢复功能。
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 会使视频停止播放。