在多人遊戲環境變更角色移動速度 (一)
簡介
在還沒有任何網路延遲處理的經驗下,很容易做出遇到延遲就會產生問題的功能。
例如說做一個緩速功能,只要遇到網路發生延遲,玩家就會感受到拉回。
在過去的專案有幸遇到前輩指教,在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
來處理。
新手作法驗證與檢討
開啟Net PktLag=500之後,我們再來測試之前的作法。這時候就會發現只要頻繁的Strafe/UnStrafe切換,畫面就會有明顯異常發生,玩家的移動將不再感覺到順暢。
為什麼速度切換不再順暢?
問題就出在當我們按下減速的時候,Client端已經先行減速,這時候Server還是以原來的速度前進,直到500ms後Server收到RPC,才會把該Player減速。
在這段時間Client與Server的誤差會越來越大,大到一定程度的時候Client就會矯正自己的位置,
因為最後正確的位置還是要以Server為主。這個矯正就會使玩家感受到不順暢,也就是前面提到的拉回。
結論
本篇以Blueprint搭配RPC來製作角色減速的功能,然後介紹如何在UE4編輯器內建立正確的多人遊戲測試環境。
為了驗證正確性,我說明如何驗證網路延遲,如何模擬網路延遲等UE4內建的功能。最後則是對這個錯誤的做法做基本的分析與檢討。
在本系列的下一篇,就要介紹如何不拉回的做法了。
留言
張貼留言