在游戲開發中我們一般都需要涉及到一個功能:游戲暫停,但是這里指的暫停僅僅是核心模塊的暫停,並不是整個游戲都暫停,比如一些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還會影響到音樂播放及粒子效果,可以參考:http://www.xuanyusong.com/archives/2956
要實現慢動作播放等效果可以考慮使用timeScale,如果可以,最好自己實現一個timeScale,其只會影響到特定的模塊,畢竟影響到全局的timeScale可能會造成一些難以察覺的坑。
我使用的暫停方法
由於我只需要暫停,不需要加速或慢速播放的效果,所以自己實現是最好的,如下:
1 using UnityEngine; 2 3 /// <summary> 4 /// 支持暫停的 MonoBehaviour 基類. 5 /// 游戲中需要暫停功能的邏輯都應該繼承該類並將邏輯寫到 OnUpdate 及 OnLateUpdate 方法中, 這兩個方法在設置為暫停時不會被調用. 6 /// </summary> 7 public class PausingBehaviour : MonoBehaviour 8 { 9 /// <summary> 10 /// 是否暫停邏輯處理. 11 /// </summary> 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 else 39 { 40 if(!_isPaused) 41 { 42 _isPaused = true; 43 this.OnPauseEnter(); 44 } 45 } 46 } 47 48 /// <summary> 49 /// 可暫停的邏輯更新方法. 50 /// </summary> 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 /// <summary> 64 /// 可暫停的邏輯更新方法. 65 /// </summary> 66 protected virtual void OnLateUpdate() 67 { 68 } 69 70 /// <summary> 71 /// 暫停開始時會調用該方法. 72 /// </summary> 73 protected virtual void OnPauseEnter() 74 { 75 } 76 77 /// <summary> 78 /// 暫停結束時會調用該方法. 79 /// </summary> 80 protected virtual void OnPauseExit() 81 { 82 } 83 }
所有需要暫停功能的腳本都繼承自該類,幀邏輯寫在OnUpdate及OnLateUpdate里,同時還有OnPauseEnter和OnPauseExit方法來表示是否進入和離開暫停狀態。
當設定PausingBehaviour.pause = false時,OnUpdate及OnLateUpdate將不會被調用,而OnPauseEnter會被調用一次,這里可以對粒子效果等進行暫停,反之設定PausingBehaviour.pause = true時也一樣。
手游強制暫停
這里額外提一下,手機游戲中來電話或鎖屏或退出到桌面時,可以接受到Unity對應的事件,這里需要對游戲進行一下“強制暫停”,另外如果“強制暫停”時間過長,網絡游戲有時得重新登錄等事件。