# 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* *状态: 代码已完成,待编辑器配置*