Files
ChildHood/docs/technical/player-controller-tech.md
T
starmen1265 150f94c674 docs(technical): v0.1 程序设计——角色控制+交互+收集三份技术方案
P-003 步骤④程序设计产出:

- player-controller-tech.md: 角色控制系统(参数调整+输入绑定,2-3天)
- interaction-system-tech.md: 交互系统核心框架(状态机+推镜+物品中转,5-7天)
- collection-system-tech.md: 收集系统进度追踪+通知UI(1-2天)

覆盖三份执行案全部行为规则,含美术需求清单和技术风险分析。
等待 PM 质量门审查。
2026-06-06 00:30:50 +08:00

383 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 角色控制技术设计文档(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 参数
```cpp
// 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
```cpp
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 控制。
```cpp
// InputYawScale 在 PlayerController 中设置
// 灵敏度通过 IA 的 Scale 值控制,不需要自定义旋转速度限制
// UE5 鼠标输入是相对移动,不受固定 °/s 限制
// v0.1 使用默认鼠标输入灵敏度,后续版本可加灵敏度滑块
```
**垂直限幅实现**:在 CameraManager 中设置
```cpp
// AChildHoodPlayerController::BeginPlay 或构造函数中
PlayerCameraManager->ViewPitchMin = -30.0f; // 向下看最多 30°
PlayerCameraManager->ViewPitchMax = 45.0f; // 向上看最多 45°
```
> 注:执行案中 150°/s 是手柄摇杆的设计参考值。键鼠模式下鼠标移动是相对输入,由玩家手速决定实际旋转速度。v0.1 优先键鼠,此参数暂不在代码中硬性限制。
**可调参数**:ViewPitchMin, ViewPitchMax, IA Scale
---
#### C4. 摄像机碰撞处理
**实现**:启用 SpringArm 原生碰撞检测
```cpp
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. 跑动中角色始终背对摄像机
**实现**:已有配置满足
```cpp
bUseControllerRotationYaw = false; // 角色不跟随 Controller Yaw
GetCharacterMovement()->bOrientRotationToMovement = true; // 角色朝移动方向旋转
GetCharacterMovement()->RotationRate = FRotator(0.f, 720.f, 0.f); // 转向速度 720°/s
```
角色转向速度 720°/s 远快于鼠标旋转速度,自然满足"摄像机追不到角色正面"的效果。无需额外逻辑。
---
### 二、移动系统
#### M1. 移动方向(相对摄像机,对角 45° 合成)
**实现**:已有 `DoMove()` 逻辑满足
```cpp
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 参数配置
```cpp
GetCharacterMovement()->bOrientRotationToMovement = true;
GetCharacterMovement()->RotationRate = FRotator(0.f, 720.f, 0.f);
```
CMC 默认走最短路径旋转,转向期间角色持续移动(不"停顿再转向")。**无需修改。**
---
#### M3. 跑步(4.5 m/s,起步加速 0.2s)
**速度**:
```cpp
GetCharacterMovement()->MaxWalkSpeed = 450.0f; // 4.5 m/s (UE5 1uu = 1cm)
```
**加速**:CMC 的 `MaxAcceleration` 控制加速过程
```cpp
// 从 0 到 450 cm/s 在 0.2s → 加速度 = 450/0.2 = 2250 cm/s²
GetCharacterMovement()->MaxAcceleration = 2250.0f;
```
> 注:CMC 加速不是严格线性,受 GroundFriction 等因素影响。2250 是起始值,实际手感需测试微调。
---
#### M4. 停止减速(0.3s)
**实现**:
```cpp
// 从 450 到 0 cm/s 在 0.3s → 减速度 = 450/0.3 = 1500 cm/s²
GetCharacterMovement()->BrakingDecelerationWalking = 1500.0f;
```
> 同样受 GroundFriction 影响,1500 是起始值。
---
#### M5. 坡道与台阶(坡度 ≤45°,台阶 ≤0.15m)
**实现**:
```cpp
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 指针和绑定
```cpp
// 新增成员(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 及其绑定
```cpp
// 删除 JumpAction 成员
// 删除 SetupPlayerInputComponent 中的 Jump 绑定
// 删除 DoJumpStart/DoJumpEnd 函数
// CMC: GetCharacterMovement()->JumpZVelocity 不需要设置(不跳跃)
```
---
### 四、输入优先级 & 跨系统交互
#### P1. 交互中忽略移动输入
**实现**:在 `DoMove()` 中添加状态检查
```cpp
// 新增成员
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. 状态信号提供
**实现**:提供查询接口
```cpp
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 | 构造函数 |