当前位置:   article > 正文

unity3d 关于游戏暂停_unity 暂停 fixedupdate

unity 暂停 fixedupdate

前提条件:在项目中用过Time.timeScale = 0来实现游戏暂停

问题: 暂停游戏后,暂停界面的按钮可能需要播放一个idle时的动画,Time.timeScale=0 会影响动画播放。

受Time.timeScale影响的因素:

1.物理模拟. FixedUpdate - 当Time.timeScale=0时,FixedUpdate 函数不会被执行,但是Update函数是会执行的。

2.Coroutines. - Time.timeScale=0 协程函数不会停止,但是会停止WaitForSeconds. 协成函数还是会每一帧都触发,但是WaitForSeconds使用的是当前的Time.deltaTime会变成0

3.Invoke 和 InvokeRepeating. -延迟一段时间后掉用指定函数.

4.Particle System 粒子系统.

5.Animations. -动画. 如果我们使用的是Animator,可以设置动画忽略Time.timeScale带来的影响. 只需要把UpdateMode设置为UnScaled Time。

timeScale表示游戏中时间流逝快慢的尺度。这个参数是用来做慢动作效果的。
对于将timeScale设置为0的情况,仅只有一个补充说明。
在实际使用中,通过设置timeScale来实现慢动作特效,是一种相当简洁且不带任何副作用的方法.
但是当将timeScale设置为0来实现暂停时,由于时间不再流逝,所有和时间有关的功能都将停止,有些时候这正是我们想要的,因为毕竟是暂停。
但是副作用也随之而来,在暂停时各种动画和粒子效果都将无法播放(因为是时间相关的),FixedUpdate也将不再被调用。
那么我又如何通过timeScale来实现上面的效果呢?
刚好realtimeSinceStartup 与 timeScale 就无关,也就是说realtimeSinceStartup 不受timeScale 的影响。
因此realtimeSinceStartup 也就成了解决在暂停下的动画和粒子效果的救命稻草。对于Unity动画,
在每一帧,根据实际时间寻找相应帧并采样显示的方法来模拟动画,

public static IEnumerator Play( this Animation animation, string clipName, bool ignoreTimeScale, Action onComplete )
{
//We don't want to use timeScale, so we have to animate by frame..
if(ignoreTimeScale)
{
AnimationState _currState = animation[clipName];
bool isPlaying = true;

float _progressTime = 0F;
float _timeAtLastFrame = 0F;
float _timeAtCurrentFrame = 0F;
bool _inReversePlaying = false;

float _deltaTime = 0F;
animation.Play(clipName);
_timeAtLastFrame = Time.realtimeSinceStartup;

while (isPlaying) {
_timeAtCurrentFrame = Time.realtimeSinceStartup;
_deltaTime = _timeAtCurrentFrame - _timeAtLastFrame;
_timeAtLastFrame = _timeAtCurrentFrame; 

_progressTime += _deltaTime;

_currState.normalizedTime = _inReversePlaying ? 1.0f - (_progressTime / _currState.length) 
: _progressTime / _currState.length; 
animation.Sample();

if (_progressTime >= _currState.length) {
switch (_currState.wrapMode) {
case WrapMode.Loop:
//Loop anim, continue.
_progressTime = 0.0f;
break;
case WrapMode.PingPong:
//PingPong anim, reversing continue.
_progressTime = 0.0f;
_inReversePlaying = !_inReversePlaying;
break;
case WrapMode.ClampForever:
//ClampForever anim, keep the last frame.
break;
case WrapMode.Default:
//We don't know how to handle it.
//In most time, this means it's a Once anim.
//Animation should be played with wrap mode specified.
Debug.LogWarning("A Default Anim Finished. Animation should be played with wrap mode specified.");
isPlaying = false;
break;
default:
//Once anim, kill it.
isPlaying = false;
break;
}
}
yield return new WaitForEndOfFrame();
}
yield return null;

if(onComplete != null) {
onComplete();
} 
} else {
if (onComplete != null) {
Debug.LogWarning("onComplete will not be called when you set \"ignoreTimeScale\" to true. Use Unity's animation handler instead!)");
animation.Play(clipName);
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

注:上面这段代码只对Animation有效,那针对Animator我们又如何在timeScale =0的情况下正常播放动画呢?

如果你是想游戏部分暂停,可以把暂停的部分写到FixedUpdate函数里面,不暂停写到Update函数。

float pauseTime =2f;
public void Pause()
    {
        if (isProp) {
            pauseTime -= Time.fixedDeltaTime;
            if (pauseTime <= 0) {
                isProp = false;
                pauseTime = 1f;
                Time.timeScale = 1;
            }
        }
    }
    这个是局部暂停的代码。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/633397
推荐阅读
相关标签
  

闽ICP备14008679号