Unity 3D實現幀同步技術


筆者介紹:姜雪偉,IT公司技術合伙人,IT高級講師,CSDN社區專家,特邀編輯,暢銷書作者,國家專利發明人;已出版書籍:《手把手教你架構3D游戲引擎》電子工業出版社和《Unity3D實戰核心技術詳解》電子工業出版社等。

CSDN視頻網址:http://edu.csdn.net/lecturer/144

現在競技類網絡游戲比較火,市面上也出現了很多這種類型的游戲競賽,提到網絡游戲就回避不了一個問題:同步技術,多個人在一個游戲場景圍攻一個怪物或者說多人組隊戰斗等等。現在在移動端的游戲由於帶寬的限制,一般采用實時同步的方式是狀態同步,也就是說角色的狀態發生改變,才會去發送消息。舉個例子:

3D角色一般的動作狀態有:Idle,walk,run,attack等,玩家操作鍵盤或者觸摸屏按鈕,會觸發這些動作,一個游戲場景中會有多個角色,每個角色都有自己的動作狀態,為了讓玩家能夠看到其他玩家在做什么,需要同步,玩家默認狀態是idle,玩家剛出現時是idle狀態,這個時候,客戶端會把玩家的狀態,位置,方向傳送給服務器,其他玩家也是一樣的,服務器接收到信息后,會把這些信息發送給除了它本人之外的其它玩家,這樣我們就可以看到其他玩家的狀態了。如果玩家從idle狀態轉化到walk狀態,這表明玩家的動作狀態發生了變化,這也需要將信息發給服務器,服務器進行群發給其他玩家,這樣其他玩家就可以看到角色開始walk了。接下來如果玩家繼續走,客戶端就不發送消息給服務器了,因為狀態沒發生變化,等狀態再變化時才會發送消息給服務器,然后服務器再群發消息,在此過程中,其他客戶端會通過插值的方式把兩個狀態之間的距離實現出來,以此類推。。。。。。這就是所說的狀態同步模式。

下面介紹一下幀同步模式,幀同步含義游戲客戶端接受來自網絡的多個客戶端的操作,如果這些操作在各個客戶端是一樣的,那么多個客戶端的顯示也就一樣了,這就帶來了“同步”的效果。所以在這種情況下,各個客戶端的運算要絕對一致,不能依賴諸如本地時間、本地隨機數等等“輸入”,而要一切以網絡來的操作數據為主。

一般來說,大多數的游戲客戶端引擎,都會定時調用一個接口函數,這個函數由用戶填寫內容,用來修改和控制游戲中各種需要顯示的內容。比如在在Unity里面叫Update(),這類函數通常會在每幀畫面渲染前調用,當用戶修改了游戲中的各個角色的位置、大小后,就在下一幀畫面中顯示出來。而在幀同步的游戲中,這個Update()函數依然是存在,只不過里面大部分的內容,需要挪到另外一個類似的函數中,我們可以稱之為UpdateNet()函數——由網絡層不斷的接收服務器發來的“網絡幀”數據包,每收到一個這樣的數據包,就調用一次這個UpdateNet()函數,這樣游戲就從通過本地CPU的Update()函數的驅動,改為根據網絡來的UpdateNet()函數驅動了。顯然,網絡發過來的同步幀速度會明顯比本地CPU要慢的多,這里就對我們的游戲邏輯開發提出了更高的要求——如何同步的同時,還能保證流暢?

實現UpdateNet函數內容,其實就是定義一個堆棧用於存放網絡發過來的消息,通過幀監測將其數據拿出來使用,因為Update函數明顯比UpdateNet快的多,這就需要我們定義一個時間間隔用於消息的發送,比如50毫秒或者100毫米等。

 

[csharp]  view plain  copy
 
  1. private float AccumilatedTime = 0f;  
  2.    
  3. private float FrameLength = 0.05f; //50 miliseconds   
  4. //called once per unity frame   
  5. public void Update() {  
  6.     //Basically same logic as FixedUpdate, but we can scale it by adjusting FrameLength   
  7.     AccumilatedTime = AccumilatedTime + Time.deltaTime;  
  8.    
  9.     //in case the FPS is too slow, we may need to update the game multiple times a frame   
  10.     while(AccumilatedTime > FrameLength) {  
  11.         GameFrameTurn ();  
  12.         AccumilatedTime = AccumilatedTime - FrameLength;  
  13.     }  
  14. }  

 

 

 

