Ue4 CharacterMovementComponent 角色移動組件
這里先簡單介紹一下3種不同的網絡角色:
AutonomousProxy(自治端):
一般為客戶端,對具有其控制權的角色而言為自治端。
Authority (權威端):
一般就是服務器,具有數據的決定權。
SimulatedProxy(模擬端):
一般為客戶端,對不具有控制權的角色而言為模擬端。
大致講講:
Ue根據網絡角色不同,移動邏輯也不一樣。
首先發起者是自治端。自治端輸入移動的操作,並將input信息加入Vector。需要注意的是角色並不會在此處立即移動。
等到下一個tick時,自治端就會取出其輸入的信息,進行完移動矯正后再正式移動。
自治端的移動並不會先等權威端移動完再動,而是在本地先移動了再說。隨后便會通知權威端進行移動。
權威端移動后會進行一個與自治端的預測結果的一個對比。
差距過大會通知自治端需要矯正,自治端會在收到后的下一個tick矯正。
差距不大會通知自治端清除移動緩存。
模擬端,則是跟着服務器數據的同步,進行模擬移動。
3種網絡角色的移動流程:
TickComponent:角色的移動從tick開始
消費輸入向量
判斷一些其他情況:
是否vaild
有沒有掉出世界
是否開啟物理模擬
處理 自治端:
自治端進行移動矯正 ClientUpdatePositionAfterServerUpdate()
自治端移動邏輯 ControlledCharacterMove():
Tips:RootMotion可以移動沒有控制器的角色
處理 模擬端:
模擬端進行移動復制 SimulatedTick()
Tip:
大家可能會有一個疑問,沒有權威端的移動邏輯。
權威端的移動(不包括監聽服務器)並不在tick中執行,而是等待自治端調用ServerMove時才處理相關邏輯。
自治端移動邏輯 ControlledCharacterMove:
自治端在Tick中會走到這里來,主要任務是移動與發包給服務器。
通過消費的輸入向量改變角色加速度
執行移動 ReplicateMoveToServer()
合並新舊移動 NewMove->CombineWith(PendingMove, CharacterOwner, PC, OldStartLocation);
個人猜想,不一定對:若前后移動加速度未發生改變的話,可以合並時間,從而減少數據量。
為何不直接用SavedMove的最后一項與之合並而用PengdingMove去合並沒有理解。
具體細節還待深入研究。
執行本地移動 PerformMovement()
將移動加入緩存列表 ClientData->SavedMoves.Push(NewMovePtr)
發送服務器 CallServerMove()
權威端移動邏輯與驗證 ServerMove(RPC函數):
自治端調用的RPC函數,權威端在這里進行移動和預測,判斷是否需要矯正。
創建/獲取預測數據 ServerData = GetPredictionData_Server_Character
將移動數據加入ServerData
權威端執行移動並記錄數據結果 MoveAutonomous()
更新移動數據
執行移動 PerformMovement()
矯正自治端移動或確認移動 ServerMoveHandleClientError()
進行狀態判斷盡量節省帶寬
權威端計算自治端端移動是否需要矯正:
需要:
設置矯正信息
ServerData->PendingAdjustment.bAckGoodMove = false;
不需要:
ServerData->PendingAdjustment.bAckGoodMove = true;
Tips:
服務器沒有在這里通知客戶端移動結果,而是等ServerReplicateActors調用SendClientAdjustment來通知。
bAckGoodMove的值代表了預測的結果。
對預測結果進行操作 SendClientAdjustment
ServerReplicateActors中調用,會根據bAckGoodMove的值來判斷是否需要矯正。
bAckGoodMove == true;
發送RPC函數給自治端:ClientAckGoodMove()
"以下在自治端":
找到SavedData對應的索引 index
將SavedData緩存清除:ClientData->AckMove(index)
bAckGoodMove = false;
通知自治端進行矯正:ClientAdjustPosition()
"以下在自治端":
Tips:這里會根據ServerData里情況的不同進行不同的通知,AdjustPosition只是其中一種
自治端保存矯正信息ClientData,並在下一次TickComponent中等待ClientUpdatePositionAfterServerUpdate進行移動矯正
模擬端進行移動復制 SimulatedTick
在最上面的Tick中調用,處理模擬端的移動。
分類討論集中情況,播放RootMotion,不用RootMotion的,對不同的情況進行平滑處理,模擬移動等,動畫細節暫不做分析了。
執行移動函數,與自治端,權威端一樣:PerformMovement
執行本地移動 PerformMovement:
移動的具體實現,暫時不分析那么細了。
具體實現角色移動
服務器與客戶端:變更狀態,更新變換,速度,回調委托等
服務器:
更新時間戳:有客戶端信息用客戶端信息更新,否則用本地時間。
收獲:
- 對於相似的移動,Ue4會嘗試將其合並減少數據包以減少帶寬消耗。在其他類似情景下也能考慮考慮是否能像這樣優化。
- 自治端並非需要等到服務器的同步在移動,可以讓自己先動再等服務器矯正以提升玩家游戲體驗。
- 移動矯正設置了容忍范圍,可以考慮是否可以通過修改其范圍,來提升角色移動的精確度或降低開銷。
- 根據3種不同的網絡角色走不同但恰到好處的代碼邏輯值得學習。
