基本组件(继承链):
UActorCompoent  - 负责组件的生命周期管理、激活/停用、与Actor的绑定等USceneCompoent - 具有变换并支持附件(组件依附),但没有渲染或碰撞功能。UPrimitiveCompoent - 具有渲染和物理信息,可以实现OverlapUMovementComponent - 具备基本移动功能和接口UProjectileMovementComponent - 抛射物移动UNavMovementComponent - 路径寻找和导航功能,可实现代理AI移动UPawnMovementComponent - 提供输入累积,Owner和移动相关接口UCharacterMovementComponent - 提供了丰富的角色移动功能UFloatingPawnMovement - 运动组件,为Pawn提供简单运动
基础移动组件(泛用型):
USceneComponent+FTransform ComponentToWorld 组件相对世界的变换/基本位置信息 //关键能力-----------------------------------MoveComponent() //核心移动入口,负责位置/旋转更新 可选择sweep。MoveComponentImpl() //虚函数分发UpdateComponentToWorldWithParent() //更新 +ComponentToWorldUMovementComponent+USceneComponent UpdatedComponent //+UPrimitiveComponent UpdatedPrimitive;+FVector Velocity //速度,表示角色当前的移动速度和方向。----------------------------------------------SafeMoveUpdatedComponent() //安全移动更新的组件,尝试移动组件并处理碰撞和阻挡,确保不会进入不可通过的区域。MoveUpdatedComponent() //移动更新的组件,直接移动组件到目标位置,不处理碰撞。MoveUpdatedComponentImpl() //虚函数分发GetPenetrationAdjustment() //计算移动调整,尝试摆脱失败移动带来的渗透/基于FHitResult,返回能解决穿透的Delta增量ResolvePenetration() //移動失敗后,多次退回尝试移出物体的穿透范围。遵循平面约束HandleImpact() // 碰撞响应ComputeSlideVector() //计算滑动下的位移SlideAlongSurface() //尝试沿表面滑动GetMaxSpeed() //获取最大速度,返回角色在当前状态下的最大移动速度。UpdateComponentVelocity() //更新组件速度GetPhysicsVolume() //获取物理体积,返回角色当前所在的物理体积,如水、空气等。UNavMovementComponent+FNavAgentProperties NavAgentProps //导航代理属性,包含角色在导航网格中的相关信息,如大小、能否通过特定区域等。+FMovementProperties MovementState //运动状态标签,用于标识角色的运动能力和状态。uint8 bCanCrouchuint8 bCanJumpuint8 bCanWalkuint8 bCanSwimuint8 bCanFly
基于GamePlay视角下的底层核心移动函数(此函数为不同移动组件衍生中包裹的核心):
USceneComponent::MoveComponent()virtual MoveComponentImpl() //虚函数转发ConditionalUpdateComponentToWorld()UpdateComponentToWorld()UpdateComponentToWorldWithParent()更新变量:+ComponentToWorld	InternalSetWorldLocationAndRotationUpdateComponentToWorldWithParent()更新变量:+ComponentToWorld
移动组件处理移动的核心调用链(主要用于处理不同的物理运动状态下的移动)
UMovementComponent::SafeMoveUpdatedComponent()UMovementComponent::MoveUpdatedComponent()UMovementComponent::MoveUpdatedComponentImpl()+UpdatedComponent -> USceneComponent::MoveComponent();
tips:移动组件必须控制一个能够存在于世界上的组件。移动组件属于UActorCompoent的子类。本身不具备坐标,其主要功能是用于控制成员变量USceneComponent UpdatedComponent进行移动
UMovementComponent::SafeMoveUpdatedComponent(const FVector& Delta, const FRotator& NewRotation, bool bSweep, FHitResult& OutHit, ETeleportType Teleport)
USceneComponent::MoveComponent(const FVector& Delta, const FQuat& NewRotation,    bool bSweep, FHitResult* Hit=NULL, EMoveComponentFlags MoveFlags = MOVECOMP_NoFlags, ETeleportType Teleport = ETeleportType::None);
衍生移动组件(角色特化型)
//角色特化型移动组件一般用于包含“物理”特性的可操控主体。例如Pawn,Character
Pawn && PawnMovementComponent
PawnMovementComponent的设计上用于为 Pawn 提供更新移动的能力(接口/辅助),主要目的还是为了子组件铺垫所提供一些Pawn其关联的移动的基本功能。提供了一种通用的方式来累积和读取方向输入(并不实现具体的移动行为):
UPawnMovementComponent+TObjectPtr<class APawn> PawnOwner;-----------------------------------AddInputVector() //接受输入方向 自身不做处理,内部转发回Owner处理ConsumeInputVector() //消耗输入方向 自身不做处理,内部转发回Owner处理
APawn+FVector ControlInputVector //待处理输入+FVector LastControlInputVector //正在处理输入+bUseControllerRotationPitch //使用控制器旋转+bUseControllerRotationRoll //使用控制器旋转+bUseControllerRotationYaw //使用控制器旋转----------------------------------------SetupPlayerInputComponent() //设置玩家输入组件CreatePlayerInputComponent()//创建玩家输入组件AddMovementInput()//内部最终调用为 APawn::Internal_AddMovementInput();//内部包含拥有PawnMovementComponent的转发,但是实际最终调用相同(转发回溯)ConsumeMovementInputVector()//内部最终调用为APawn::Internal_ConsumeMovementInputVector();//内部包含拥有PawnMovementComponent的转发,但是实际最终调用相同(转发回溯)AddControllerPitchInput()//内部转发至AController::AddPitchInput();AddControllerYawInput()//内部转发至AController::AddYawInput();AddControllerRollInput()//内部转发至AController::AddRollInput();GetLastMovementInputVector()//返回LastControlInputVectorGetPendingMovementInputVector()//返回ControlInputVectorFaceRotation()//将Pawn的旋转更新为指定的旋转,假定为ControlRotation,遵循控制器旋转设置GetViewRotation()// 返回视图旋转 通常是控制器旋转UpdateNavAgent()//更新导航代理,确保导航代理属性与角色状态同步。MoveIgnoreActorAdd()//添加忽略的移动演员,将指定的演员添加到移动忽略列表中,避免与之碰撞GetMovementComponent()//此函数为了通用性用了消耗量比较大的查找类去搜寻,可以进行重载变得更快捷- AddMovementInput()用于收集和存储移动输入。主要用于改变Pawn中的- ControlInputVector以及- LastControlInputVector。本身不会直接导致Pawn移动,而是将输入量存储起来供移动组件在每帧更新时处理。
- ControlInputVector,- LastControlInputVector保存了玩家输入的移动方向和大小,这些输入量通常在对应的移动组件中进行处理,不会应用到Pawn的移动上。
- 基础Pawn类中并没有直接附加UPawnMovementComponent组件。需要自行添加
- UPawnMovementComponent组件并不实现具体的移动行为,其组件含义为提供输入累积,Owner 关联和一些移动相关的工具函数
- ControlInputVector->LastControlInputVector(目的是防止在帧之间控制输入的累积)
输入-移动/旋转流程
Pawn中不实现具体的移动逻辑,但是存在已经实现的旋转逻辑
旋转流程:
APlayerController::TickActorPlayerTickUpdateRotationAPawn::FaceRotation
	如果启用以下设置中任意一项+bUseControllerRotationPitch //使用控制器旋转+bUseControllerRotationRoll //使用控制器旋转+bUseControllerRotationYaw //使用控制器旋转在APawn::FaceRotation中Pawn的旋转会被启用的对应控制器旋转控制(直接SetActorRotation())
