Files
Cielonos/Assets/Scripts/MainGame/Effects/Feedbacks/Actions/Time/TimeScaleModifierAction.cs

188 lines
5.7 KiB
C#
Raw Normal View History

2026-04-12 02:11:15 -04:00
using System;
using Sirenix.OdinInspector;
using SLSUtilities.Feedback;
using UnityEngine;
namespace Cielonos.MainGame.Effects.Feedback
{
/// <summary>
2026-07-18 03:16:20 -04:00
/// TimeScale 通道的工作模式。
2026-04-12 02:11:15 -04:00
/// </summary>
public enum TimeScaleMode
{
/// <summary>
2026-07-18 03:16:20 -04:00
/// 在 Clip 持续期间使用固定 TimeScale。
2026-04-12 02:11:15 -04:00
/// </summary>
Fixed,
/// <summary>
2026-07-18 03:16:20 -04:00
/// 根据 Curve 和 Remap 动态计算 TimeScale。
2026-04-12 02:11:15 -04:00
/// </summary>
Dynamic
}
/// <summary>
2026-07-18 03:16:20 -04:00
/// 单个 TimeScale 通道的配置。
2026-04-12 02:11:15 -04:00
/// </summary>
[Serializable]
public class TimeScaleChannel
{
/// <summary>
2026-07-18 03:16:20 -04:00
/// 是否启用此通道。
2026-04-12 02:11:15 -04:00
/// </summary>
2026-04-18 13:57:19 -04:00
[HorizontalGroup("Channel")]
2026-04-12 02:11:15 -04:00
public bool active;
/// <summary>
2026-07-18 03:16:20 -04:00
/// 通道的计算模式。
2026-04-12 02:11:15 -04:00
/// </summary>
[ShowIf("active")]
2026-04-18 13:57:19 -04:00
[HorizontalGroup("Channel")]
2026-04-12 02:11:15 -04:00
public TimeScaleMode mode = TimeScaleMode.Fixed;
/// <summary>
2026-07-18 03:16:20 -04:00
/// Fixed 模式下的 TimeScale 值。
2026-04-12 02:11:15 -04:00
/// </summary>
[ShowIf("@active && mode == TimeScaleMode.Fixed")]
[LabelText("Fixed Value")]
public float fixedValue;
/// <summary>
2026-07-18 03:16:20 -04:00
/// Dynamic 模式下使用的曲线。
2026-04-12 02:11:15 -04:00
/// </summary>
[ShowIf("@active && mode == TimeScaleMode.Dynamic")]
[LabelText("Curve")]
2026-04-18 13:57:19 -04:00
[ShakeCurvePreset]
2026-04-12 02:11:15 -04:00
public AnimationCurve curve = new AnimationCurve(
new Keyframe(0f, 0f),
new Keyframe(0.5f, 1f),
new Keyframe(1f, 0f)
);
/// <summary>
2026-07-18 03:16:20 -04:00
/// Curve 值为 0 时映射到的 TimeScale。
2026-04-12 02:11:15 -04:00
/// </summary>
[ShowIf("@active && mode == TimeScaleMode.Dynamic")]
[LabelText("Remap Zero")]
2026-04-18 13:57:19 -04:00
[HorizontalGroup("Ramp")]
2026-04-12 02:11:15 -04:00
public float remapZero;
/// <summary>
2026-07-18 03:16:20 -04:00
/// Curve 值为 1 时映射到的 TimeScale。
2026-04-12 02:11:15 -04:00
/// </summary>
[ShowIf("@active && mode == TimeScaleMode.Dynamic")]
[LabelText("Remap One")]
2026-04-18 13:57:19 -04:00
[HorizontalGroup("Ramp")]
2026-04-12 02:11:15 -04:00
public float remapOne = 1f;
/// <summary>
2026-07-18 03:16:20 -04:00
/// 转换为事件传输用的只读数据。
2026-04-12 02:11:15 -04:00
/// </summary>
2026-04-18 13:57:19 -04:00
public TimeScaleChannelData ToChannelData()
{
return new TimeScaleChannelData
{
active = active,
mode = mode,
fixedValue = fixedValue,
curve = curve,
remapZero = remapZero,
remapOne = remapOne
};
}
2026-07-18 03:16:20 -04:00
2026-04-12 02:11:15 -04:00
public float Evaluate(float normalizedTime)
{
if (!active) return 1f;
if (mode == TimeScaleMode.Fixed)
{
return fixedValue;
}
2026-04-18 13:57:19 -04:00
float curveValue = curve?.Evaluate(normalizedTime) ?? 0f;
2026-04-12 02:11:15 -04:00
return Mathf.LerpUnclamped(remapZero, remapOne, curveValue);
}
}
/// <summary>
2026-07-18 03:16:20 -04:00
/// TimeScale 修改反馈。它只提交请求,实际的多实例合成由 TimeScaleShaker 统一处理。
2026-04-12 02:11:15 -04:00
/// </summary>
[Serializable]
2026-04-18 13:57:19 -04:00
[FeedbackActionColor(0.3f, 0.7f, 1.0f)]
2026-04-12 02:11:15 -04:00
public class TimeScaleModifierAction : FeedbackActionBase
{
public override string DisplayName => "Time Scale Modifier";
2026-07-18 03:16:20 -04:00
2026-04-18 13:57:19 -04:00
/// <summary>
2026-07-18 03:16:20 -04:00
/// 此 Action 自身必须使用未缩放时间推进,避免被它制造的慢动作拖慢。
2026-04-18 13:57:19 -04:00
/// </summary>
public override bool IgnoreTimeScale => true;
2026-07-18 03:16:20 -04:00
[LabelText("Priority")]
[Tooltip("同一 TimeScale 通道存在多个活跃反馈时,优先使用 Priority 更高的反馈Priority 相同则后触发者生效。")]
public int priority;
2026-04-18 13:57:19 -04:00
public TimeScaleChannel globalChannel = new TimeScaleChannel { active = true, fixedValue = 0.1f };
2026-04-12 02:11:15 -04:00
2026-04-18 13:57:19 -04:00
public bool advancedSettings = false;
2026-07-18 03:16:20 -04:00
2026-04-18 13:57:19 -04:00
[ShowIf("advancedSettings")]
2026-04-12 02:11:15 -04:00
public TimeScaleChannel playerChannel = new TimeScaleChannel();
2026-07-18 03:16:20 -04:00
2026-04-18 13:57:19 -04:00
[ShowIf("advancedSettings")]
2026-04-12 02:11:15 -04:00
public TimeScaleChannel enemyChannel = new TimeScaleChannel();
2026-07-18 03:16:20 -04:00
2026-04-18 13:57:19 -04:00
[ShowIf("advancedSettings")]
2026-04-12 02:11:15 -04:00
public TimeScaleChannel alliedChannel = new TimeScaleChannel();
2026-07-18 03:16:20 -04:00
2026-04-18 13:57:19 -04:00
[ShowIf("advancedSettings")]
2026-04-12 02:11:15 -04:00
public TimeScaleChannel nonPlayerChannel = new TimeScaleChannel();
public override void OnStart(FeedbackContext context)
{
2026-04-18 13:57:19 -04:00
TimeScaleShakeEvent.Trigger(
2026-07-18 03:16:20 -04:00
feedbackContext: context,
2026-04-18 13:57:19 -04:00
duration: context.duration,
2026-07-18 03:16:20 -04:00
priority: priority,
2026-04-18 13:57:19 -04:00
global: globalChannel.ToChannelData(),
player: playerChannel.ToChannelData(),
enemy: enemyChannel.ToChannelData(),
allied: alliedChannel.ToChannelData(),
nonPlayer: nonPlayerChannel.ToChannelData()
);
}
public override void OnUpdate(FeedbackContext context, float normalizedTime)
{
2026-07-18 03:16:20 -04:00
// TimeScaleShaker 会在收到事件后立即应用,并在之后逐帧推进。
2026-04-12 02:11:15 -04:00
}
public override void OnEnd(FeedbackContext context)
{
2026-07-18 03:16:20 -04:00
// TimeScaleShaker 根据持续时间自动结束实例。
2026-04-12 02:11:15 -04:00
}
public override void OnInterrupt(FeedbackContext context)
{
2026-07-18 03:16:20 -04:00
TimeScaleShakeEvent.Trigger(context, 0f, stop: true);
2026-04-12 02:11:15 -04:00
}
public override bool Validate(out string error)
{
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;
}
}
}