[csharp]  view plain  copy
 
  1. private void GameFrameTurn() {  
  2.     //first frame is used to process actions   
  3.     if(GameFrame == 0) {  
  4.         if(LockStepTurn()) {  
  5.             GameFrame++;  
  6.         }  
  7.     } else {  
  8.         //update game   
  9.         SceneManager.Manager.TwoDPhysics.Update (GameFramesPerSecond);  
  10.            
  11.         List<IHasGameFrame> finished = new List<IHasGameFrame>();  
  12.         foreach(IHasGameFrame obj in SceneManager.Manager.GameFrameObjects) {  
  13.             obj.GameFrameTurn(GameFramesPerSecond);  
  14.             if(obj.Finished) {  
  15.                 finished.Add (obj);  
  16.             }  
  17.         }  
  18.            
  19.         foreach(IHasGameFrame obj in finished) {  
  20.             SceneManager.Manager.GameFrameObjects.Remove (obj);  
  21.         }  
  22.            
  23.         GameFrame++;  
  24.         if(GameFrame == GameFramesPerLocksetpTurn) {  
  25.             GameFrame = 0;  
  26.         }  
  27.     }  
  28. }  

 

 

 

幀同步游戲中,由於需要“每一幀”都要廣播數據,所以廣播的頻率非常高,這就要求每次廣播的數據要足夠的小。最好每一個網絡幀,能在一個MTU以下,這樣才能有效降低底層網絡的延遲。同樣的理由,我們為了提高實時性,一般也傾向於使用UDP而不是TCP協議,這樣底層的處理會更高效。但是,這樣也會帶來了丟包、亂序的可能性。因此我們常常會以冗余的方式——比如每個幀數據包,實際上是包含了過去2幀的數據,也就是每次發3幀的數據,來對抗丟包。也就是說三個包里面只要有一個包沒丟,就不影響游戲。

幀同步實現的過程有個很重要的地方就是邏輯層和表現層一定要分開,表現層先行,邏輯層等發到服務端的指令再處理。幀與幀之間的播放頻率,則由服務器統一控制,但由於網絡抖動等影響,幀的頻率並不是太穩定,為避免播放抖動,幀數控制器需要進行一定的平滑處理。

 

網絡抖動的產生原因:在網絡游戲中,各個客戶端的運行條件和環境往往千差萬別,有的硬件好一些,有的差一些,各方的網絡情況也不一致;時不時玩家的網絡還會在游戲過程中,發生臨時的擁堵,我們稱之為“網絡抖動”。可能導致客戶端收到“過去時間”里的一堆網絡幀,客戶端需要拿出一定的時間去處理這些堆積的網絡幀,因此,客戶端必須要有處理這些堆積起來的網絡數據的能力。

實時同步游戲最重要的是流暢,然而影響游戲流暢的因素很多,網絡帶寬的限制,CPU運算和渲染效率的限制。一般玩家控制的角色的動作,包括當前客戶端控制的角色,還是應該從網絡幀里面獲得行為數據,因為如果玩家愛控制角色不一致的太多,整個游戲場面就會差更多。很多游戲中的怪物AI都是根據玩家角色來設定的,所以一旦玩家角色的行為是同步的,那么大多數的怪物的表現還是一致的。

 

幀同步游戲技術,並不存在一種可以讓游戲流暢的通用做法,而是需要和游戲具體做很多結合,在減少數據包,優化游戲快進體驗,控制發包速度上盡量調優。同時還需要和游戲產品策划一起,平衡一致性、實時性、公平性的策略,才能真正達到流暢游戲的目的。

 
Demo下載地址:鏈接: https://pan.baidu.com/s/1kVt77wz 密碼: tfsa

http://www.woaipu.com/shops/zuzhuan/61406
http://nanning.xjwy.cn/f/bencandy.php?fid=43&id=117777
http://nanning.xjwy.cn/f/bencandy.php?fid=43&id=117890
http://nanning.xjwy.cn/f/bencandy.php?fid=43&id=117994
http://nanning.xjwy.cn/f/bencandy.php?fid=43&id=118376


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM