[UE学习笔记][基于源码] 控制器、Pawn、相机的控制关系

[UE学习笔记][基于源码] 控制器、Pawn、相机的控制关系

基于 UE 5.7 引擎源码

理清 Controller / PlayerController / Pawn / Character / CharacterMovementComponent / SpringArm / Camera / PlayerCameraManager 之间"谁持有什么、谁改谁"。

先盘点状态变量 ,再讲过程怎么读写它们------从"数据"到"流程"建立心智模型。


1. 核心状态变量

只列与"控制 / 移动 / 视点"直接相关的字段。

1.1 AController(基类)

抽象的"控制者",只有一个 Pawn 引用、一个朝向意图。

字段 类型 含义 默认
Pawn TObjectPtr<APawn> 当前控制的 Pawn(通过 Possess/UnPossess 改) nullptr
Character TObjectPtr<ACharacter> Pawn 是 Character 时的别名 nullptr
PlayerState TObjectPtr<APlayerState> 玩家信息(昵称、分数等),可复制 nullptr
ControlRotation FRotator 核心:玩家"想看哪儿"的朝向,权威源 (0,0,0)

1.2 APlayerController(在 AController 之上加了什么)

人类玩家专用,新增"输入"和"相机管理"两组字段。

字段 类型 含义 默认
PlayerInput TObjectPtr<UPlayerInput> 按键 / 轴的"原始账本",输入流入口 OverridePlayerInputClassInputSettings.DefaultPlayerInputClass Spawn
RotationInput FRotator 本帧鼠标 / 手柄累积的"旋转增量",每帧消费后清零 (0,0,0)
PlayerCameraManager TObjectPtr<APlayerCameraManager> 视点管理器,每个 PlayerController 一个 PostInitializeComponents 中 Spawn
PlayerCameraManagerClass TSubclassOf<APlayerCameraManager> Spawn 时用哪个类 APlayerCameraManager::StaticClass()
bAutoManageActiveCameraTarget bool Possess 时是否自动把新 Pawn 设为 ViewTarget true
MyHUD TObjectPtr<AHUD> UI 入口 nullptr

1.3 APawn

被控制对象的基类,承担"被谁控制"和"要往哪儿走"两件事的存储。

字段 类型 含义 默认
Controller TObjectPtr<AController> 反向指针 :谁在控制我(由 PossessedBy 设置) nullptr
PlayerState TObjectPtr<APlayerState> Controller.PlayerState 同步的镜像 nullptr
bUseControllerRotationPitch uint32:1 Pawn.Rotation.Pitch 是否每帧同步成 Controller.ControlRotation.Pitch false
bUseControllerRotationYaw uint32:1 同上,Yaw false
bUseControllerRotationRoll uint32:1 同上,Roll false
BaseEyeHeight float 计算视点位置时的眼高偏移 64
ControlInputVector FVector 本帧累积的"移动输入向量"(世界空间),Movement Tick 后清零 (0,0,0)
LastControlInputVector FVector 上一帧的副本,给查询用 (0,0,0)

Pawn 自己没有 ControlRotationPawn.GetViewRotation() 默认实现 = Controller ? Controller->GetControlRotation() : ActorRotation

1.4 ACharacter(在 APawn 之上加了什么)

把"角色三件套"持有起来,并加了跳跃状态。

字段 类型 含义 默认
CapsuleComponent TObjectPtr<UCapsuleComponent> 碰撞胶囊(RootComponent) 构造时创建
Mesh TObjectPtr<USkeletalMeshComponent> 角色骨骼网格 构造时创建
CharacterMovement TObjectPtr<UCharacterMovementComponent> 位移引擎 构造时创建
bPressedJump uint8:1 玩家是否按住跳键 false
JumpKeyHoldTime float 按住时长 0
JumpMaxHoldTime float 最大允许按住时长 0
JumpMaxCount int32 最多连跳次数 1
JumpCurrentCount int32 已跳次数 0

ACharacter 构造里会把 bUseControllerRotationYaw 改回 true------所以默认 Character 的身体跟着鼠标转。

1.5 UCharacterMovementComponent

真正"动起来"的地方,持有速度 / 加速度 / 移动模式 / 朝向开关。

