UE 角色移动与 Locomotion 系统设计完全指南
前言
Locomotion(运动系统)是角色动画的灵魂。再华丽的外观,如果走路僵硬、转向迟钝、跳跃违和,整个角色就会失去「生命感」。UE 的 Character Movement Component 与动画系统深度耦合,提供了从移动速度到地面检测的一切基础设施——但如何把这些底层数据转化为流畅、自然的角色动作,需要开发者对两者的衔接机制有清晰理解。
本文聚焦 Walk / Jog / Sprint 步态设计、根骨骼运动、转向动画匹配、跳跃落地系统、以及 IK 足部 placement 五大核心主题。
一、速度体系与步态设计
1.1 UE 的速度档位
UE Character Movement Component 内置了清晰的速度层级:
| 速度参数 | 默认值 | 用途 |
|---|---|---|
MaxWalkSpeed |
175 cm/s | 行走速度上限 |
MaxJogSpeed |
335 cm/s | 慢跑/冲刺 |
MaxSprintSpeed |
600 cm/s | 全力冲刺 |
MaxCrouchSpeed |
160 cm/s | 蹲行 |
MaxSwimSpeed |
256 cm/s | 水中移动 |
在 Project Settings → Character Controller 中可全局调整,也可运行时通过蓝图或 C++ 动态修改。
1.2 三档步态实现
典型的三档步态(Walk → Jog → Sprint)通过 Blend Space 1D + AnimBP 变量 实现:
AnimBP EventGraph:
Character.GetMovementComponent → Is Sprinting?
↓
Set SprintSpeed / WalkSpeed
↓
AnimBP AnimGraph:
Speed Variable (0~600) → BlendSpace1D (Walk/Jog/Sprint)
↓
Output Pose
1.3 地面 / 空中 / 水下检测
// C++ 获取当前运动状态
UCharacterMovementComponent* MoveComp = Character->GetCharacterMovement();
if (MoveComp->IsFalling()) {
// 空中状态
} else if (MoveComp->IsSwimming()) {
// 水中状态
} else if (MoveComp->IsWalking()) {
// 地面状态(会自动处理斜坡)
}
// 获取当前地面法线(用于斜坡适配)
FVector GroundNormal = MoveComp->CurrentFloor.HitResult.ImpactNormal;
1.4 动态速度调整
// 蓝图等效:在 Character Blueprint 中
Event Tick
→ Branch (IsExhausted == true)
→ Set MaxWalkSpeed (100) // 疲惫状态减速
→ Set MaxJogSpeed (200)
→ Branch (IsSprinting == true && Stamina > 0)
→ Set MaxJogSpeed (600) // 冲刺状态
二、根骨骼运动 vs 完全复制运动
2.1 两种运动模式
UE 中角色的实际位置移动有两种模式:
模式一:完全复制运动(Root Motion from Montages OFF)
– 动画只负责「看起来在动」,实际位移由 Character Movement Component 计算
– 优点:网络同步简单、碰撞可靠
– 缺点:动画与位移可能不完全匹配
模式二:根骨骼运动(Root Motion from Montages / Anim Drives Motion)
– 动画的根骨骼位移直接驱动角色实际移动
– 优点:动画与位移完全匹配,无滑步
– 缺点:需要精确动画,网络同步复杂
2.2 何时用哪种
| 场景 | 推荐模式 |
|---|---|
| 普通走/跑/跳 | 复制运动 |
| 翻滚(Roll)/ 起身 | 根骨骼 |
| 攀爬(Climb) | 根骨骼 |
| 攻击位移(如突进) | 根骨骼 Montage |
| 受击后仰 | 根骨骼 |
2.3 配置方式
在 Character Movement Component 中:
CharacterMovementComponent:
bRequestedMoveUseAcceleration: True # 是否使用加速度
NavAgentProps:
bRequestedMoveUseAcceleration: False # AI 路径移动不用加速度
RootMotion:
bHasRootMotionSources: False # 是否允许根骨骼驱动
在 Animation Blueprint 中:
AnimGraph:
UseNormalizedBlendSpaceAssetPlayerTime → 支持时间驱动
RootMotionMode → "Root Motion from Montages Only"
2.4 bUseControllerRotationYaw
这个布尔值决定了角色是否「跟随控制器朝向旋转」:
// 玩家角色通常设为 false,由动画系统处理转身
Character->bUseControllerRotationYaw = false;
// AI 角色通常设为 true,由 AIController 驱动朝向
AIController->bActivateAINavSystem = true;
配合 Orient Rotation to Movement 使用时,角色会自动朝运动方向旋转,转身动画由 Blend Space 或 Turn In Place 驱动。
三、转向与动画匹配
3.1 转向的三种模式
| 模式 | 适用场景 | 实现难度 |
|---|---|---|
| Directional(方向步态) | 原地转向时播放转身动画 | 简单 |
| Turn In Place | 超过角度阈值时原地转身 | 中等 |
| Blend Turn In Place | 小角度快速转身用原地 Blend | 复杂 |
3.2 Directional 步态
Directional 步态下,Blend Space 2D 的 X 轴是 Speed,Y 轴是 Direction(相对角色的朝向角度):
角色朝向(0°)
↑
90° ← | → -90°
向左跑 | 向右跑
|
180° ← → -180°
|
背面跑
这种模式下,角色奔跑动画包含「左倾 / 右倾 / 正面 / 背面」四个方向的变体,Blend Space 自动混合。
3.3 Turn In Place(原地转身)
当转向角度超过阈值(通常是 90°)时,播放原地转身动画:
转向角度检测:
DeltaAngle = abs(ActorRotation.Yaw - LastRotation.Yaw)
if (DeltaAngle > 90 && GroundSpeed < 50)
→ 播放 Turn_90 或 Turn_180 动画
3.4 转身角度阈值设置
// 在 AnimBP EventGraph 中计算转身角度
FVector Velocity2D = GetWorld()->GetFirstPlayerController()->GetPawn()->GetVelocity();
Velocity2D.Z = 0;
FRotator VelocityAngle = Velocity2D.Rotation();
float TurnAngle = FMath::FindDeltaAngleDegrees(
GetOwningActor()->GetActorRotation().Yaw,
VelocityAngle.Yaw
);
// 设置到 AnimBP 变量,供 Blend Space 或 Turn 状态机使用
TurnAngleRaw = TurnAngle;
TurnAngle = FMath::GridSnap(TurnAngle, 45.0f); // 吸附到 45° 步进
四、跳跃、落地与受击
4.1 跳跃状态时序
完整的跳跃时序:
[Walk/Jog/Running]
↓ (按下 Jump)
[Jump Start] (起跳蓄力/起跳动画, ~0.1s)
↓
[InAir] (空中浮空/下落动画, 持续时间)
↓ (检测地面)
[Land] (落地动画, ~0.2s)
↓
[Land Recovery] (恢复平衡, ~0.3s)
↓
[Idle/Run] (回到 Locomotion)
4.2 落地预判(Land Anticipation)
高质量的 Locomotion 系统会在落地前根据 下落高度 播放不同强度的落地动画:
// 根据下落高度选择落地强度
float FallHeight = LastAirLocation.Z - CurrentLocation.Z;
float LandScale = FMath::GetMappedRangeValueClamped(
FVector2D(200.0f, 1000.0f), // 下落高度范围
FVector2D(1.0f, 3.0f), // 落地动画强度
FallHeight
);
AnimInstance->SetLandRecoveryScale(LandScale);
4.3 受击反应(Hit React)
受击反应需要游戏逻辑通知动画系统:
// 游戏逻辑(Character 或 Gameplay Ability)
void AMyCharacter::OnTakeHit(FHitResult Hit, FVector ImpulseDir) {
// 计算击打方向(正面/侧面/背面)
FVector Forward = GetActorForwardVector();
float Dot = FVector::DotProduct(ImpulseDir, Forward);
if (Dot > 0.3f) {
// 正面击打 → Hit_Forward
} else if (Dot < -0.3f) {
// 背面击打 → Hit_Backward
} else {
// 侧面击打 → Hit_Left / Hit_Right
}
// 播放受击 Montage
UAnimMontage* HitMontage = HitReactMontage.LoadSynchronous();
AnimInstance->Montage_Play(HitMontage);
}
受击后自动过渡回 Locomotion 状态,通常通过 Montage 的 Blend Out 时间控制。
4.4 Ragdoll 状态切换
Ragdoll(布娃娃物理)通常用于死亡或严重受击:
Locomotion State Machine:
Any State → [Ragdoll]
↑ ↓
← (Blend Out, ~0.3s)
// C++ 启用 Ragdoll
void AMyCharacter::EnableRagdoll() {
GetMesh()->SetAllBodiesSimulatePhysics(true);
GetMesh()->SetSimulatePhysics(true);
GetMesh()->WakeAllRigidBodies();
// 关闭 Character Movement
GetCharacterMovement()->DisableMovement();
GetCharacterMovement()->StopMovementImmediately();
}
五、IK 足部 Placement
5.1 什么是 Foot IK
Foot IK 是通过 程序化方式 调整角色足部位置,使其自然贴合地面的技术。即使角色站在斜坡或台阶上,足部也能「贴」在地面上,而不是悬空或穿模。
5.2 Two Bone IK 节点
UE 提供 Two Bone IK 节点用于处理四肢 IK:
AnimGraph:
Foot IK
├── Effector Location (从地面检测获取)
├── Joint Target Location (膝部 IK 目标)
└── Bone Name (Foot_L / Foot_R)
5.3 地面检测实现
// 在 Character Blueprint 的 EventGraph 中
// 每帧 Raycast 检测地面高度
FVector Foot_L_Location = GetMesh()->GetSocketLocation("foot_l");
FVector Foot_R_Location = GetMesh()->GetSocketLocation("foot_r");
FCollisionQueryParams Params;
Params.AddIgnoredActor(this);
FHitResult Hit_L, Hit_R;
GetWorld()->LineTraceSingleByChannel(Hit_L, Foot_L_Location,
Foot_L_Location + FVector::DownVector * 100.0f,
ECC_Visibility, Params);
GetWorld()->LineTraceSingleByChannel(Hit_R, Foot_R_Location,
Foot_R_Location + FVector::DownVector * 100.0f,
ECC_Visibility, Params);
// 计算 Pelvis(盆骨)偏移
float PelvisOffset = FMath::Min(Hit_L.ImpactPoint.Z, Hit_R.ImpactPoint.Z)
- GetMesh()->GetSocketLocation("pelvis").Z;
// 设置到 AnimBP
AnimBP->PelvisOffset = PelvisOffset;
AnimBP->FootIK_L_Effector = Hit_L.ImpactPoint;
AnimBP->FootIK_R_Effector = Hit_R.ImpactPoint;
5.4 Pelvis 深度补偿
Pelvis(盆骨)需要根据两脚落地高度的差异做补偿:
// 盆骨高度 = 两脚最低点高度 - 预设偏移
float PelvisHeight = FMath::Min(Hit_L.ImpactPoint.Z, Hit_R.ImpactPoint.Z)
- BasePelvisOffset;
AnimBP->SetPelvisTargetHeight(PelvisHeight);
// 膝盖 IK 目标位置(防止膝盖穿模)
FVector KneeTarget_L = Foot_L_Location + FVector::UpVector * 50.0f
+ ForwardVector * 20.0f;
AnimBP->SetKneeTarget_L(KneeTarget_L);
5.5 斜坡适应性
当 CurrentFloor.HitResult.ImpactNormal 与垂直方向有夹角时,说明角色站在斜坡上:
FVector FloorNormal = MoveComp->CurrentFloor.HitResult.ImpactNormal;
float SlopeAngle = FMath::RadiansToDegrees(
FMath::Acos(FVector::DotProduct(FloorNormal, FVector::UpVector))
);
if (SlopeAngle > 5.0f) {
// 应用斜坡旋转到角色基底
FRotator SlopeRotation = FRotator(
-SlopeAngle * ForwardVector.Y,
0,
SlopeAngle * ForwardVector.X
);
AddActorLocalRotation(SlopeRotation);
}
六、总结:Locomotion 调试清单
在完成 Locomotion 系统后,按以下清单逐项检查:
- [ ] 滑步检查:角色实际移动距离是否与动画位移匹配
- [ ] 转身检查:快速连续转身是否有动画断裂
- [ ] 斜坡检查:站在 30° 斜坡上,足部是否穿模
- [ ] 跳跃检查:长短跳跃高度 / 落地区间是否符合预期
- [ ] 落地检查:不同高度落地是否有不同强度的落地动画
- [ ] 网络检查:P2P / Server 模式下,同步延迟是否导致动画抖动
- [ ] 性能检查:
IsInGameThreadCheck确保每帧动画计算量合理
推荐参考资料:
– ALS 社区版(ShadowfallStudios/ALS-Community)——最完整的 UE5 Locomotion 参考实现
– UE 官方 Gameplay Framework 文档——Character Movement Component 详细参数
– 「Animation Boot Camp」GDC 演讲——AAA 游戏 Locomotion 设计思路
本文收录于 Matrix4x4 AI 编程与游戏开发资源库