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:

移动的具体实现,暂时不分析那么细了。

具体实现角色移动
	服务器与客户端:变更状态,更新变换,速度,回调委托等
	服务器:
		更新时间戳:有客户端信息用客户端信息更新,否则用本地时间。
收获:
  1. 对于相似的移动,Ue4会尝试将其合并减少数据包以减少带宽消耗。在其他类似情景下也能考虑考虑是否能像这样优化。
  2. 自治端并非需要等到服务器的同步在移动,可以让自己先动再等服务器矫正以提升玩家游戏体验。
  3. 移动矫正设置了容忍范围,可以考虑是否可以通过修改其范围,来提升角色移动的精确度或降低开销。
  4. 根据3种不同的网络角色走不同但恰到好处的代码逻辑值得学习。
posted @ 2022-04-19 17:48  ccsu_madoka  阅读(1243)  评论(0编辑  收藏  举报