如果不是自由相机,尽可能不要使用这个方式,尤其是在Character这种精细化的角色子类。
DefaultPawn(Pawn衍生/模板)
Character 和 DefaultPawn 等子类会自动处理此输入并移动。
以DefaultPawn举例,由输入导致的最终更新位于TickComponent中SafeMoveUpdatedComponent();
DefaultPawn作为基本实现应用类的简易角色类,是其余角色类的基本模板
UFloatingPawnMovement //运动组件,提供速度,加速度限制,没有实现重力ApplyControlInputToVelocity()//负责将存储的输入量转换为加速度或速度。这一步将输入量应用到Pawn的速度上,决定Pawn的移动方向和速度。ADefaultPawn+UFloatingPawnMovement MovementComponent //移动组件+UStaticMeshComponent MeshComponent //
输入-移动旋转流程
- 旋转由父类Pawn的FaceRotation提供,默认启用三项控制器旋转设置
- UFloatingPawnMovement::TickComponent- ApplyControlInputToVelocity()消费输入转换为- Velocity;
- Velocity转换为移动差量- Delta
- Delta用于驱动- SafeMoveUpdatedComponent()实现实际的移动
- HandleImpact()和SlideAlongSurface()处理滑动以及物理阻挡
- UpdateComponentVelocity()更新组件速度
 
