Unity3d進階學習(3)-- 遊戲定時器

原文:http://forum.china.unity3d.com/thread-28428-1-1.html

0x02 可變增量時間
ok,那我們來看看遊戲引擎的定時器是如何來實現的吧。假設我們手頭沒有一個現成的遊戲引擎,一切都需要自己來實現,那麼一個最簡單的遊戲循環大概就是下面這個樣子的。

double lastTime = Timer.GetTime();
...

while (!quit()){

  double currentTime = Timer.GetTime();
  double frameTime = currentTime - lastTime ;

  UpdateWorld(frameTime);
  RenderWorld();

  lastTime = currentTime;
}

這種實現方式使得增量時間和具體的機器設備相關,並且它每一次的時間增量都不一定相同。
當機器十分快時,引擎可能通過線程休眠來保證固定的FPS。

while(timeout > 0.001 && deltaTime<timeout)
{
    //...休眠後計算新的增量時間
}

所以看上去整個遊戲保證一個大致的更新頻率似乎不難。但是現在問題的關鍵在於每次更新時的時間增量無法保證相同。而在物理模擬中,保證一個固定的增量時間是十分重要的。這是因爲在遊戲引擎進行物理模擬時要使用數值積分,而作爲最簡單的數值積分方法——歐拉法在遊戲引擎中大量使用。

image

上面就是一個歐拉法的簡單例子。可以看到增量時間是很重要的。而在遊戲引擎的物理模擬中,一個不穩定的增量時間可能導致很多和預期相悖的結果。

由於此時計算的是真實的時間,而真實的增量時間無法保證固定,那換一個思路,我們把參與物理模擬的增量時間當做一個常量可以嗎?換句話說,不論遊戲的更新頻率如何,參與物理模擬的增量時間是一個常數。

0x03 固定增量時間

一個最簡單的固定增量時間的實現,顯然就是將固定的增量時間作爲一個常量參數傳遞給物理模擬模塊,這樣我們就能夠保證物理模擬的增量時間固定,同時還能將物理模擬的更新頻率和遊戲引擎的更新頻率進行解耦——物理的模擬不受引擎的更新頻率影響,無論遊戲的更新頻率是多少,傳遞給物理模擬的增量時間都是一個常量。

這裏還拿Unity引擎來舉例子,默認情況下項目的Fixed Timestep的值爲0.02s。也就是說物理模擬的頻率是50FPS,假設我們的遊戲的更新頻率是25FPS,那麼會發生什麼呢?沒錯,遊戲每1次Update時,物理模擬都要推進2次,也就是之前我們看到的在Update之前多次調用了FixedUpdate。那麼如果我們的遊戲更新頻率是100FPS呢?這次就變成了每2次Update調用1次FixedUpdate。

這也就解釋了爲何有的朋友在做相關的小測試的時候,在每次FixedUpdate內打印Time.deltaTime時輸出的都是0.02了,因爲Time.deltaTime並非兩次調用FixedUpdate之間真實的時間間隔,而是來自我們在項目的Time設置內設置的值——它是一個與真實時間無關的常量。

When called from inside MonoBehaviour’s FixedUpdate, returns the fixed framerate delta time.

那麼這種固定增量時間的邏輯如何用代碼表示呢?很簡單,只需要在主循環的內部,再來一個二級循環。

double  simulationTime = 0;
double  fixedTime = 20;

while (!quit()){

  double  realTime = Timer.GetTime();

  while (simulationTime < realTime){
         simulationTime += fixedTime; 
         UpdateWorld(fixedTime);
  }

  RenderWorld();
}

而Unity的實現顯然也是類似的,這個在Unity手冊中關於執行順序的相關章節內可以看到。
官網:https://docs.unity3d.com/500/Documentation/Manual/ExecutionOrder.html
unity 函數執行順序.png

上圖標明瞭FixedUpdate是屬於物理模擬模塊的,同時在主循環的內部,物理模擬的部分還有一個二級循環。

發佈了39 篇原創文章 · 獲贊 11 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章