P-003 步骤④程序设计产出: - player-controller-tech.md: 角色控制系统(参数调整+输入绑定,2-3天) - interaction-system-tech.md: 交互系统核心框架(状态机+推镜+物品中转,5-7天) - collection-system-tech.md: 收集系统进度追踪+通知UI(1-2天) 覆盖三份执行案全部行为规则,含美术需求清单和技术风险分析。 等待 PM 质量门审查。
12 KiB
角色控制技术设计文档(v0.1 原型)
任务ID: P-003(部分) 对应执行案:
docs/design/prototype/player-controller-execution.md阶段: 原型 日期: 2026-06-06
概述
角色控制系统基于现有 AChildHoodCharacter + AChildHoodPlayerController 框架进行参数调整和少量代码修改。核心架构(SpringArm 摄像机 + Enhanced Input + CMC 移动)已就绪,v0.1 工作以配置级调整为主,不引入新的类或组件。
实现复杂度:低 预估工期:2-3 天 新增/修改代码量:约 80-100 行 C++
类与组件架构
修改现有类
| 类 | 修改内容 | 代码量 |
|---|---|---|
AChildHoodCharacter |
移除跳跃、调整 CMC/SpringArm 参数、添加交互状态标志、新增交互相关 IA 绑定 | ~60 行 |
AChildHoodPlayerController |
调整 Pitch 限幅(通过 CameraManager) | ~5 行 |
不新增类
v0.1 角色控制系统不引入新类。所有功能通过修改现有类的参数和少量逻辑实现。
组件挂载关系(不变)
AChildHoodCharacter
├── UCapsuleComponent (Root) — 碰撞胶囊体
├── USkeletalMeshComponent (Mesh) — 角色网格
├── USpringArmComponent (CameraBoom) — 摄像机摇臂
└── UCameraComponent (FollowCamera) — 跟随摄像机
AChildHoodPlayerController
├── APlayerCameraManager — 摄像机管理器(设置 Pitch 限幅)
└── UEnhancedInputComponent — 输入组件
└── IMC 注册(通过 DefaultMappingContexts)
行为规则 → 实现方案映射
一、摄像机系统
C1. 默认位置(距离 3.5m / 高度 0.8m / 俯角 15°)
实现:构造函数中配置 SpringArm 参数
// AChildHoodCharacter 构造函数
CameraBoom->TargetArmLength = 350.0f; // 3.5m 距离
CameraBoom->SocketOffset = FVector(0.f, 0.f, 80.f); // 0.8m 高于角色
// 初始俯角由 Controller Pitch 控制,在 PlayerController 中设置初始旋转
可调参数:TargetArmLength, SocketOffset.Z
C2. 软跟随(3-5x 角色移动速度)
实现:启用 SpringArm 原生 Camera Lag
CameraBoom->bEnableCameraLag = true;
CameraBoom->CameraLagSpeed = 6.0f; // 可调,范围 2-8
CameraBoom->bEnableCameraRotationLag = false; // v0.1 不启用旋转延迟
可调参数:CameraLagSpeed
C3. 视角旋转(水平 150°/s,垂直 +45°/-30°)
水平旋转实现:通过 Enhanced Input IA 的 Value 值 × PlayerController::InputYawScale 控制。
// InputYawScale 在 PlayerController 中设置
// 灵敏度通过 IA 的 Scale 值控制,不需要自定义旋转速度限制
// UE5 鼠标输入是相对移动,不受固定 °/s 限制
// v0.1 使用默认鼠标输入灵敏度,后续版本可加灵敏度滑块
垂直限幅实现:在 CameraManager 中设置
// AChildHoodPlayerController::BeginPlay 或构造函数中
PlayerCameraManager->ViewPitchMin = -30.0f; // 向下看最多 30°
PlayerCameraManager->ViewPitchMax = 45.0f; // 向上看最多 45°
注:执行案中 150°/s 是手柄摇杆的设计参考值。键鼠模式下鼠标移动是相对输入,由玩家手速决定实际旋转速度。v0.1 优先键鼠,此参数暂不在代码中硬性限制。
可调参数:ViewPitchMin, ViewPitchMax, IA Scale
C4. 摄像机碰撞处理
实现:启用 SpringArm 原生碰撞检测
CameraBoom->bDoCollisionTest = true;
CameraBoom->ProbeSize = 12.0f; // 碰撞探针半径
CameraBoom->ProbeChannel = ECC_Camera; // 使用 Camera 碰撞通道
// 最小距离保证:SpringArm 自动缩短到碰撞面
// 当目标位置被阻挡时,SpringArm 将摄像机移到最近的未阻挡位置
// 默认行为已满足"紧贴碰撞面内侧"的要求
最小距离保证(0.5m):SpringArm 的 TargetArmLength 最短会被碰撞面推到约 0(取决于探针半径和角色胶囊体大小)。如需严格保证 0.5m 最小距离,可在蓝图中加 Tick 检查后处理。v0.1 先用原生行为,视体验再决定是否添加。
恢复:碰撞消除后 SpringArm 自动恢复到 TargetArmLength,配合 Camera Lag 实现平滑回位。
v0.1 简化:仅处理与静态几何体碰撞(默认行为),不处理动态物体。
C5. 跑动中角色始终背对摄像机
实现:已有配置满足
bUseControllerRotationYaw = false; // 角色不跟随 Controller Yaw
GetCharacterMovement()->bOrientRotationToMovement = true; // 角色朝移动方向旋转
GetCharacterMovement()->RotationRate = FRotator(0.f, 720.f, 0.f); // 转向速度 720°/s
角色转向速度 720°/s 远快于鼠标旋转速度,自然满足"摄像机追不到角色正面"的效果。无需额外逻辑。
二、移动系统
M1. 移动方向(相对摄像机,对角 45° 合成)
实现:已有 DoMove() 逻辑满足
void AChildHoodCharacter::DoMove(float Right, float Forward)
{
const FRotator Rotation = GetController()->GetControlRotation();
const FRotator YawRotation(0, Rotation.Yaw, 0);
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
AddMovementInput(ForwardDirection, Forward);
AddMovementInput(RightDirection, Right);
}
- 对角输入(W+A)由 Enhanced Input 的 2D Axis 自然处理
AddMovementInput不叠加速度(CMC 内部归一化)- 连续旋转中移动方向实时跟随摄像机朝向(每帧重新计算方向)
无需修改。
M2. 角色转向(720°/s,最短路径,边跑边转)
实现:CMC 参数配置
GetCharacterMovement()->bOrientRotationToMovement = true;
GetCharacterMovement()->RotationRate = FRotator(0.f, 720.f, 0.f);
CMC 默认走最短路径旋转,转向期间角色持续移动(不"停顿再转向")。无需修改。
M3. 跑步(4.5 m/s,起步加速 0.2s)
速度:
GetCharacterMovement()->MaxWalkSpeed = 450.0f; // 4.5 m/s (UE5 1uu = 1cm)
加速:CMC 的 MaxAcceleration 控制加速过程
// 从 0 到 450 cm/s 在 0.2s → 加速度 = 450/0.2 = 2250 cm/s²
GetCharacterMovement()->MaxAcceleration = 2250.0f;
注:CMC 加速不是严格线性,受 GroundFriction 等因素影响。2250 是起始值,实际手感需测试微调。
M4. 停止减速(0.3s)
实现:
// 从 450 到 0 cm/s 在 0.3s → 减速度 = 450/0.3 = 1500 cm/s²
GetCharacterMovement()->BrakingDecelerationWalking = 1500.0f;
同样受 GroundFriction 影响,1500 是起始值。
M5. 坡道与台阶(坡度 ≤45°,台阶 ≤0.15m)
实现:
GetCharacterMovement()->WalkableFloorAngle = 45.0f; // 最大可行走坡度
// 台阶高度由胶囊体半径和 CMC 的 StepHeight 决定
// 默认 StepOffset = 45.0f (4.5cm),覆盖 0.15m 需要调大
// 但 v0.1 场景设计避免高台阶,先保持默认
GetCharacterMovement()->SetWalkableFloorAngle(45.0f);
三、输入映射
I1. WASD/方向键 → 移动
实现:已有 IA_Move + IMC 配置。保持不变。
I2. 鼠标移动 → 视角旋转
实现:已有 IA_MouseLook + IMC 配置。保持不变。
I3. E/ESC/Tab/滚轮 → 委托交互系统
实现:在 Character 中添加交互相关 IA 指针和绑定
// 新增成员(AChildHoodCharacter.h)
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* InteractAction; // E 键
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* CancelAction; // ESC 键
UPROPERTY(EditAnywhere, Category="Input")
UInputAction* SwitchInteractAction; // Tab 键
// SetupPlayerInputComponent 中绑定
// 回调函数直接调用 InteractionManager 的对应接口
具体回调实现见交互系统技术设计文档。
I4. 移除跳跃
实现:移除 JumpAction 及其绑定
// 删除 JumpAction 成员
// 删除 SetupPlayerInputComponent 中的 Jump 绑定
// 删除 DoJumpStart/DoJumpEnd 函数
// CMC: GetCharacterMovement()->JumpZVelocity 不需要设置(不跳跃)
四、输入优先级 & 跨系统交互
P1. 交互中忽略移动输入
实现:在 DoMove() 中添加状态检查
// 新增成员
bool bIsInteracting = false;
// 修改 DoMove
void AChildHoodCharacter::DoMove(float Right, float Forward)
{
if (bIsInteracting) return; // 交互中忽略移动
// ... 原有逻辑
}
// 外部接口(供 InteractionManager 调用)
UFUNCTION(BlueprintCallable)
void SetInteracting(bool bInteracting);
P2. 交互中摄像机控制权交接
实现:InteractionManager 在进入交互时通过 SetViewTargetWithBlend 切换摄像机目标;退出时切换回 Character。角色控制系统本身不需要修改摄像机逻辑。
交互结束后摄像机自动回到 SpringArm 默认跟随(因为 ViewTarget 切回 Character,SpringArm 恢复控制)。
P3. 状态信号提供
实现:提供查询接口
UFUNCTION(BlueprintCallable, BlueprintPure)
bool IsInteracting() const { return bIsInteracting; }
UFUNCTION(BlueprintCallable, BlueprintPure)
bool IsRunning() const;
// IsRunning: GetVelocity().Size() > Threshold && GetCharacterMovement()->IsMovingOnGround()
数据流
配置参数流
C++ 构造函数默认值 → 蓝图派生类可覆盖 → 运行时通过 Details 面板微调
v0.1 原型阶段所有参数在 C++ 中设置默认值,蓝图可覆盖。不使用 DataAsset 或配置表。 批量生产阶段迁移到参数 DataAsset。
运行时状态流
Enhanced Input (WASD/鼠标)
→ AChildHoodPlayerController (IMC 注册)
→ AChildHoodCharacter (IA 回调)
├─ DoMove() → CMC (AddMovementInput)
├─ DoLook() → Controller (AddYawInput/AddPitchInput)
│ → SpringArm (Controller Rotation)
│ → Camera (位置/旋转)
├─ InteractAction → InteractionManager (委托)
└─ bIsInteracting → DoMove() (输入屏蔽)
美术资源需求
v0.1 角色控制系统不直接需要美术资产。以下为间接需求:
| 资源类型 | 名称 | 数量 | 规格 | 说明 |
|---|---|---|---|---|
| 占位动画 | Idle(站立待机) | 1 | 简单 T-pose 或 A-pose 即可 | v0.1 可无动画 |
| 占位动画 | Run(跑步循环) | 1 | 简单跑步循环,角色可在地面滑动 | 执行案明确说"若无动画资源,角色在地面滑动也可接受" |
v0.1 角色控制不包含跳跃、蹲下、攀爬,因此不需要对应动画。
技术风险与注意事项
| 风险 | 等级 | 说明 | 缓解措施 |
|---|---|---|---|
| 软跟随手感不佳 | 🟢 低 | CameraLagSpeed 需要实际测试调整 | 多个预设值快速切换测试 |
| 摄像机碰撞穿墙 | 🟢 低 | SpringArm 原生碰撞处理基本满足 | 角落/窄空间需额外测试 |
| CMC 加速/减速不符合预期 | 🟢 低 | CMC 物理模型不完全线性 | 参数范围已预留,微调即可 |
| 角色转身"飘"的感觉 | 🟢 低 | 720°/s 偏快可能导致动画不自然 | v0.1 无正式动画,暂时不是问题 |
可调参数汇总
所有参数均在构造函数中设置默认值,蓝图可覆盖:
| 参数 | C++ 属性 | 默认值 | 位置 |
|---|---|---|---|
| 摄像机距离 | CameraBoom->TargetArmLength |
350.0f | 构造函数 |
| 摄像机高度 | CameraBoom->SocketOffset.Z |
80.0f | 构造函数 |
| 跟随速度 | CameraBoom->CameraLagSpeed |
6.0f | 构造函数 |
| 俯角上限 | CameraManager->ViewPitchMax |
45.0f | BeginPlay |
| 俯角下限 | CameraManager->ViewPitchMin |
-30.0f | BeginPlay |
| 碰撞检测 | CameraBoom->bDoCollisionTest |
true | 构造函数 |
| 跑步速度 | CMC->MaxWalkSpeed |
450.0f | 构造函数 |
| 加速度 | CMC->MaxAcceleration |
2250.0f | 构造函数 |
| 减速度 | CMC->BrakingDecelerationWalking |
1500.0f | 构造函数 |
| 转向速度 | CMC->RotationRate.Yaw |
720.0f | 构造函数 |
| 可行走坡度 | CMC->WalkableFloorAngle |
45.0f | 构造函数 |