UE代码-CharacterMovementComponent-角色移动组件
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种不同的网络角色走不同但恰到好处的代码逻辑值得学习。