chore: initial commit
This commit is contained in:
264
Docs/Design/01_InputSystem.md
Normal file
264
Docs/Design/01_InputSystem.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# 01 · 输入系统
|
||||
|
||||
> **命名空间** `BaseGames.Input`
|
||||
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
|
||||
> **依赖** Unity Input System · `BaseGames.Core.Events`
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
1. [设计目标](#1-设计目标)
|
||||
2. [核心架构:InputReaderSO](#2-核心架构inputreaderso)
|
||||
3. [Input Actions 资产结构](#3-input-actions-资产结构)
|
||||
4. [InputBuffer — 输入缓冲](#4-inputbuffer--输入缓冲)
|
||||
5. [Coyote Time](#5-coyote-time)
|
||||
6. [输入数据流](#6-输入数据流)
|
||||
7. [设备切换与多平台支持](#7-设备切换与多平台支持)
|
||||
8. [编辑器友好设计](#8-编辑器友好设计)
|
||||
|
||||
---
|
||||
|
||||
## 1. 设计目标
|
||||
|
||||
- **零耦合**:游戏系统不直接引用 `PlayerInput` 组件,通过 `InputReaderSO`(ScriptableObject)订阅输入事件
|
||||
- **可测试**:`InputReaderSO` 可在测试代码中手动触发事件,无需模拟硬件
|
||||
- **可重映射**:Input Actions Asset 支持运行时重映射,配合 UI 设置页面
|
||||
- **输入宽容**:提供输入缓冲(Buffer)和 Coyote Time,提升手感
|
||||
|
||||
---
|
||||
|
||||
## 2. 核心架构:InputReaderSO
|
||||
|
||||
`InputReaderSO` 是整个输入系统的**唯一门面**,封装 Input Actions,以 C# Action 事件对外暴露:
|
||||
|
||||
```
|
||||
InputReaderSO (ScriptableObject)
|
||||
│
|
||||
├── 内部持有: PlayerInputActions (生成的 C# 类)
|
||||
│
|
||||
├── 移动输入
|
||||
│ ├── event MoveEvent(Vector2 direction)
|
||||
│ └── Vector2 MoveInput { get; } ← 当前帧移动向量(持续值)
|
||||
│
|
||||
├── 跳跃输入
|
||||
│ ├── event JumpStartedEvent() ← 按下(用于触发跳跃)
|
||||
│ └── event JumpCancelledEvent() ← 松开(用于可变跳跃高度)
|
||||
│
|
||||
├── 攻击输入
|
||||
│ └── event AttackEvent() ← 按下
|
||||
│
|
||||
├── 弹反输入
|
||||
│ └── event ParryEvent() ← 按下
|
||||
│
|
||||
├── 冲刺输入
|
||||
│ └── event DashEvent() ← 按下
|
||||
│
|
||||
├── 灵泉输入
|
||||
│ └── event UseSpringEvent() ← 按下(消耗灵泉使用次数)
|
||||
│
|
||||
├── 形态切换输入
|
||||
│ ├── event SwitchSkyFormEvent() ← 切换天魂姿态
|
||||
│ ├── event SwitchEarthFormEvent() ← 切换地魂姿态
|
||||
│ └── event SwitchDeathFormEvent() ← 切换命魂姿态
|
||||
│
|
||||
├── 技能输入
|
||||
│ ├── event SoulSkillEvent() ← 当前形态魂技能(消耗灵力)
|
||||
│ ├── event SpiritSkill1StartedEvent() ← 魄技能 1 按下
|
||||
│ ├── event SpiritSkill1CancelledEvent() ← 魄技能 1 松开(蓄力型技能用)
|
||||
│ ├── event SpiritSkill2StartedEvent() ← 魄技能 2 按下
|
||||
│ └── event SpiritSkill2CancelledEvent() ← 魄技能 2 松开(蓄力型技能用)
|
||||
│
|
||||
├── 交互输入
|
||||
│ └── event InteractEvent() ← 按下
|
||||
│
|
||||
├── UI 输入
|
||||
│ ├── event PauseEvent()
|
||||
│ ├── event NavigateEvent(Vector2 dir)
|
||||
│ └── event SubmitEvent()
|
||||
│
|
||||
└── Action Map 切换
|
||||
├── EnableGameplayInput() ← 进入游戏时启用
|
||||
├── EnableUIInput() ← 进入 UI 时启用
|
||||
└── DisableAllInput() ← 过场动画/加载时禁用
|
||||
```
|
||||
|
||||
**所有使用输入的系统**仅需在 Inspector 中拖入 `InputReaderSO` 资产,订阅所需事件:
|
||||
|
||||
```
|
||||
系统 A: [SerializeField] InputReaderSO _input;
|
||||
OnEnable → _input.JumpStartedEvent += HandleJump;
|
||||
OnDisable → _input.JumpStartedEvent -= HandleJump;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Input Actions 资产结构
|
||||
|
||||
`PlayerInputActions.inputactions` 包含以下 Action Maps:
|
||||
|
||||
### Gameplay Action Map
|
||||
|
||||
| Action 名称 | 类型 | 绑定(默认键盘)| 绑定(手柄)|
|
||||
|------------|------|---------------|------------|
|
||||
| `Move` | Value (Vector2) | WASD / Arrow Keys | 左摇杆 |
|
||||
| `Jump` | Button | Space | South Button (×/A) |
|
||||
| `Attack` | Button | J / Z | West Button (□/X) |
|
||||
| `Parry` | Button | K / X | Right Bumper (R1/RB) |
|
||||
| `Dash` | Button | L-Shift / C | East Button (○/B) |
|
||||
| `UseSpring` | Button | G / Tab | Right Trigger (R2/RT) |
|
||||
| `Interact` | Button | F / E | North Button (△/Y) |
|
||||
| `SwitchSkyForm` | Button | 1 | D-Pad Left |
|
||||
| `SwitchEarthForm` | Button | 2 | D-Pad Down |
|
||||
| `SwitchDeathForm` | Button | 3 | D-Pad Right |
|
||||
| `SoulSkill` | Button | Q | Left Trigger (L2/LT) |
|
||||
| `SpiritSkill1` | Button | E | D-Pad Up |
|
||||
| `SpiritSkill2` | Button | R | Left Trigger (L2/LT)(双击或组合)|
|
||||
| `Pause` | Button | Escape | Start / Menu |
|
||||
|
||||
### UI Action Map
|
||||
|
||||
| Action 名称 | 类型 | 说明 |
|
||||
|------------|------|------|
|
||||
| `Navigate` | Value (Vector2) | UI 导航方向 |
|
||||
| `Submit` | Button | 确认 |
|
||||
| `Cancel` | Button | 返回 |
|
||||
| `Point` | Value (Vector2) | 鼠标/触摸位置(UI 点击)|
|
||||
|
||||
### 重映射配置
|
||||
|
||||
- 使用 `PlayerInput` 组件的 `SaveBindingOverridesAsJson()` 持久化重映射到 PlayerPrefs
|
||||
- 启动时调用 `LoadBindingOverridesFromJson()` 恢复
|
||||
|
||||
---
|
||||
|
||||
## 4. InputBuffer — 输入缓冲
|
||||
|
||||
`InputBuffer` 是一个**轻量计时器**组件,解决"输入早于判断条件成立"问题:
|
||||
|
||||
### 缓冲时长配置
|
||||
|
||||
| 输入动作 | 缓冲时长 | 说明 |
|
||||
|---------|---------|------|
|
||||
| 跳跃 | 0.15s | 落地前提前按跳跃,落地即起跳 |
|
||||
| 攻击 | 0.12s | 前一段攻击结束前输入,自动接续下一击 |
|
||||
| 弹反 | 0.0s | 不缓冲(弹反必须精准,缓冲会降低挑战性)|
|
||||
| 冲刺 | 0.1s | 小量缓冲,避免帧率不稳定导致失手 |
|
||||
| UseSpring | 0.0s | 不缓冲(消耗资源,防误操作)|
|
||||
| SoulSkill | 0.1s | 小量缓冲,允许攻击后衔接技能 |
|
||||
| SpiritSkill1/2 | 0.0s | 不缓冲(蓄力型技能按下即生效)|
|
||||
|
||||
### 缓冲工作原理
|
||||
|
||||
```
|
||||
玩家按下跳跃键
|
||||
→ InputBuffer 记录 jumpBufferTimer = 0.15s
|
||||
→ 每帧 jumpBufferTimer -= deltaTime
|
||||
↓
|
||||
PlayerAirState 进入(落地)
|
||||
→ 查询 InputBuffer.HasBufferedJump()
|
||||
├── 若 jumpBufferTimer > 0 → true → 立即起跳 → 消费缓冲
|
||||
└── 若 jumpBufferTimer ≤ 0 → false → 不起跳
|
||||
```
|
||||
|
||||
### 缓冲接口
|
||||
|
||||
```
|
||||
InputBuffer
|
||||
├── bool HasBufferedJump() → 消费性查询(调用后清除)
|
||||
├── bool HasBufferedAttack() → 消费性查询
|
||||
├── bool HasBufferedDash() → 消费性查询
|
||||
├── void ConsumeJump() → 手动消费
|
||||
├── void ConsumeAttack()
|
||||
└── void ConsumeDash()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Coyote Time
|
||||
|
||||
Coyote Time 让玩家在**走出平台边缘后的短暂时间内**仍可起跳,提升平台跳跃手感:
|
||||
|
||||
```
|
||||
玩家离开地面
|
||||
→ PlayerAirState 记录 coyoteTimer = 0.12s(当离地原因是走下而非跳跃时)
|
||||
→ 每帧 coyoteTimer -= deltaTime
|
||||
↓
|
||||
玩家按下跳跃键(此时仍在 coyoteTimer > 0)
|
||||
→ 视为地面跳跃(速度叠加正常跳跃力)
|
||||
→ 消耗 coyoteTimer(不可再次触发)
|
||||
```
|
||||
|
||||
**Coyote Time 不生效的情况**:
|
||||
- 玩家主动跳跃后进入空中(不是走落)
|
||||
- 已经触发过一次 Coyote Jump
|
||||
- 玩家正在执行冲刺(DashState 期间禁用 Coyote)
|
||||
|
||||
| 参数 | 值 | 位置 |
|
||||
|------|-----|------|
|
||||
| `CoyoteTimeDuration` | 0.12s | `PlayerMovementConfigSO` |
|
||||
| `JumpBufferDuration` | 0.15s | `PlayerMovementConfigSO` |
|
||||
|
||||
---
|
||||
|
||||
## 6. 输入数据流
|
||||
|
||||
```
|
||||
硬件设备(键盘/手柄)
|
||||
↓
|
||||
Input System Runtime
|
||||
↓
|
||||
PlayerInputActions(生成类,内嵌在 InputReaderSO)
|
||||
↓
|
||||
InputReaderSO.OnJumpPerformed() → 触发 JumpStartedEvent
|
||||
↓
|
||||
InputBuffer.RecordJump(timestamp)
|
||||
↓
|
||||
PlayerAirState.OnStateUpdate()
|
||||
└── InputBuffer.HasBufferedJump() → true → 起跳
|
||||
```
|
||||
|
||||
**Action Map 切换时序**:
|
||||
|
||||
```
|
||||
游戏启动 → EnableGameplayInput()
|
||||
打开暂停菜单 → EnableUIInput() (游戏逻辑冻结,输入切换到 UI)
|
||||
关闭暂停菜单 → EnableGameplayInput()
|
||||
进入过场动画 → DisableAllInput()
|
||||
过场动画结束 → EnableGameplayInput()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 设备切换与多平台支持
|
||||
|
||||
`InputReaderSO` 监听 `InputSystem.onActionChange`,检测当前活跃设备类型,发布 `DeviceChangedEvent(DeviceType)`,UI 系统根据此事件切换图标(键盘图标 / 手柄图标)。
|
||||
|
||||
| DeviceType | 说明 |
|
||||
|-----------|------|
|
||||
| `KeyboardMouse` | 键盘 + 鼠标 |
|
||||
| `Gamepad` | 手柄(PS / Xbox)|
|
||||
| `Touch` | 触屏(移动端扩展,P2)|
|
||||
|
||||
---
|
||||
|
||||
## 8. 编辑器友好设计
|
||||
|
||||
### InputReaderSO Inspector
|
||||
|
||||
自定义 Inspector(`BaseGames.Editor`)提供:
|
||||
|
||||
- **实时事件监控**(Play Mode):每个 Action 上方显示"上次触发时间"
|
||||
- **手动触发按钮**:在 Inspector 中点击"Simulate Jump"等按钮,无需按实体键,方便调试 FSM 状态
|
||||
|
||||
### Input 配置可视化
|
||||
|
||||
`InputBuffer` 在 Inspector 中以进度条显示各缓冲的剩余时间(只读),方便调试缓冲窗口:
|
||||
|
||||
```
|
||||
┌─ InputBuffer ──────────────────────────────┐
|
||||
│ Jump Buffer [████░░░░░░░] 0.08s / 0.15s │
|
||||
│ Attack Buffer [░░░░░░░░░░░] 0.00s / 0.12s │
|
||||
│ Dash Buffer [░░░░░░░░░░░] 0.00s / 0.10s │
|
||||
└────────────────────────────────────────────┘
|
||||
```
|
||||
Reference in New Issue
Block a user