字段 类型 含义 默认
CharacterOwner TObjectPtr<ACharacter> 反向指针 自动绑定
UpdatedComponent(基类) USceneComponent* 实际被挪动的组件(= Character 的 Capsule) Capsule
Velocity(基类) FVector 当前速度 (0,0,0)
Acceleration FVector 当前加速度(来自 ControlInputVector 归一化方向 × MaxAcceleration (0,0,0)
MovementMode EMovementMode Walking / Falling / Flying / Swimming / Custom MOVE_None(Possess 后由 SetDefaultMovementMode 切到 DefaultLandMovementMode,默认 MOVE_Walking
bOrientRotationToMovement uint8:1 角色朝向移动方向 (覆盖 bUseControllerDesiredRotation false
bUseControllerDesiredRotation uint8:1 角色平滑转向 ControlRotation false
RotationRate FRotator 上述两种转向的速度上限(度/秒) (0, 360, 0)
JumpZVelocity float 跳跃初速 420
MaxWalkSpeed float 行走最大速 600
GravityScale float 重力倍率 1.0

1.6 USpringArmComponent

只决定"相机末端的位置和朝向",自身不渲染

字段 类型 含义 默认
TargetArmLength float 吊臂自然长度 300
SocketOffset FVector 末端 socket 偏移(最常用,决定相机位置) (0,0,0)
TargetOffset FVector 起点的世界空间偏移 (0,0,0)
bUsePawnControlRotation uint32:1 吊臂朝向 = Pawn.GetViewRotation()(即 ControlRotation false
bInheritPitch uint32:1 是否继承父组件 Pitch true
bInheritYaw uint32:1 是否继承父组件 Yaw true
bInheritRoll uint32:1 是否继承父组件 Roll true
bDoCollisionTest uint32:1 被遮挡时是否回弹 true
bEnableCameraLag uint32:1 位置是否平滑跟随 false
bEnableCameraRotationLag uint32:1 旋转是否平滑跟随 false

1.7 UCameraComponent

只决定镜头参数(FOV / 后处理等),位置由父级(通常是 SpringArm 末端)决定。

字段 类型 含义 默认
FieldOfView float 透视 FOV(度) 90
AspectRatio float 宽高比 1.777778
bConstrainAspectRatio uint8:1 是否强制宽高比(不匹配时加黑边) false
PostProcessSettings FPostProcessSettings 后处理 默认结构
bUsePawnControlRotation uint8:1 没有 SpringArm 时,自己跟控制器旋转 false

1.8 APlayerCameraManager

视点的"出口":选定 ViewTarget、调它的 CalcCamera、缓存 POV、跑修饰器栈。

字段 类型 含义 默认
PCOwner TObjectPtr<APlayerController> 反向指针 Spawn 时绑定
ViewTarget FTViewTarget 当前观察对象(一般 = 当前 Pawn)+ 缓存的 POV
PendingViewTarget FTViewTarget 切换中的目标(用于混合)
CameraStyle FName "Default" / "Fixed" / "FreeCam" 等模式 "Default"
DefaultFOV float 没有 CameraComponent 时的兜底 FOV 90
CameraCachePrivate FCameraCacheEntry 上一帧算出的 POV 缓存
ModifierList TArray<UCameraModifier*> 后处理混合栈(震屏等)

2. 重要动作和开关------发生了什么

按"动作 / 开关"逐节展开,每节回答"它到底改了什么状态、玩家看到什么差异"。

时序图说明:🔓 表示虚函数(C++ 可重写)。

2.1 Add Yaw Input 发生了什么

这一步只做累加 ------把鼠标增量加到 APlayerController.RotationInput,不立即生效。
APlayerController APawn 蓝图 APlayerController APawn 蓝图 RotationInput.Yaw += Val Add Controller Yaw Input(Val) 1 AddYawInput(Val) 2

调用本身就到这里。真正"消费 RotationInput 写入 ControlRotation、并把朝向同步给 Pawn / SpringArm" 的过程在后续小节展开------这里只是生产端

2.2 启用 Pawn 的 bUseControllerRotationPitch / Yaw / Roll 会发生什么

让 Pawn 的身体 跟着 ControlRotation 转。这一节顺便把 2.1 累积起来的 RotationInput怎么、什么时候被消费 也画出来------UpdateRotation 内部一气呵成。
APawn APlayerCameraManager APlayerController APawn APlayerCameraManager APlayerController TG_PrePhysics 局部 ViewRot = GetControlRotation() 局部 DeltaRot = RotationInput 跑 ModifierList 链 OutViewRot += OutDeltaRot;OutDeltaRot = 0 LimitViewPitch / Yaw / Roll 直接 return,不写 ActorRotation 关掉的轴回退到 ActorRotation 当前值 alt [三个 bUseControllerRotation* 全为 false] [任一为 true] TickActor 末尾:RotationInput = ZeroRotator 🔓 TickActor(DeltaTime) 1 🔓 PlayerTick(DeltaTime) 2 🔓 UpdateRotation(DeltaTime) 3 🔓 ProcessViewRotation(DeltaTime, ViewRot&, DeltaRot&) 4 返回(ViewRot 已按引用更新) 5 SetControlRotation(ViewRot) 6 🔓 FaceRotation(ViewRot) 7 SetActorRotation(ViewRot) 8

2.3 启用 SpringArm 的 bUsePawnControlRotation / bInheritPitch / Yaw / Roll 会发生什么

AController APawn USpringArmComponent AController APawn USpringArmComponent TG_PostPhysics DesiredRot = GetComponentRotation()(默认基底) DesiredRot = ControlRotation alt [bUsePawnControlRotation == true] DesiredRot.Pitch = RelativeRotation.Pitch alt [!bInheritPitch] DesiredRot.Yaw = RelativeRotation.Yaw alt [!bInheritYaw] DesiredRot.Roll = RelativeRotation.Roll alt [!bInheritRoll] alt [!IsUsingAbsoluteRotation()] 用 DesiredRot 计算 SocketTransform,末端 Camera 跟随 🔓 TickComponent(DeltaTime) 1 🔓 UpdateDesiredArmLocation(...) 2 GetTargetRotation() 3 🔓 GetViewRotation() 4 GetControlRotation() 5 ControlRotation 6 返回 ControlRotation 7 返回 DesiredRot 8

典型用法

配置 表现
关掉 bInheritPitch 相机水平面跟玩家转,但俯仰恒定(俯视 / 仰视固定相机)
关掉 bInheritYaw 相机朝固定方向,玩家在画面内自由转身(横版固定视角)
全部关掉 相机姿态完全由 SpringArm 自身 RelativeRotation 决定,跟谁都不跟

2.4 Add Movement Input 发生了什么

UCharacterMovementComponent APawn 蓝图 UCharacterMovementComponent APawn 蓝图 ControlInputVector += WorldAccel TG_PrePhysics LastControlInputVector = ControlInputVector ControlInputVector = ZeroVector 用 InputVector 算 Acceleration / Velocity / 写 Capsule 位置 🔓 Add Movement Input(WorldDir, Scale) 1 🔓 AddInputVector(WorldDir * Scale) 2 Internal_AddMovementInput(WorldAccel) 3 🔓 TickComponent(DeltaTime) 4 ConsumeInputVector() 5 Internal_ConsumeMovementInputVector() 6 返回 InputVector 7 🔓 PerformMovement(DeltaSeconds) 8

关键AddYawInputPlayerController 的成员(人类玩家专属 ),AddMovementInputPawn 的成员(AI 也用同一个 )------这就是为什么 AI 和玩家的"走路"汇合在 ControlInputVector 这一层,而"看哪儿"对 AI 而言走的是另一套(直接给 Controller SetControlRotation)。

相关推荐
Fabarta技术团队2 小时前
务实、灵活——枫清科技财务单证智能审核方案 以AI自学习驱动审核提效与规则进化
人工智能·科技·学习
Qinn-2 小时前
【工作笔记】锁等待超时错误 排查
笔记
星幻元宇VR2 小时前
VR科普赛车|沉浸式学习交通安全知识
科技·学习·安全·生活·vr
LeeeX!3 小时前
【OpenClaw最新版本】 命令行备忘录:高频操作与实战技巧
笔记·aigc·openclaw
KuaCpp3 小时前
Linux从0到1学习
linux·学习
羊群智妍3 小时前
2026免费GEO工具,AI搜索优化一步到位
笔记
tryqaaa_3 小时前
学习日志(一)【含markdown语法,Linux学习】
linux·运维·学习·web安全·web·markdown
Leah-3 小时前
Web项目测试流程
笔记·学习·web·测试·复盘
Qinn-4 小时前
【学习笔记】软考系统分析师计算机系统计算题考点
笔记