352 lines
13 KiB
Markdown
352 lines
13 KiB
Markdown
# 07 · 反馈系统
|
||
|
||
> **命名空间** `BaseGames.Feedback`
|
||
> **所属文档集** [← 返回索引](./README.md) · [总览](./00_Overview.md)
|
||
> **依赖** Feel v4.3 · `BaseGames.Core.Events` · `BaseGames.Combat`
|
||
|
||
---
|
||
|
||
## 目录
|
||
|
||
1. [设计原则](#1-设计原则)
|
||
2. [Feel MMF_Player 体系](#2-feel-mmf_player-体系)
|
||
3. [PlayerFeedback — 玩家反馈配置](#3-playerfeedback--玩家反馈配置)
|
||
4. [EnemyFeedback — 敌人反馈配置](#4-enemyfeedback--敌人反馈配置)
|
||
5. [时间管理:子弹时间集成](#5-时间管理子弹时间集成)
|
||
6. [镜头震动集成](#6-镜头震动集成)
|
||
7. [音效管理](#7-音效管理)
|
||
8. [粒子特效规范](#8-粒子特效规范)
|
||
9. [UI 反馈](#9-ui-反馈)
|
||
10. [事件频道驱动的全局反馈](#10-事件频道驱动的全局反馈)
|
||
11. [FeedbackConfigSO](#11-feedbackconfigso)
|
||
12. [编辑器友好设计](#12-编辑器友好设计)
|
||
|
||
---
|
||
|
||
## 1. 设计原则
|
||
|
||
- **零耦合**:所有反馈通过**事件频道**或 `UnityEvent` 触发,GameLogic 不直接调用 Feedback
|
||
- **数据驱动**:每种反馈配置为独立 `MMF_Player` 资产,可在 Inspector 中调节,无需修改代码
|
||
- **分层设计**:本地反馈(HitBox 命中瞬间)→ 全局反馈(OnHitConfirmed 频道)→ 时间管理(ParrySuccess)
|
||
- **像素风格适配**:优先使用 Shader 闪光(Flash)而非粒子,减少视觉噪声
|
||
|
||
---
|
||
|
||
## 2. Feel MMF_Player 体系
|
||
|
||
### MMF_Player 命名规范
|
||
|
||
所有 `MMF_Player` GameObject 命名格式:`MMF_{Owner}_{EventName}`
|
||
|
||
示例:
|
||
- `MMF_Player_OnHit`(玩家受击)
|
||
- `MMF_Player_OnAttackHit`(玩家攻击命中)
|
||
- `MMF_Player_OnParrySuccess`(弹反成功)
|
||
- `MMF_Enemy_OnHit`(敌人受击)
|
||
- `MMF_Enemy_OnDeath`(敌人死亡)
|
||
|
||
### MMF_Player Feedback 类型速查
|
||
|
||
| Feel Feedback 类型 | 常用场景 | 关键参数 |
|
||
|-------------------|---------|---------|
|
||
| `MMF_Flash` | Sprite 受击白闪 | `FlashColor`, `Duration` |
|
||
| `MMF_SpriteRenderer` | 闪烁/变色 | `Color`, `Blink Duration` |
|
||
| `MMF_Particles` | 命中粒子特效 | `ParticleSystem` 引用 |
|
||
| `MMF_AudioSource` | 播放音效 | `AudioClip`, `Volume`, `Pitch Variance` |
|
||
| `MMF_CinemachineImpulse` | 镜头震动 | `ImpulseSource`, `Velocity` |
|
||
| `MMF_FreezeFrame` | 命中冻帧 | `FreezeDuration` |
|
||
| `MMF_TimeScale` | 子弹时间 | `TimeScale`, `Duration` |
|
||
| `MMF_TextMeshPro` | 伤害数字弹出 | `Value`, `Animation Curve` |
|
||
| `MMF_Position` | 物体位移(扑克震动)| `Displacement`, `Curve` |
|
||
| `MMF_Scale` | 冲击缩放(南瓜弹)| `Scale`, `Duration` |
|
||
| `MMF_Enable` | 启用/禁用 GameObject | `Target` |
|
||
|
||
---
|
||
|
||
## 3. IFeedbackPlayer 接口 — 反馈抽象层
|
||
|
||
为了让游戏逻辑(`PlayerCombat`、`EnemyBase`)与具体的 Feel/MMF_Player 实现零耦合,所有反馈调用必须通过 `IFeedbackPlayer` 接口进行:
|
||
|
||
```csharp
|
||
/// <summary>
|
||
/// 反馈执行器的抽象接口。
|
||
/// GameLogic 依赖此接口,而非具体的 MMF_Player 引用。
|
||
/// </summary>
|
||
public interface IFeedbackPlayer
|
||
{
|
||
void PlayHit(HitWeight weight); // 命中反馈(轻/中/重)
|
||
void PlayParrySuccess(); // 弹反成功
|
||
void PlayTakeHit(); // 玩家受击
|
||
void PlayDeath(); // 死亡演出
|
||
void PlayHeal(); // 治疗
|
||
void PlayLandImpact(); // 落地冲击
|
||
void PlayAttackWhoosh(); // 攻击挥动音效
|
||
void PlayJumpLaunch(); // 起跳
|
||
void TriggerPreset(string presetId); // 通过 ID 触发任意预设(动画事件用)
|
||
void PlaySFXById(string sfxId); // 通过 ID 播放音效(动画事件用)
|
||
}
|
||
```
|
||
|
||
**使用规范**:
|
||
- `PlayerCombat`、`PlayerMovement` 等逻辑组件持有 `IFeedbackPlayer _feedback`(通过 Inspector 注入)
|
||
- 测试时可替换为 `NullFeedbackPlayer`(空实现),完全不需要 Feel 资产
|
||
- 新增反馈类型时先在接口声明,再在 `PlayerFeedback` 中实现,保持单一变更点
|
||
|
||
---
|
||
|
||
## 4. PlayerFeedback — 玩家反馈配置
|
||
|
||
`PlayerFeedback` 组件挂载在 Player Prefab 下,实现 `IFeedbackPlayer` 接口,聚合所有玩家相关 `MMF_Player`:
|
||
|
||
### 受击反馈(OnTakeHit)
|
||
|
||
| Feedback | 参数 | 视觉效果 |
|
||
|----------|------|---------|
|
||
| `MMF_Flash` | 白色,0.15s | Sprite 白闪(经典受击感)|
|
||
| `MMF_AudioSource` | SFX_Player_Hurt | 受伤音效(随机 Pitch 0.9~1.1)|
|
||
| `MMF_CinemachineImpulse` | Medium,0.5强度 | 镜头震动 |
|
||
| `MMF_FreezeFrame` | 0.033s | 2帧冻帧 |
|
||
| `MMF_Position` | 朝击退反方向 1 unit | 玩家轻微弹开 |
|
||
|
||
### 攻击命中反馈(OnAttackHit)
|
||
|
||
| Feedback | 参数 | 说明 |
|
||
|----------|------|------|
|
||
| `MMF_Particles` | HitSpark Prefab,命中点生成 | 金属火花粒子 |
|
||
| `MMF_AudioSource` | SFX_Attack_Hit(随机 3 个变体之一)| 命中音效 |
|
||
| `MMF_FreezeFrame` | 0.033s(2帧)| 命中停顿感 |
|
||
| `MMF_CinemachineImpulse` | Light,0.2强度 | 轻微镜头震 |
|
||
|
||
### 弹反成功反馈(OnParrySuccess)
|
||
|
||
| Feedback | 参数 | 说明 |
|
||
|----------|------|------|
|
||
| `MMF_Flash` | 金色,0.1s | Sprite 金光闪烁 |
|
||
| `MMF_Particles` | ParryFlash Prefab(全屏金色光圈)| 弹反标志性特效 |
|
||
| `MMF_AudioSource` | SFX_Parry_Success(金属碰撞音)| 清脆弹反音效 |
|
||
| `MMF_CinemachineImpulse` | Parry,0.7强度,带方向 | 有方向性震动 |
|
||
| `MMF_TimeScale` | 0.25×,0.2s | 子弹时间(与 ParrySystem 同步)|
|
||
| `MMF_FreezeFrame` | 0.066s(4帧)| 更长冻帧强调击中感 |
|
||
|
||
### 治疗反馈(OnHeal)
|
||
|
||
| Feedback | 参数 | 说明 |
|
||
|----------|------|------|
|
||
| `MMF_Flash` | 蓝色,0.2s | 恢复光效 |
|
||
| `MMF_Particles` | HealParticle Prefab | 向上飘散的蓝色粒子 |
|
||
| `MMF_AudioSource` | SFX_Heal | 回血音效 |
|
||
|
||
### 死亡反馈(OnDeath)
|
||
|
||
| Feedback | 参数 | 说明 |
|
||
|----------|------|------|
|
||
| `MMF_AudioSource` | SFX_Player_Death | 死亡音效 |
|
||
| `MMF_CinemachineImpulse` | Heavy,1.0强度 | 强烈震动 |
|
||
| `MMF_FreezeFrame` | 0.1s(6帧)| 死亡冻帧 |
|
||
| `MMF_Enable` | 禁用 HurtBox | 防止死亡后继续受击 |
|
||
|
||
---
|
||
|
||
## 4. EnemyFeedback — 敌人反馈配置
|
||
|
||
`EnemyFeedback` 挂在每个敌人 Prefab 下:
|
||
|
||
### 受击反馈(OnHit)
|
||
|
||
| Feedback | 参数 | 说明 |
|
||
|----------|------|------|
|
||
| `MMF_Flash` | 白色,0.1s | 受击白闪 |
|
||
| `MMF_AudioSource` | SFX_Enemy_Hurt(按敌人类型变体)| 受伤音效 |
|
||
| `MMF_Particles` | HitSpark(命中位置)| 命中粒子 |
|
||
|
||
### 被弹反反馈(OnParried)
|
||
|
||
| Feedback | 参数 | 说明 |
|
||
|----------|------|------|
|
||
| `MMF_Flash` | 金色,0.15s | 与玩家弹反视觉对应 |
|
||
| `MMF_SpriteRenderer` | 扭曲/Shader 效果 | 硬直视觉反馈 |
|
||
| `MMF_AudioSource` | SFX_Parry_Impact | 被弹反音效 |
|
||
| `MMF_Position` | 小幅后退 | 轻微击退特效 |
|
||
|
||
### 死亡反馈(OnDeath)
|
||
|
||
| Feedback | 参数 | 说明 |
|
||
|----------|------|------|
|
||
| `MMF_AudioSource` | SFX_Enemy_Death | 死亡音效 |
|
||
| `MMF_Particles` | DeathParticle Prefab | 死亡解体粒子 |
|
||
| `MMF_Enable` | 禁用 Rigidbody2D / Colliders | 防止尸体物理继续 |
|
||
| `MMF_FreezeFrame` | 0.05s(3帧)| 击杀冻帧 |
|
||
|
||
---
|
||
|
||
## 5. 时间管理:子弹时间集成
|
||
|
||
子弹时间通过两套系统协调:
|
||
|
||
### Feel MMTimeManager(主要)
|
||
|
||
- 注册所有 `MMTimeManager` Listener
|
||
- `ParrySystem.TriggerParrySuccess()` → `MMTimeScaleEvent` 广播
|
||
- `MMTimeManager` 接收后修改 `Time.timeScale`
|
||
- 时间恢复:Lerp 方式平滑还原(`LerpSpeed = 20`)
|
||
|
||
### 与 Animancer 的配合
|
||
|
||
- Animancer 动画默认使用 `Time.timeScale`(跟随子弹时间减速)
|
||
- 特例:UI 动画、音频播放必须用 `Time.unscaledDeltaTime`
|
||
- 检测敌人动画速率被子弹时间自动降低(无需额外配置)
|
||
|
||
---
|
||
|
||
## 6. 镜头震动集成
|
||
|
||
详见 [02_CameraSystem](./02_CameraSystem.md#6-镜头震动cinemachineimpulse)。
|
||
|
||
### Feel 与 Cinemachine Impulse 的桥接
|
||
|
||
Feel `MMF_CinemachineImpulse` → 内部调用 `CinemachineImpulseSource.GenerateImpulse()` → `CinemachineImpulseListener` 响应。
|
||
|
||
**PlayerFeedback 中每种震动类型对应 ImpulseSource**(Inspector 中拖入引用):
|
||
|
||
| 震动类型 | 来源 ImpulseSource | 说明 |
|
||
|---------|-------------------|------|
|
||
| Light | `ImpulseSource_Light` | 普通命中 |
|
||
| Medium | `ImpulseSource_Medium` | 玩家受伤 |
|
||
| Heavy | `ImpulseSource_Heavy` | 玩家死亡 / Boss 重击 |
|
||
| Parry | `ImpulseSource_Parry` | 弹反成功(带方向性)|
|
||
|
||
---
|
||
|
||
## 7. 音效管理
|
||
|
||
### 音效 SO 资产结构
|
||
|
||
`AudioEventSO` 封装音效播放参数(非特定 AudioSource),通过事件频道解耦:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| `Clips` | `AudioClip[]` | 随机选取其中一个播放 |
|
||
| `Volume` | `float` | 基础音量(0~1)|
|
||
| `PitchMin` | `float` | Pitch 随机范围最小值 |
|
||
| `PitchMax` | `float` | Pitch 随机范围最大值 |
|
||
| `MixerGroup` | `AudioMixerGroup` | SFX / Music / UI 混音组 |
|
||
|
||
所有 `MMF_AudioSource` 通过 `AudioEventSO` 播放音效(而非直接引用 `AudioClip`),实现随机音调变化。
|
||
|
||
### 音效资产路径
|
||
|
||
```
|
||
Assets/Audio/SFX/
|
||
├── Player/
|
||
│ ├── SFX_Player_Hurt.asset
|
||
│ ├── SFX_Player_Death.asset
|
||
│ ├── SFX_Attack_Hit.asset ← 含3个变体Clip
|
||
│ ├── SFX_Parry_Success.asset
|
||
│ └── SFX_Heal.asset
|
||
├── Enemies/
|
||
│ ├── SFX_Enemy_Hurt_Generic.asset
|
||
│ └── SFX_Enemy_Death_Generic.asset
|
||
└── World/
|
||
├── SFX_Footstep.asset
|
||
└── SFX_Landing.asset
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 粒子特效规范
|
||
|
||
| 特效 Prefab | 触发来源 | 生命周期 | 说明 |
|
||
|-------------|---------|---------|------|
|
||
| `FX_HitSpark` | 攻击命中 | 0.3s 后自销毁 | 金属火花(4~6 粒子)|
|
||
| `FX_ParryFlash` | 弹反成功 | 0.5s 后自销毁 | 金色光圈(全屏扩散)|
|
||
| `FX_HealParticle` | 玩家治疗 | 1.0s 后自销毁 | 蓝色粒子上飘 |
|
||
| `FX_EnemyDeath` | 敌人死亡 | 1.5s 后自销毁 | 解体粒子(按敌人主题色)|
|
||
| `FX_DustCloud` | 玩家落地 | 0.5s 后自销毁 | 落地灰尘 |
|
||
| `FX_DashTrail` | 玩家冲刺 | 0.4s 后自销毁 | 冲刺残影(Sprite Fade)|
|
||
|
||
**像素风格适配**:所有粒子使用 `Render Mode: Billboard`,粒子贴图与角色 PPU(32 PPU)保持一致,避免模糊。
|
||
|
||
---
|
||
|
||
## 9. UI 反馈
|
||
|
||
### 伤害数字(FloatingText)
|
||
|
||
- 触发:`OnHitConfirmed` 事件频道
|
||
- 从对象池中取 `FloatingText` Prefab,在命中位置生成
|
||
- 数字内容:`DamageInfo.FinalDamage`
|
||
- 弹反反击:数字显示为金色 + 粗体(`FinalDamage` 为 3× 时额外标记)
|
||
- 动画:向上飘 0.8s + 淡出
|
||
|
||
### HP 血条动画
|
||
|
||
- `OnPlayerHPChanged` 事件频道驱动
|
||
- 满格 HP 以绿色实心显示,扣除部分以红色渐出动画表示(延迟 0.2s 开始缩短,视觉缓冲)
|
||
|
||
### Soul 槽动画
|
||
|
||
- `OnSoulChanged` 事件频道驱动
|
||
- 弹反成功 +33 时,Soul 槽显示**扫光动画**(金色高亮流过 1/3 槽)
|
||
|
||
---
|
||
|
||
## 10. 事件频道驱动的全局反馈
|
||
|
||
`GlobalFeedbackController` 组件(单例,挂在 `[Managers]` GO 上)监听全局频道并触发对应 `MMF_Player`:
|
||
|
||
| 频道 | 触发反馈 |
|
||
|------|---------|
|
||
| `OnPlayerDied` | 停止音乐、播放死亡演出(慢慢音量淡出,画面泛红)|
|
||
| `OnBossFightStarted` | 停止环境音乐、淡入 Boss 战BGM |
|
||
| `OnBossFightEnded` | Boss 死亡演出(震动+特效+音乐过渡)|
|
||
| `OnRoomEntered` | 淡出 → 淡入(场景切换遮罩)|
|
||
|
||
---
|
||
|
||
## 11. FeedbackConfigSO
|
||
|
||
`FeedbackConfigSO` 全局配置,存放于 `Assets/ScriptableObjects/Config/FeedbackConfigSO.asset`:
|
||
|
||
| 参数 | 类型 | 推荐值 | 说明 |
|
||
|------|------|--------|------|
|
||
| `HitFreezeFrames` | `int` | 2 | 命中冻帧帧数 |
|
||
| `ParryFreezeFrames` | `int` | 4 | 弹反冻帧帧数 |
|
||
| `SfxVolumeMaster` | `float` | 1.0 | SFX 总音量(0~1)|
|
||
| `HapticsEnabled` | `bool` | true | 手柄震动开关(P2)|
|
||
| `FloatingTextPoolSize` | `int` | 20 | 伤害数字对象池大小 |
|
||
| `ParticlePoolSize` | `int` | 30 | 粒子特效对象池大小 |
|
||
|
||
---
|
||
|
||
## 12. 编辑器友好设计
|
||
|
||
### MMF_Player 预览支持
|
||
|
||
Feel 原生支持在 Editor 非 Play Mode 下预览 `MMF_Player`:
|
||
|
||
- Inspector 底部的"▶ Play"按钮可单独预览每组反馈
|
||
- `Preview in Editor` 模式下验证视觉效果,无需进入 Play Mode
|
||
|
||
### FX 对象池监控(Play Mode Inspector)
|
||
|
||
```
|
||
┌─ GlobalFeedbackController ──────────────────────┐
|
||
│ FloatingText Pool: 14 / 20 available │
|
||
│ Particle Pool : 28 / 30 available │
|
||
│ ───────────────────────────────────────────── │
|
||
│ [Test: Player Hurt] [Test: Parry Success] │
|
||
│ [Test: Enemy Hit ] [Test: Boss Phase Change] │
|
||
└────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 反馈效果全局开关(调试用)
|
||
|
||
`FeedbackDebugOverlay`(编辑器 Play Mode 下叠加):
|
||
|
||
- `[Toggle Screen Shake]`:开关镜头震动
|
||
- `[Toggle Freeze Frames]`:开关冻帧
|
||
- `[Toggle Particles]`:开关粒子特效
|
||
- `[Toggle Bullet Time]`:开关子弹时间
|
||
|
||
方便策划/美术人员单独调试某类反馈。
|