看板 GameDesign 關於我們 聯絡資訊
網頁版 https://yekdniwue.blogspot.com/2020/07/CustomMove1.html 簡介 在還沒有任何網路延遲處理的經驗下, 很容易做出遇到延遲就會產生問題的功能。 例如說做一個緩速功能,只要遇到網路發生延遲,玩家就會感受到拉回。 在過去的專案有幸遇到前輩指教,在UE4做了一點驗證,本篇算是學習的成果。 本系列我將會以一個實際的UE4 4.23案例做說明。 要實作的功能是: 玩家按下某一個鍵後,會進入移動射擊狀態(假設名字定義為Strafe), 放開按鍵後離開移動射擊狀態(UnStrafe)。 Strafe時,移動速度會減慢一半,UnStrafe後移動速度回到正常。 然後以新手的角度實作,接著提到如何模擬網路延遲, 驗證新手的實作方法有問題,以及問題在哪邊。 再來就是提出正確的解法。這個解法需要以C++繼承UE4內建的 CharacterMovementComponent,並複寫部分函式。 這樣的做法伺服器端就會接受玩家的指令, 如同玩家送出的移動一樣,不會造成拉回。 本系列目標是能夠介紹一系列的流程,包含如何開發移動減速功能, 如何驗證網路延遲,結束於改善網路延遲移動的問題。 讀者可能需要知道什麼是RPC,文章前面提的部份是BP專案就能做到。 後面要改善移動的時候才需要C++專案,有需求的人可以參考部份就好。 本篇不會提到改善網路延遲移動的做法,該作法會放到下一篇。 新手做法(以RPC) 本節會介紹我當初在錯誤的觀念做出來的做法以及結果。 雖然可能有人會想說為什麼要介紹錯誤的觀念? 主要是我認為並非所有人有網路基礎。 所以有必要先用比較淺顯易懂的方式, 介紹這個需求的功能,把基礎建設先解釋完。 然後接下來我只要專注在介紹修正錯誤的部份, 避免本篇文章的閱讀難度一開始就過高。 首先在玩家的PlayerCharacter要新增按鈕接收的事件, 在這邊我用input action strafe定義了輸入事件strafe, 觸發的話就進入strafe,放開事件就離開strafe。 在多人連線的架構,直覺的作法就是client收到按鍵事件後, 玩家角色端先套用Strafe處理,然後透過reliable RPC發送事件給server。 server收到事件後作一樣的處理。 所以我們要新增兩個事件,一個是PerformStrafe , 根據現在事件是Strafe還是UnStrafe, 作移動速度的變更,如圖所示。 [圖] 另一個則是Client,通知Server的reliable RPC 事件, 命名為ServerPerformStrafe,裡面就是Server呼叫PerformStrafe來更改速度。 如圖所示。 [圖] 最後就是事件Input Action Strafe,裡面要接上PerformStrafe還有 ServerPerformStrafe事件。 如圖所示。 [圖] 測試環境設定 本章會介紹如何模擬網路延遲,並驗證前一章提的做法是有問題,問題會發生在哪邊。 為了客觀驗證,我們需要使用dedicated server+client這樣的環境做測試。 千萬要記得如果環境設定成單機,或是自己就是Listen Server, 那不管怎麼調整都是測不出來的。 所以要測試網路延遲,只有兩種對象可以達到。 1. dedicated server / client 架構的任一client 2. listen server / client 架構下server以外的client。 在UE4,如果想在Editor的環境驗證,還需要多設定以下幾項: [圖] [圖] 最重要的就是Run Dedicated server,以及取消single process, 並設為Play As Client。 這樣server跟client才會分開成兩隻獨立的程式執行。同一個process等於沒辦法模擬延 遲,所以很重要。通常我要模擬延遲的之前,會使用StandaloneGame做測試。 也因為開啟的時候是開兩個程式起來,所以如果要修改BP,請記得兩個開起來的程式都要 先關掉,以免跳錯或得到不預期的結果。 實際測試與網路延遲模擬 先前的設定都好了之後就可以點Play執行。 這時候就會跳出兩個視窗,一個是server,一個是client。 如圖所示,左上的圖是client,右下方的是dedicated server的訊息視窗。 [圖] 這時候我們開始移動,並頻繁的操作Strafe,UnStrafe,會發現沒有問題。 這是正常的,因為畢竟兩個程式還是在同一台電腦,所以不會有延遲。 就算我們將環境架在內網,大概也不會差太多。 所以我們必須先學會如何模擬網路的延遲。 取得網路延遲資訊 在開始模擬延遲之前,先介紹如何在UE4知道網路有延遲。 在PlayerState裡面有個變數是Ping Engine/Source/Runtime/Engine/Classes/GameFramework/PlayerState.h 這個變數是Server計算出來同步給所有玩家的值,但是因為有處理過, 所以不是真正的數值。 坦白說我沒去追查這個值跟真正的值的換算公式, 我只知道因為這個值要同步給玩家,所以有做過處理, 以避免每個frame可能都在變動的數值一直傳輸給玩家。 不過,Ping這個變數是UPROPERTY,所以我們可以使用console command displayall playerstate ping 來獲得結果,一行程式碼都不用寫。 在我的環境開起來Ping顯示的是個位數左右,印象中如果是SingleProcess的話, 應該會是0。 所以如果不在意精準的話,大概就是0~個位數就是幾乎無延遲。 如果想獲得比較精準的值,請參考PlayerState內的ExactPing。 但是這個值就必須要到C++處理了。 模擬網路延遲 在UE4內有一系列的console command可以模擬網路異常的狀況。 1. Net PktLag=[延遲ms] 2. Net PktOrder=[] 3. Net PktLoss=[掉包機率] 4. Net PktVariance=[延遲變量] 5. Net PktDup=[重送機率] 這些參數的意義 都可以在 Engine/Source/Runtime/Engine/Classes/Engine/NetDriver.h 裡面查到 最重要的當然就是模擬延遲,例如輸入 Net PktLag=500 就可以模擬延遲500 ms的結果。 不過我有查到,UE4的模擬延遲只能延遲送出,無法模擬延遲接收。 如果Client延遲500ms,指的是他送資料給server會慢500ms。 如果Server延遲200ms,指的是Server會延遲200ms才送給"所有人"。 所以如果想做 Server送到Client1延遲100ms, Server送到Client2延遲200ms。 這種更詳細的測試,只用UE4內建不行,這時候可以考慮使用Clumsy (https://jagt.github.io/clumsy/) 來處理。 新手作法驗證與檢討 開啟Net PktLag=500之後,我們再來測試之前的作法。這時候就會發現只要頻繁的 Strafe/UnStrafe切換,畫面就會有明顯異常發生,玩家的移動將不再感覺到順暢。 詳情可以看影片: [影片] 為什麼速度切換不再順暢? 問題就出在當我們按下減速的時候,Client端已經先行減速, 這時候Server還是以原來的速度前進,直到500ms後Server收到RPC, 才會把該Player減速。 在這段時間Client與Server的誤差會越來越大, 大到一定程度的時候Client就會矯正自己的位置, 因為最後正確的位置還是要以Server為主。 這個矯正就會使玩家感受到不順暢,也就是前面提到的拉回。 結論 本篇以Blueprint搭配RPC來製作角色減速的功能,然後介紹如何在UE4編輯器內建立正確 的多人遊戲測試環境。 為了驗證正確性,我說明如何驗證網路延遲,如何模擬網路延遲等UE4內建的功能。最後 則是對這個錯誤的做法做基本的分析與檢討。 在本系列的下一篇,就要介紹如何不拉回的做法了。 -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 59.120.146.90 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/GameDesign/M.1595990033.A.28E.html
sampp1213205: 先推再看 07/29 10:50
metallican: 推爆 07/29 18:48
coolrobin: 坐等下一篇 07/29 22:13
wangm4a1: 推 07/30 12:39
nyc0125: 樓主樂於分享一生平安 07/30 18:05
ConSeR: 感謝 很受用 07/31 14:21