chore: initial commit

This commit is contained in:
2026-05-08 11:04:00 +08:00
commit f55d2a57c3
6278 changed files with 866081 additions and 0 deletions

View 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 │
└────────────────────────────────────────────┘
```