Character (包含基础运动学的网络同步角色)
UCharacterMovementComponent +FVector Acceleration //加速度 由输入向量更新+FFindFloorResult CurrentFloor //当前地面信息+enum EMovementMode MovementMode //当前移动模式+float Mass //质量,用于计算加速度以及受力+bEnableScopedMovementUpdates //是否启动范围内更新优化性能+FNetworkPredictionData_Client_Character* ClientPredictionData //客户端角色移动预测数据+FNetworkPredictionData_Server_Character* ServerPredictionData //服务器角色移动预测数据--------------------------------------------------MoveAutonomous() //处理自主移动,即在不受其他外力干扰的情况下,角色根据输入指令进行移动的逻辑。MoveAlongFloor() //在地面上移动的逻辑,确保角色沿着地面正常行走,并处理地形变化。UpdateBasedRotation() //随着底座的旋转更新控制器的视图旋转StartNewPhysics() //启动新的物理处理周期,根据角色当前的移动模式和状态,调用相应的物理处理函数。PhysWalking() //处理角色在步行模式下的物理计算,包括地面摩擦力、重力等因素。PhysNavWalking() //处理角色在导航网格上步行的物理计算,通常用于AI角色的路径导航。PhysFalling() //处理角色在下落模式下的物理计算,包括重力加速度和落地检测。PhysFlying() //处理角色在飞行模式下的物理计算,包括飞行速度和方向控制。PhysSwimming() //处理角色在游泳模式下的物理计算,包括水的浮力和阻力。 PhysCustom() //处理自定义模式下的物理计算,允许开发者实现自定义的移动逻辑。CallServerMove() //在客户端上调用,向服务器发送移动请求,确保客户端和服务器上的角色位置同步。ReplicateMoveToServer() //复制移动数据到服务器,确保服务器上的角色位置和客户端的一致。ClientUpdatePositionAfterServerUpdate() //在服务器更新后,客户端更新角色位置,处理可能的位移校正。SimulatedTick() //在模拟角色(非本地控制的角色)上调用,用于处理模拟的移动和物理更新。TickCharacterPose() //每帧更新角色的姿态,确保角色动画和物理状态的同步ACharacter+FBasedMovementInfo BasedMovement //保存角色当前所站立的“基础”对象的信息,用于处理角色在移动平台上或其他移动基础上的相对位置和旋转。+FBasedMovementInfo ReplicatedBasedMovement //复制的基于移动的信息,用于网络同步,确保客户端和服务器上的基于移动状态一致。+uint8 ReplicatedMovementMode //复制的移动模式,用于网络同步,确保客户端和服务器上的移动模式一致。+float ReplicatedServerLastTransformUpdateTimeStamp //复制的服务器最后变换更新时间戳,用于网络同步,记录服务器上最后一次变换更新的时间。+TObjectPtr<UCharacterMovementComponent> CharacterMovement+TObjectPtr<USkeletalMeshComponent> Mesh+TObjectPtr<UCapsuleComponent> CapsuleComponentFBasedMovementinfo //保存有关角色所站立的“基础”对象的信息的结构。+TObjectPtr<UPrimitiveComponent> MovementBase //指向角色所站立的基础对象的指针,通常是一个移动平台或其他物理对象+FName BoneName //基础对象上的骨骼名称,如果角色站立在一个骨骼网格的特定骨骼上,则记录该骨骼的名称。+FVector_NetQuantize100 Location //角色相对于基础对象的位置,使用网络量化格式确保高效同步。+FRotator Rotation //角色相对于基础对象的旋转。+bool bServerHasBaseComponent //表示服务器是否拥有基础组件。+bool bRelativeRotation //表示角色是否相对于基础对象进行旋转。+bool bServerHasVelocity //表示服务器是否拥有基础对象的速度信息。
输入-移动旋转流程(玩家)
//以下是接受控制器输入状态的角色,也就是玩家角色的流程
常规的第三人称/第一人称 角色移动逻辑:
AddControllerPitch/Yaw/RollInput //添加对应的控制器旋转
更新ControlRotation
AddMovementInput //添加移动向量
移动输入向量被转换为加速度向量,后续在各类动力学模式中被处理为速度进行移动
通常根据ControlRotation转换移动向量 //例如攀爬等方向为特殊需要单独处理
UCharacterMovementComponent::TickComponent()
InputVector = ConsumeInputVector(){return APawn::LastControlInputVector}
UCharacterMovementComponent::ControlledCharacterMove(InputVector, DeltaTime)
Acceleration = ScaleInputAcceleration(ConstrainInputAcceleration(InputVector));
PerformMovement() //完整的移动处理流程
FScopedMovementUpdate // 延迟更新
StartNewPhysics() //在这里处理不同状态下的移动逻辑
switch (MovementMode){ PhysWalking PhysNavWalking PhysFalling PhyFlying PhysSwimming PhysCustom }
CalcVelocity() //根据加速度计算速度
SafeMoveUpdatedComponent()  //核心移动逻辑(每个分支均会包括)
PhysicsRotation()//核心旋转逻辑。
ComputeOrientToMovementRotation()
// 根据当前运动计算目标旋转,当使用bOrientRotationToMovement时,基于加速度计算旋转
正常在地面上的流程栈帧:
![[6bbc850572a1f714064411937e50411e.png]]
PerformMovement
处理绝大部分情况下的每帧运动,是CharacterMovementComponent的核心,其中包含范围更新移动代码块。此代码块为PerformMovement的核心
tips:以目的做流程,子列表为核心函数
处理流程如下
- 计时/前置验证
- SCOPE_CYCLE_COUNTER(性能统计)
- HasValidData()/- GetWorld()前置有效性检查
 
