在游戏开发中我们一般都需要涉及到一个功能:游戏暂停,但是这里指的暂停仅仅是核心模块的暂停,并不是整个游戏都暂停,比如一些UI和UI上的动画与特效是不能被暂停的,整个游戏都暂停了玩家该如何继续游戏呢。
这里我们主要讨论Unity的游戏暂停实现。
使用timeScale
我们通过设定Time.timeScale的值可以影响到整个游戏的播放速率。
但是请注意,无论timeScale是多少都不会影响到Update、LateUpdate这2个方法的执行速度,而是会影响到Time.time和Time.deltaTime的值。
比如将timeScale设定为0、1、2等等时,Update和LateUpdate的调用频率是不会变的,但是Time.time及Time.deltaTime会受其影响。
- 当timeScale为0时,time为不继续累加时间,deltaTime为0;
- 当timeScale为1时,time为正常累计时间,deltaTime为正常时间;
- 当timeScale为2时,time为加倍累计时间,deltaTime为正常时间的两倍;
而对于物理方面的FixedUpdate则会由于timeScale的变换而影响到其调用的频率。
- 当timeScale为0时,FixedUpdate将不会再被调用;
- 当timeScale为1时,FixedUpdate正常按时间间隔调用;
- 当timeScale为2时,FixedUpdate按两倍速度调用;
Time.realtimeSinceStartup
Time.realtimeSinceStartup可以不受timeScale的影响,其记录着程序启动到目前经过的时间。我们可以使用该属性来获得不受timeScale影响的时间。
不推荐使用timeScale来实现暂停
timeScale控制者整个游戏的时间缩放,修改它除了会影响到Time.time和Time.deltaTime外,还会影响到游戏的物理模拟,虽然诸如NGUI等支持ingoreTimeScale的属性,但是最好不使用timeScale = 0的方式来实现暂停。
同时timeScale还会影响到音乐播放及粒子效果,可以参考:
要实现慢动作播放等效果可以考虑使用timeScale,如果可以,最好自己实现一个timeScale,其只会影响到特定的模块,毕竟影响到全局的timeScale可能会造成一些难以察觉的坑。
我使用的暂停方法
由于我只需要暂停,不需要加速或慢速播放的效果,所以自己实现是最好的,如下:
1 using UnityEngine; 2 3 ///4 /// 支持暂停的 MonoBehaviour 基类. 5 /// 游戏中需要暂停功能的逻辑都应该继承该类并将逻辑写到 OnUpdate 及 OnLateUpdate 方法中, 这两个方法在设置为暂停时不会被调用. 6 /// 7 public class PausingBehaviour : MonoBehaviour 8 { 9 ///10 /// 是否暂停逻辑处理.11 /// 12 public static bool pause { get; set; }13 14 static PausingBehaviour()15 {16 pause = false;17 }18 19 private bool _isPaused;20 21 protected virtual void OnEnable()22 {23 _isPaused = pause;24 }25 26 protected virtual void Update()27 {28 if(!pause)29 {30 if(_isPaused)31 {32 _isPaused = false;33 this.OnPauseExit();34 }35 36 this.OnUpdate();37 }38 else39 {40 if(!_isPaused)41 {42 _isPaused = true;43 this.OnPauseEnter();44 }45 }46 }47 48 ///49 /// 可暂停的逻辑更新方法.50 /// 51 protected virtual void OnUpdate()52 {53 }54 55 protected virtual void LateUpdate()56 {57 if(!pause)58 {59 this.OnLateUpdate();60 }61 }62 63 ///64 /// 可暂停的逻辑更新方法.65 /// 66 protected virtual void OnLateUpdate()67 {68 }69 70 ///71 /// 暂停开始时会调用该方法.72 /// 73 protected virtual void OnPauseEnter()74 {75 }76 77 ///78 /// 暂停结束时会调用该方法.79 /// 80 protected virtual void OnPauseExit()81 {82 }83 }
所有需要暂停功能的脚本都继承自该类,帧逻辑写在OnUpdate及OnLateUpdate里,同时还有OnPauseEnter和OnPauseExit方法来表示是否进入和离开暂停状态。
当设定PausingBehaviour.pause = false时,OnUpdate及OnLateUpdate将不会被调用,而OnPauseEnter会被调用一次,这里可以对粒子效果等进行暂停,反之设定PausingBehaviour.pause = true时也一样。
手游强制暂停
这里额外提一下,手机游戏中来电话或锁屏或退出到桌面时,可以接受到Unity对应的事件,这里需要对游戏进行一下“强制暂停”,另外如果“强制暂停”时间过长,网络游戏有时得重新登录等事件。