2017-03-05 24 views
1

我目前正在爲Unity遊戲構建我自己的網絡代碼(用於學習體驗),而且我正在對事情的「解碼數據包」方面發生嚴重的延遲。在多人遊戲中,如何有效地通過套接字發送位置數據?

基本上,我有playerObject將位置數據(Vector3(x,y,z))作爲JSON字符串發送到服務器,服務器將其發回給所有其他玩家。

東西的插座邊很漂亮。從創建數據包到收到數據包時的延遲非常小。

但我上午讓我的客戶一個巨大的延遲,當他們試圖取消JSON的遠程客戶端的位置:

Vector3 remotePos = JsonUtility.FromJson<Vector3>(_command.Substring(5 + _usernameLength));

JSON字符串有字符串的開頭的標識符說它是一個位置更新,然後是兩個數字,表示用戶名的長度,然後是用戶名(以便遠程客戶端可以更新正確的playerObject。整個字符串看起來是這樣的)

POS09NewPlayer{"x":140.47999572753907,"y":0.25,"z":140.7100067138672}

從服務器接收這樣的報文後,我的客戶將瓶坯以下任務:

 int _usernameLength = Int32.Parse(_command.Substring(3, 2)); 
     string _username = _command.Substring(5, _usernameLength); 
     Vector3 remotePos = JsonUtility.FromJson<Vector3> 
     if (_username != username) 
     { 
     playerDict[_username].transform.position = remotePos; 
     } 

所有這些「作品」,但變得非常低迷後剛剛3個客戶端同時連接。

我在做什麼錯?必須有一個重大的缺陷,因爲我每3秒鐘只發送0.015秒的更新時間,而像「戰地」這樣的遊戲每秒可以發送60次更新給64名玩家!

任何意見,將不勝感激。

+1

至少舉動'JsonUtility.FromJson'在'if' –

+0

我很懷疑反序列化JSON在這種情況下,造成這種巨大的影響 – Evk

+0

@Evk我指望收到的數據包,同時計數json'd包。我接收數據包的速度是我能夠快速發送的速度的三倍。這意味着東西落後。 – MrDysprosium

回答

5

那麼,確實有優化的空間。既然你引述的大遊戲引擎作爲參考,我會根據舊的虛幻引擎版本和一些他們使用的優化給你一些例子:

  • 網絡包使用UDP協議。它仍然需要自行處理掉落,重複或無序的軟件包,但它會吞下那顆苦藥,而不是使用實際的TCP連接,因爲後者會帶來更多的開銷。
  • 服務器會跟蹤它發送給客戶端的信息更新。對於客戶端上由服務器複製的每個對象,服務器都會跟蹤所有變量。在每次遊戲循環更新結束時,服務器將檢查哪些變量實際上具有與上次向客戶端發送更新時不同的值。只有實際存在差異時,纔會將新值發送給客戶端。這可能看起來像一個令人難以置信的開銷,但網絡帶寬是一個比系統內存和CPU時間更稀缺的資源。
  • 矢量信息在通過網絡發送之前實際上被截斷。該引擎使用float作爲其向量分量的數據類型,但它仍然將X,Y和Z四捨五入爲最接近的整數,並將其傳遞爲完整的浮點數據。這樣它們只佔用幾位到幾個字節,而不是12個字節的未壓縮原始浮點數。
  • 在客戶端模擬位置更新並與來自服務器的傳入數據合併。爲避免位置更新抖動,客戶端根據其速度值預測對象的新位置。當客戶端稍後從服務器接收到位置更新時,它將優雅地將對象略微移動到新的位置(基本上是客戶端和服務器座標之間的折衷),並且只有在服務器的位置與客戶端版本。這是用很多東西來完成的。如果玩家發射了彈丸,那麼在服務器上執行該彈丸,這將產生彈丸並將其發送給玩家以更新其位置。但是玩家也會收到關於鏡頭的函數調用,並且在本地創建子彈並更新其彈道。即使該拋射物不能真正殺死客戶端的玩家,它的軌跡和效果仍然可以在本地模擬以給出遊戲流暢的印象。如果碰到什麼東西,可以在該位置播放適當的效果,而不需要服務器告訴客戶端創建這些效果。
  • 服務器記錄每個玩家的相關內容。如果一名玩家位於地圖的另一邊,並且不需要向您發送關於該玩家動作的任何更新信息。如果該玩家的投擲物後來碰巧出現在你的視線中,服務器仍然可以在適當的時候告訴你這些投射物。

整個事情比我可以在這篇文章中填入的內容要複雜得多,但其要點可能是:網絡帶寬是多人遊戲中最有限的資源,因此引擎不再使用它發送儘可能少且很少的信息包的方式。

注意事項?在此引擎中,對於整個矢量而言,小於您的位置矢量的單個分量已經被認爲太大。我猜JSON真的在這裏引入了一些開銷,只是由於它的冗長。你可以發送數字作爲字符串,當你也可以發送他們的實際位並從實際包裝中推斷出它們的含義時。

+0

哇,謝謝你寫了很多有用的信息。 你能否詳細介紹一下最後一部分? 「你也可以只是發送他們的實際數據,並從實際包裝中推斷出他們的含義。」 – MrDysprosium

+0

這更多的是暗示實際的引擎可能會這樣做,因爲它們可能不使用JSON。如果你使用UDP作爲準系統,你可以隨意發送你想要的任何字節(每個包最多大約65000字節)。然後,您可以用幾個字節來識別播放器,其中一些用於識別發送的數據,然後用幾個字節來表示矢量的實際數值,然後在客戶端自行解析。在.NET中的UDP示例:https://social.msdn.microsoft.com/Forums/zh-CN/92846ccb-fad3-469a-baf7-bb153ce2d82b/simple-udp-example-code?forum=netfxnetcom –

+0

保留但請注意,UDP不會自行處理重複,丟棄或亂序的包,因此您可能需要自行處理。這意味着發送某種形式的確認,表明已收到包裹,否則請發件人定期重新發送包裹,直至收到確認信息。並且對傳出包進行時間戳記,所以如果較新的數據事先到達(但仍然發送確認,以便發送者不繼續發送這些包),舊數據可以在接收端丟棄。 –

相關問題