- 瞬移检测
- 更新 bTeleportedSinceLastUpdate 用于在地面上瞬移后强制检测地面
 
- 早退(不能移动的情况)
- 若 MovementMode == MOVE_None或UpdatedComponent不可动或在物理仿真中:
- 处理 root motion 的消耗(若不是客户端更新且不忽略根运动),清空/消费 root motion,清除累计力,然后返回。
 
- 若 
- 基于移动的地面检查准备
- bForceNextFloorCheck |= (IsMovingOnGround() && bTeleportedSinceLastUpdate);如果我们在地上且发生瞬移,强制下一帧做地面检查。
 
- root motion 的增量调整
- CurrentRootMotion.LastPreAdditiveVelocity += Adjustment;
 
- 保存旧状态(调试用)
- 开始范围移动更新(性能/一致性保障)
- FScopedCapsuleMovementUpdate ScopedMovementUpdate(UpdatedComponent, bEnableScopedMovementUpdates);减少重复性碰撞检测
 
- 根据基座运动更新或者延迟更新位置
- MaybeUpdateBasedMovement(DeltaSeconds)- UpdateBasedMovement(DeltaSeconds)- UpdateBasedRotation(FinalRotation, PawnDeltaRotation.Rotator());
 
 
 
- 清理无效的 RootMotion Source
- CurrentRootMotion.CleanUpInvalidRootMotion(DeltaSeconds, *CharacterOwner, *this);
 
- 应用累计外力
- ApplyAccumulatedForces(DeltaSeconds):把外部施加到 character 的力(launch、external forces)转换为速度/影响。
 
- 更新角色状态(移动前)
- UpdateCharacterStateBeforeMovement(DeltaSeconds);移动前修正状态 //源码中为蹲伏状态的切换
 
- 检查MOVE_NavWalking
- TryToLeaveNavWalking();查询是否需要做离开导航步行状态的转换
 
- 处理延迟的 Launch
- HandlePendingLaunch() Character::LaunchCharacter()被延迟执行时在此生效
- ClearAccumulatedForces清除累计力
 
- 准备/收集 Root Motion(在物理前)
- 存在根运动且不由客户端更新:
- `IsPlayingRootMotion()
- TickCharacterPose(),并转换动画 local->world。
 
- CurrentRootMotion.PrepareRootMotion(...):准备合成/累积来自非动画来源的 root motion。
 
- `IsPlayingRootMotion()
 
