402 lines
11 KiB
Markdown
402 lines
11 KiB
Markdown
# 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`立即为true,Clip立即结束。
|
||
|
||
### 时间线示例
|
||
```
|
||
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*
|
||
*状态: 代码已完成,待编辑器配置*
|