11 KiB
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
- 打开Unity编辑器
- 导航到
Assets/Prefabs/MainGame/Characters/Player/Data/Feedbacks/ - 逐个配置上述FeedbackData文件
步骤2:在Player Prefab中关联FeedbackData
- 选择Player Prefab
- 找到FeedbackDataCollection组件
- 确保以下键值对存在:
"Dash"→ Player_Feedback_Dash.asset"Dodge"→ Player_Feedback_Dodge.asset"NormalDodge"→ Player_Feedback_NormalDodge.asset"PerfectDodge"→ Player_Feedback_PerfectDodge.asset
步骤3:测试
- 进入游戏
- 测试冲刺反馈
- 测试后撤步反馈
- 测试普通闪避反馈
- 测试完美闪避反馈(需要被敌人攻击时在完美时机闪避)
步骤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") // 播放完美闪避反馈
⚠️ 注意事项
- 时间缩放:PerfectDodge的TimeScaleModifierAction必须不受全局时间缩放影响
- 性能:同时激活的效果不要超过5个
- 调试:可以在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()
代码
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播放时:
- TimeScaleModifierAction立即修改globalTimeScale = 0.1
- 同一帧内,其他Feedback能立即读取到0.1
- 所有效果在同一帧内协调生效
🔧 关键修复: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
代码
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
状态: 代码已完成,待编辑器配置