- 存在根运动且不由客户端更新:
- 应用 Root Motion 到 Velocity
- HasAnimRootMotion()animation root motion 转成世界空间速度,覆盖- Velocity- `RootMotionParams = ConvertLocalRootMotionToWorld()
- AnimRootMotionVelocity = CalcAnimRootMotionVelocity()
- Velocity = ConstrainAnimRootMotionVelocity()
 
- else- 若 HasOverrideVelocity,合成 override velocity 到Velocity。
 
- 若 
 
- NaN 校验
- 宏 ensureMsgf(!Velocity.ContainsNaN()确保速度合法,避免灾难性崩溃
 
- 宏 
- 清除跳跃输入与计数
- CharacterOwner->ClearJumpInput(DeltaSeconds);
- NumJumpApexAttempts = 0;
 
- 主要物理移动调用
- StartNewPhysics(DeltaSeconds, 0)真正移动角色地方,存在基本的动力学
 
- 再次验证有效性
- 移动后更新角色
- UpdateCharacterStateAfterMovement(DeltaSeconds);移动后修正状态 //源码中为蹲伏状态的切换
 
- 旋转处理
- PhysicsRotation(DeltaSeconds);
 
- 应用 Root Motion 的旋转
- `HasAnimRootMotion()
- MoveUpdatedComponent(FVector::ZeroVector, NewActorRotationQuat, true)}
 
- CurrentRootMotion.HasActiveRootMotionSources()- MoveUpdatedComponent(FVector::ZeroVector, NewActorRotationQuat, true);
 
 
- `HasAnimRootMotion()
- 消费路径跟随请求速度
- `LastUpdateRequestedVelocity = bHasRequestedVelocity ? RequestedVelocity : FVector::ZeroVector;
- bHasRequestedVelocity = false;
 
- 触发移动更新回调
- OnMovementUpdated(DeltaSeconds, OldLocation, OldVelocity);
 
- 结束范围移动更新
- 退出 FScopedCapsuleMovementUpdate,让变换/碰撞状态最终生效。
 
- 退出 
- 外部事件回调
- CallMovementUpdateDelegate(DeltaSeconds, OldLocation, OldVelocity):广播外部监听者(在 scoped update 之外,以便事件能看到最终 Overlaps 等)。
 
- 保存/更新基座位置选项
- 根据 CVar 选择 SaveBaseLocation()或MaybeSaveBaseLocation()(修复/优化相关行为)。
 
- 根据 CVar 选择 
- 更新组件速度缓存
- UpdateComponentVelocity():把 movement component 的- Velocity同步到 UpdatedComponent 的 velocity 等。
 
- 网络相关:尽早取消自适应频率 Throttle
- 在服务器权威下,如果 actor 移动了并且网络更新在被节流,可能会调用 NetDriver->CancelAdaptiveReplication(CharacterOwner)来确保快速同步。
 
- 在服务器权威下,如果 actor 移动了并且网络更新在被节流,可能会调用 
- 计算/保存本帧最终位置/旋转并在服务端处理 timestamp
- NewLocation = UpdatedComponent->GetComponentLocation(),- NewRotation = UpdatedComponent->GetComponentQuat()。若 server 且 transform 改变,保存- ServerLastTransformUpdateTimeStamp(有条件使用客户端时间戳)。
 
- 保存 LastUpdateLocation/Rotation/Velocity
- LastUpdateLocation = NewLocation; LastUpdateRotation = NewRotation; LastUpdateVelocity = Velocity;—— 用于下一帧比较/差分和网络预测。
 
工程要点:
在CharacterMovementComponent中处理旋转的是PhysicsRotation:其核心变量为DesiredRotation
由Orient Rotation to movement和bUseControllerDesiredRotation决定DesiredRotation计算方式
ComputeOrientToMovementRotation();//根据当前运动计算目标旋转,当使用bOrientRotationToMovement时,基于加速度计算旋转
UpdateBasedRotation :当角色所依附的 Base(比如旋转的平台/载具/重力基座)发生旋转 时,同步调整角色相关的朝向(主要是 Controller 的 ControlRotation / 视角)并根据设置决定是否把基座的 roll (翻滚)应用到角色/摄像机上。它在 PerformMovement 中计算出 pawn 因基座旋转产生的增量旋转(delta) 后被调用,允许移动组件修正最终的角色朝向或对控制器视角做额外处理。
旋转基座处理的调用栈
PerformMovement
MaybeUpdateBasedMovement
UpdateBasedMovement
UpdateBasedRotation //前置有移动基座的判断,只有进入移动基座才会在此进入这个
关于添加推动力 两个一个描述为一次性推动 一个为每帧推动,实际上完全相同。且每帧推动还会被*帧 使其大量缩减