using System; using Cielonos.MainGame; using Sirenix.OdinInspector; using SLSUtilities.Feedback; using UnityEngine; namespace Cielonos.MainGame.Effects.Feedback { /// /// 时间缩放通道的工作模式。 /// public enum TimeScaleMode { /// /// 固定值模式:在 Clip 期间将时间缩放设为固定值。 /// Fixed, /// /// 动态曲线模式:根据曲线和 Remap 驱动时间缩放。 /// Dynamic } /// /// 单个时间缩放通道的配置。 /// [Serializable] public class TimeScaleChannel { /// /// 是否激活此通道。 /// public bool active; /// /// 通道工作模式。 /// [ShowIf("active")] public TimeScaleMode mode = TimeScaleMode.Fixed; /// /// Fixed 模式下的目标值。 /// [ShowIf("@active && mode == TimeScaleMode.Fixed")] [LabelText("Fixed Value")] public float fixedValue; /// /// Dynamic 模式下的变化曲线。 /// [ShowIf("@active && mode == TimeScaleMode.Dynamic")] [LabelText("Curve")] public AnimationCurve curve = new AnimationCurve( new Keyframe(0f, 0f), new Keyframe(0.5f, 1f), new Keyframe(1f, 0f) ); /// /// 曲线值 0 映射到的实际值。 /// [ShowIf("@active && mode == TimeScaleMode.Dynamic")] [LabelText("Remap Zero")] public float remapZero; /// /// 曲线值 1 映射到的实际值。 /// [ShowIf("@active && mode == TimeScaleMode.Dynamic")] [LabelText("Remap One")] public float remapOne = 1f; /// /// 根据归一化进度计算当前通道的时间缩放值。 /// public float Evaluate(float normalizedTime) { if (!active) return 1f; if (mode == TimeScaleMode.Fixed) { return fixedValue; } float curveValue = curve.Evaluate(normalizedTime); return Mathf.LerpUnclamped(remapZero, remapOne, curveValue); } } /// /// 时间缩放修改器反馈,直接驱动 TimeManager 的各个通道。 /// /// 重要:此 Action 只应使用游戏的 unscaledDeltaTime 驱动。 /// 不要在包含此 Action 的 Clip 上启用自定义 overrideTimeSettings, /// FeedbackData 的 defaultTimeSettings.useTimeScale 也应保持为 false。 /// 我们的自定义时间参数绝不能影响时间缩放修改器本身。 /// [Serializable] public class TimeScaleModifierAction : FeedbackActionBase { public override string DisplayName => "Time Scale Modifier"; [Title("Global Time Scale")] public TimeScaleChannel globalChannel = new TimeScaleChannel { active = true, fixedValue = 0f }; [Title("Player Time Scale")] public TimeScaleChannel playerChannel = new TimeScaleChannel(); [Title("Enemy Time Scale")] public TimeScaleChannel enemyChannel = new TimeScaleChannel(); [Title("Allied Time Scale")] public TimeScaleChannel alliedChannel = new TimeScaleChannel(); [Title("Non-Player Time Scale")] public TimeScaleChannel nonPlayerChannel = new TimeScaleChannel(); [NonSerialized] private float _initialGlobal; [NonSerialized] private float _initialPlayer; [NonSerialized] private float _initialEnemy; [NonSerialized] private float _initialAllied; [NonSerialized] private float _initialNonPlayer; public override void OnStart(FeedbackContext context) { if (TimeManager.Instance == null) { Debug.LogWarning("[TimeScaleModifierAction] TimeManager instance not found."); return; } _initialGlobal = TimeManager.Instance.globalTimeScale.Value; _initialPlayer = TimeManager.Instance.playerTimeScale.Value; _initialEnemy = TimeManager.Instance.enemyTimeScale.Value; _initialAllied = TimeManager.Instance.alliedMinionTimeScale.Value; _initialNonPlayer = TimeManager.Instance.nonPlayerTimeScale.Value; } public override void OnUpdate(FeedbackContext context, float normalizedTime) { if (TimeManager.Instance == null) return; if (globalChannel.active) TimeManager.Instance.globalTimeScale.Value = globalChannel.Evaluate(normalizedTime); if (playerChannel.active) TimeManager.Instance.playerTimeScale.Value = playerChannel.Evaluate(normalizedTime); if (enemyChannel.active) TimeManager.Instance.enemyTimeScale.Value = enemyChannel.Evaluate(normalizedTime); if (alliedChannel.active) TimeManager.Instance.alliedMinionTimeScale.Value = alliedChannel.Evaluate(normalizedTime); if (nonPlayerChannel.active) TimeManager.Instance.nonPlayerTimeScale.Value = nonPlayerChannel.Evaluate(normalizedTime); } public override void OnEnd(FeedbackContext context) { RestoreValues(); } public override void OnInterrupt(FeedbackContext context) { RestoreValues(); } public override bool Validate(out string error) { // 防呆检查:时间缩放修改器不应受自定义时间缩放影响 // 此检查在 Editor 中调用,完整的 Inspector 防呆将在后续版本中添加 bool anyActive = globalChannel.active || playerChannel.active || enemyChannel.active || alliedChannel.active || nonPlayerChannel.active; if (!anyActive) { error = "No time scale channel is active. Enable at least one channel."; return false; } error = null; return true; } private void RestoreValues() { if (TimeManager.Instance == null) return; if (globalChannel.active) TimeManager.Instance.globalTimeScale.Value = _initialGlobal; if (playerChannel.active) TimeManager.Instance.playerTimeScale.Value = _initialPlayer; if (enemyChannel.active) TimeManager.Instance.enemyTimeScale.Value = _initialEnemy; if (alliedChannel.active) TimeManager.Instance.alliedMinionTimeScale.Value = _initialAllied; if (nonPlayerChannel.active) TimeManager.Instance.nonPlayerTimeScale.Value = _initialNonPlayer; } } }