Files
Cielonos/docs/闪避反馈系统实现进度.md
2026-04-18 13:57:19 -04:00

402 lines
11 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.
# Cielonos 闪避反馈系统实现进度
## ✅ 已完成的工作
### 1. 代码架构修改
#### 1.1 DodgeSource.Default() 方法重构
- **文件**`Assets/Scripts/MainGame/Characters/Base/Subcontrollers/Reaction/DodgeSubmodule.cs`
- **修改**移除了MMF_Feedback相关的代码MMF_RadialBlur、MMF_AdvancedVignette
- **状态**:✅ 完成
#### 1.2 PlayerAnimationSubcontroller 闪避反馈重构
- **文件**`Assets/Scripts/MainGame/Characters/Player/Animation/PlayerAnimScDashDodge.cs`
- **修改**
- 移除了所有MMF_Feedback引用
- Dash反馈使用新的`player.feedbackSc.PlayFeedback("Dash")`
- Dodge反馈使用新的`player.feedbackSc.PlayFeedback("Dodge")`
- **状态**:✅ 完成
#### 1.3 EventSubmodule 新增事件
- **文件**`Assets/Scripts/MainGame/Characters/Base/Submodules/EventSubmodule.cs`
- **新增事件**
- `onDodgeSuccess` - 完美闪避成功时触发
- `onNormalDodgeSuccess` - 普通闪避成功时触发
- **状态**:✅ 完成
#### 1.4 Player 事件监听注册
- **文件**`Assets/Scripts/MainGame/Characters/Player/Player.cs`
- **新增内容**
-`InitializeSubmodules()`中注册PerfectDodge和NormalDodge事件监听
- 新增`Feedback_PerfectDodge()`方法:播放完美闪避反馈
- 新增`Feedback_NormalDodge()`方法:处理普通闪避反馈
- **状态**:✅ 完成
#### 1.5 ReactionSubmodule 事件触发
- **文件**`Assets/Scripts/MainGame/AttackArea/Submodules/ReactionSubmodule.cs`
- **修改**
- 完美闪避成功后触发`dodger.eventSm.onDodgeSuccess.Invoke(firstDodgeSource)`
- 普通闪避成功后触发`dodger.eventSm.onNormalDodgeSuccess.Invoke(firstDodgeSource)`
- **状态**:✅ 完成
---
## 📋 FeedbackData 配置状态
### 已创建的FeedbackData文件
位置:`Assets/Prefabs/MainGame/Characters/Player/Data/Feedbacks/`
| 文件名 | 用途 | 配置状态 |
|--------|------|---------|
| Player_Feedback_Dash.asset | 冲刺反馈 | ⚠️ 待配置 |
| Player_Feedback_Dodge.asset | 后撤步反馈 | ⚠️ 待配置 |
| Player_Feedback_NormalDodge.asset | 普通闪避反馈 | ⚠️ 待配置 |
| Player_Feedback_PerfectDodge.asset | 完美闪避反馈 | ⚠️ 待配置 |
**注意**这些文件已创建但tracks为空需要在Unity编辑器中配置。
---
## 🎯 FeedbackData 配置指南
### 2.1 Dash冲刺FeedbackData 配置
**目标**:强调速度感、移动感
**Track 1: "Camera" - 相机效果**
```
Clip 1: CameraFieldOfViewAction
- FOV增量: +6°
- 持续时间: 0.2秒
- 曲线: FadeOut
```
**Track 2: "Camera" - 旋转震动**
```
Clip 1: CameraRotationShakeAction
- Rotation: (1°, 0.5°, 2°)
- 持续时间: 0.15秒
- 曲线: QuickImpact
```
**Track 3: "PostProcess" - 径向模糊**
```
Clip 1: RadialBlurAction
- Intensity: 0.25
- 持续时间: 0.15秒
- 曲线: FadeOut
```
### 2.2 Dodge后撤步FeedbackData 配置
**目标**:强调突然性、灵活性
**Track 1: "Camera" - 相机效果**
```
Clip 1: CameraFieldOfViewAction
- FOV增量: +5°
- 持续时间: 0.2秒
- 曲线: FadeOut
```
**Track 2: "Camera" - 旋转震动**
```
Clip 1: CameraRotationShakeAction
- Rotation: (0.5°, 0.3°, 1.5°)
- 持续时间: 0.12秒
- 曲线: QuickImpact
```
**Track 3: "PostProcess" - 径向模糊**
```
Clip 1: RadialBlurAction
- Intensity: 0.2
- 持续时间: 0.12秒
- 曲线: FadeOut
```
### 2.3 NormalDodge普通闪避FeedbackData 配置
**说明**NormalDodge用于普通闪避非冲刺的短距离闪避
**Track 1: "Camera" - 相机效果**
```
Clip 1: CameraFieldOfViewAction
- FOV增量: +4°
- 持续时间: 0.15秒
- 曲线: FadeOut
```
**Track 2: "Camera" - 旋转震动**
```
Clip 1: CameraRotationShakeAction
- Rotation: (0.3°, 0.2°, 1°)
- 持续时间: 0.1秒
- 曲线: QuickImpact
```
**Track 3: "PostProcess" - 径向模糊**
```
Clip 1: RadialBlurAction
- Intensity: 0.15
- 持续时间: 0.1秒
- 曲线: FadeOut
```
### 2.4 PerfectDodge完美闪避FeedbackData 配置
**目标**:时间扭曲 + 视觉强化 + 成就感
**Track 1: "Time" - 时间缩放**
```
Clip 1: TimeScaleModifierAction
- Mode: Dynamic
- Curve: Custom
- RemapZero: 0.3
- RemapOne: 1.0
- 持续时间: 0.3秒
- ⚠️ 重要此Track不应受全局时间缩放影响
```
**Track 2: "Camera" - FOV变化**
```
Clip 1: CameraFieldOfViewAction
- FOV增量: +10°
- 持续时间: 0.35秒
- 曲线: FadeOut
```
**Track 3: "Camera" - 旋转震动**
```
Clip 1: CameraRotationShakeAction
- Rotation: (3°, 2°, 5°)
- 持续时间: 0.3秒
- 曲线: QuickImpact
```
**Track 4: "PostProcess" - 暗角**
```
Clip 1: VignetteAction
- Intensity: 0.4
- 持续时间: 0.35秒
- 曲线: FadeOut
```
**Track 5: "PostProcess" - 径向模糊**
```
Clip 1: RadialBlurAction
- Intensity: 0.6
- 持续时间: 0.25秒
- 曲线: FadeOut
```
**Track 6: "PostProcess" - 色差**
```
Clip 1: ChromaticAberrationAction
- Intensity: 0.25
- 持续时间: 0.2秒
- 曲线: FadeOut
```
---
## 🔧 接下来的步骤
### 步骤1在Unity编辑器中配置FeedbackData
1. 打开Unity编辑器
2. 导航到 `Assets/Prefabs/MainGame/Characters/Player/Data/Feedbacks/`
3. 逐个配置上述FeedbackData文件
### 步骤2在Player Prefab中关联FeedbackData
1. 选择Player Prefab
2. 找到FeedbackDataCollection组件
3. 确保以下键值对存在:
- `"Dash"` → Player_Feedback_Dash.asset
- `"Dodge"` → Player_Feedback_Dodge.asset
- `"NormalDodge"` → Player_Feedback_NormalDodge.asset
- `"PerfectDodge"` → Player_Feedback_PerfectDodge.asset
### 步骤3测试
1. 进入游戏
2. 测试冲刺反馈
3. 测试后撤步反馈
4. 测试普通闪避反馈
5. 测试完美闪避反馈(需要被敌人攻击时在完美时机闪避)
### 步骤4根据体验调整参数
根据实际手感调整:
- FOV变化量
- 震动强度
- 模糊程度
- 时间缩放值
---
## 📊 代码流程图
```
玩家触发闪避
PlayerAnimationSubcontroller.SetupDash/SetupDodge()
PlayerAnimationSubcontroller.DashStart/DodgeStart()
player.feedbackSc.PlayFeedback("Dash"/"Dodge") // 播放普通闪避反馈
ApplyDodge() → 添加闪避源
敌人攻击命中
ReactionSubmodule.CheckDodge()
判断是否完美闪避
DodgeSource.PerfectDodge() / NormalDodge()
触发事件: dodger.eventSm.onDodgeSuccess/onNormalDodgeSuccess
Player.Feedback_PerfectDodge() / Feedback_NormalDodge()
player.feedbackSc.PlayFeedback("PerfectDodge") // 播放完美闪避反馈
```
---
## ⚠️ 注意事项
1. **时间缩放**PerfectDodge的TimeScaleModifierAction必须不受全局时间缩放影响
2. **性能**同时激活的效果不要超过5个
3. **调试**可以在Player.Feedback_PerfectDodge()中添加Debug.Log用于调试
---
## 🔧 问题修复TimeScaleModifierAction立即生效
### 问题描述
当PerfectDodge播放时TimeScaleModifierAction修改的globalTimeScale在同一帧内不会立即被其他Feedback读取到。
### 原因
- TimeScaleModifierAction.OnStart()调用TimeScaleShakeEvent.Trigger()
- 只是注册了TimeScaleShakeInstance
- TimeScaleShaker.Update()在下一帧才执行
- 其他Feedback的ComputeClipDeltaTime()已经读取了旧的globalTimeScale值
### 解决方案
在TimeScaleModifierAction.OnStart()中立即应用一次时间缩放调用ImmediateApplyTimeScale()
### 修改内容
- 文件TimeScaleModifierAction.cs
- 添加ImmediateApplyTimeScale()方法
- 在OnStart()末尾调用ImmediateApplyTimeScale()
### 代码
```csharp
public override void OnStart(FeedbackContext context)
{
// 原有逻辑...
TimeScaleShakeEvent.Trigger(...);
// 新增:立即应用时间缩放
ImmediateApplyTimeScale();
}
private void ImmediateApplyTimeScale()
{
if (TimeManager.Instance == null) return;
float t = 0f; // 归一化时间0
if (globalChannel.active)
TimeManager.Instance.globalTimeScale.Value = globalChannel.Evaluate(t);
if (playerChannel.active)
TimeManager.Instance.playerTimeScale.Value = playerChannel.Evaluate(t);
if (enemyChannel.active)
TimeManager.Instance.enemyTimeScale.Value = enemyChannel.Evaluate(t);
if (alliedChannel.active)
TimeManager.Instance.alliedMinionTimeScale.Value = alliedChannel.Evaluate(t);
if (nonPlayerChannel.active)
TimeManager.Instance.nonPlayerTimeScale.Value = nonPlayerChannel.Evaluate(t);
}
```
### 效果
现在当PerfectDodge播放时
1. TimeScaleModifierAction立即修改globalTimeScale = 0.1
2. 同一帧内其他Feedback能立即读取到0.1
3. 所有效果在同一帧内协调生效
---
## 🔧 关键修复ProcessClip的pending分支elapsed计算
### 问题描述
当CameraFOV等Feedback在PerfectDodge播放期间持续处于pending状态时等待estimatedEndTime满足它们的elapsed时间会累积。
当终于进入active状态时使用了`elapsed = _currentTime - startTime`计算导致elapsed很大可能是10秒然后在active分支中`elapsed >= safeDuration`立即为trueClip立即结束。
### 时间线示例
```
PerfectDodge播放第1帧: _currentTime = 0.016, CameraFOV.pending (estimatedEndTime=10.032)
PerfectDodge播放第100帧: _currentTime = 1.6, CameraFOV.pending (estimatedEndTime=11.616)
PerfectDodge播放结束时: CameraFOV终于满足estimatedEndTime >= _currentTime
elapsed = _currentTime - 0 = 1.6 (或更大)
elapsed >= safeDuration(0.2) 立即为true
CameraFOV.OnEnd()立即被触发!
```
### 解决方案
在pending->active分支中`elapsed = _currentTime - startTime`改为`elapsed = 0f`
### 修改内容
- 文件FeedbackPlayer.cs
- 位置ProcessClip方法的pending分支
- 修改:将`elapsed = _currentTime - clip.startTime`改为`elapsed = 0f`
### 代码
```csharp
case ClipState.Pending:
if (_currentTime >= clip.startTime)
{
clipState = ClipState.Active;
// 关键修复当Clip进入active状态时elapsed应该从0开始
elapsed = 0f;
// ...
}
break;
```
### 效果
- Clip进入active状态时elapsed从0开始
- 不会被之前累积的_currentTime影响
- Clip的持续时间正确
---
## 📝 待办事项清单
- [ ] 在Unity编辑器中配置Player_Feedback_Dash.asset
- [ ] 在Unity编辑器中配置Player_Feedback_Dodge.asset
- [ ] 在Unity编辑器中配置Player_Feedback_NormalDodge.asset
- [ ] 在Unity编辑器中配置Player_Feedback_PerfectDodge.asset
- [ ] 在Player Prefab中关联所有FeedbackData
- [ ] 测试Dash反馈
- [ ] 测试Dodge反馈
- [ ] 测试NormalDodge反馈
- [ ] 测试PerfectDodge反馈
- [ ] 根据手感调整参数
---
*文档生成日期: 2026-04-17*
*生成者: Game Designer Agent*
*状态: 代码已完成,待编辑器配置*