Files
Cielonos/Assets/Scripts/MainGame/Effects/Feedbacks/Shakers/StrobeFlashShaker.cs

269 lines
9.9 KiB
C#
Raw Normal View History

2026-04-18 13:57:19 -04:00
using System.Collections.Generic;
using SLSUtilities.Feedback;
using SLSUtilities.Rendering.PostProcessing;
using UnityEngine;
namespace Cielonos.MainGame.Effects.Feedback
{
2026-04-30 07:06:38 -04:00
/// <summary>
/// 频率控制模式。
/// </summary>
public enum StrobeFrequencyMode
{
/// <summary>使用固定频率数值。</summary>
Constant,
/// <summary>使用 FloatCurveChannel 以动画曲线控制频率。</summary>
Curve,
/// <summary>使用 AnimationCurve 手动控制 ManualInvertY >= 1 时翻转)。</summary>
Manual
}
2026-04-18 13:57:19 -04:00
/// <summary>
/// 黑白闪震动事件。
/// </summary>
public struct StrobeFlashShakeEvent
{
private static event ShakeDelegate OnEvent;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void RuntimeInitialization() { OnEvent = null; }
public delegate void ShakeDelegate(
FeedbackContext feedbackContext,
2026-04-30 07:06:38 -04:00
StrobeFrequencyMode frequencyMode,
float constantFrequency,
2026-04-18 13:57:19 -04:00
FloatCurveChannel frequencyCurve,
2026-04-30 07:06:38 -04:00
AnimationCurve manualCurve,
bool modifyColorHigh,
bool useColorHighGradient,
Color colorHighConstant,
ColorCurveChannel colorHighCurve,
bool modifyColorLow,
bool useColorLowGradient,
Color colorLowConstant,
ColorCurveChannel colorLowCurve,
2026-04-18 13:57:19 -04:00
bool stop
);
public static void Register(ShakeDelegate callback) { OnEvent += callback; }
public static void Unregister(ShakeDelegate callback) { OnEvent -= callback; }
public static void Trigger(
FeedbackContext feedbackContext,
2026-04-30 07:06:38 -04:00
StrobeFrequencyMode frequencyMode = StrobeFrequencyMode.Constant,
float constantFrequency = 15f,
2026-04-18 13:57:19 -04:00
FloatCurveChannel frequencyCurve = default,
2026-04-30 07:06:38 -04:00
AnimationCurve manualCurve = null,
bool modifyColorHigh = false,
bool useColorHighGradient = false,
Color colorHighConstant = default,
ColorCurveChannel colorHighCurve = default,
bool modifyColorLow = false,
bool useColorLowGradient = false,
Color colorLowConstant = default,
ColorCurveChannel colorLowCurve = default,
2026-04-18 13:57:19 -04:00
bool stop = false)
{
2026-04-30 07:06:38 -04:00
OnEvent?.Invoke(feedbackContext,
frequencyMode, constantFrequency, frequencyCurve, manualCurve,
modifyColorHigh, useColorHighGradient, colorHighConstant, colorHighCurve,
modifyColorLow, useColorLowGradient, colorLowConstant, colorLowCurve,
stop);
2026-04-18 13:57:19 -04:00
}
}
/// <summary>
/// 黑白闪震动实例。
/// </summary>
public class StrobeFlashShakeInstance : ShakeInstanceBase
{
2026-04-30 07:06:38 -04:00
public readonly StrobeFrequencyMode frequencyMode;
public readonly float constantFrequency;
2026-04-18 13:57:19 -04:00
public readonly FloatCurveChannel frequencyCurve;
2026-04-30 07:06:38 -04:00
public readonly AnimationCurve manualCurve;
public readonly bool modifyColorHigh;
public readonly bool useColorHighGradient;
public readonly Color colorHighConstant;
public readonly ColorCurveChannel colorHighCurve;
public readonly bool modifyColorLow;
public readonly bool useColorLowGradient;
public readonly Color colorLowConstant;
public readonly ColorCurveChannel colorLowCurve;
2026-04-18 13:57:19 -04:00
public StrobeFlashShakeInstance(
FeedbackContext feedbackContext,
2026-04-30 07:06:38 -04:00
StrobeFrequencyMode frequencyMode,
float constantFrequency,
2026-04-18 13:57:19 -04:00
FloatCurveChannel frequencyCurve,
2026-04-30 07:06:38 -04:00
AnimationCurve manualCurve,
bool modifyColorHigh,
bool useColorHighGradient,
Color colorHighConstant,
ColorCurveChannel colorHighCurve,
bool modifyColorLow,
bool useColorLowGradient,
Color colorLowConstant,
ColorCurveChannel colorLowCurve)
2026-04-18 13:57:19 -04:00
: base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration)
{
2026-04-30 07:06:38 -04:00
this.frequencyMode = frequencyMode;
this.constantFrequency = constantFrequency;
2026-04-18 13:57:19 -04:00
this.frequencyCurve = frequencyCurve;
2026-04-30 07:06:38 -04:00
this.manualCurve = manualCurve;
this.modifyColorHigh = modifyColorHigh;
this.useColorHighGradient = useColorHighGradient;
this.colorHighConstant = colorHighConstant;
this.colorHighCurve = colorHighCurve;
this.modifyColorLow = modifyColorLow;
this.useColorLowGradient = useColorLowGradient;
this.colorLowConstant = colorLowConstant;
this.colorLowCurve = colorLowCurve;
2026-04-18 13:57:19 -04:00
}
}
/// <summary>
2026-04-30 07:06:38 -04:00
/// StrobeFlash 的震动聚合器。最新添加的 Shake 具有最高优先级。
2026-04-18 13:57:19 -04:00
/// </summary>
[AddComponentMenu("SLS Utilities/Feedback Shakers/Strobe Flash Shaker")]
public class StrobeFlashShaker : MonoBehaviour
{
private StrobeFlash _component;
private float _initialFrequency;
private Color _initialColorHigh;
private Color _initialColorLow;
private bool _resolved;
private readonly List<StrobeFlashShakeInstance> _activeShakes = new List<StrobeFlashShakeInstance>();
private void Awake()
{
_resolved = TryResolve();
}
private void OnEnable()
{
StrobeFlashShakeEvent.Register(OnShakeEvent);
}
private void OnDisable()
{
StrobeFlashShakeEvent.Unregister(OnShakeEvent);
StopAll();
}
private void Update()
{
if (!_resolved || _activeShakes.Count == 0) return;
for (int i = _activeShakes.Count - 1; i >= 0; i--)
{
2026-04-30 07:06:38 -04:00
_activeShakes[i].timer += _activeShakes[i].timeProvider.GetDeltaTime(_activeShakes[i].timeSettings);
if (_activeShakes[i].IsFinished)
2026-04-18 13:57:19 -04:00
_activeShakes.RemoveAt(i);
}
2026-04-30 07:06:38 -04:00
if (_activeShakes.Count == 0)
{
Restore();
return;
}
// 最新添加(最高索引)的 Shake 具有最高优先级。
StrobeFlashShakeInstance dominant = _activeShakes[_activeShakes.Count - 1];
float normalizedTime = dominant.timer / dominant.duration;
2026-04-18 13:57:19 -04:00
_component.enableEffect.value = true;
2026-04-30 07:06:38 -04:00
switch (dominant.frequencyMode)
2026-04-18 13:57:19 -04:00
{
2026-04-30 07:06:38 -04:00
case StrobeFrequencyMode.Constant:
_component.autoFlash.value = true;
_component.manualInvert.value = false;
_component.frequency.value = dominant.constantFrequency;
break;
case StrobeFrequencyMode.Curve:
_component.autoFlash.value = true;
_component.manualInvert.value = false;
_component.frequency.value = dominant.frequencyCurve.Evaluate(normalizedTime);
break;
case StrobeFrequencyMode.Manual:
_component.autoFlash.value = false;
_component.manualInvert.value = dominant.manualCurve.Evaluate(normalizedTime) >= 1f;
break;
2026-04-18 13:57:19 -04:00
}
2026-04-30 07:06:38 -04:00
if (dominant.modifyColorHigh)
2026-04-18 13:57:19 -04:00
{
2026-04-30 07:06:38 -04:00
_component.colorHigh.value = dominant.useColorHighGradient
? dominant.colorHighCurve.Evaluate(normalizedTime)
: dominant.colorHighConstant;
}
if (dominant.modifyColorLow)
{
_component.colorLow.value = dominant.useColorLowGradient
? dominant.colorLowCurve.Evaluate(normalizedTime)
: dominant.colorLowConstant;
2026-04-18 13:57:19 -04:00
}
}
private void OnShakeEvent(
FeedbackContext feedbackContext,
2026-04-30 07:06:38 -04:00
StrobeFrequencyMode frequencyMode,
float constantFrequency,
2026-04-18 13:57:19 -04:00
FloatCurveChannel frequencyCurve,
2026-04-30 07:06:38 -04:00
AnimationCurve manualCurve,
bool modifyColorHigh,
bool useColorHighGradient,
Color colorHighConstant,
ColorCurveChannel colorHighCurve,
bool modifyColorLow,
bool useColorLowGradient,
Color colorLowConstant,
ColorCurveChannel colorLowCurve,
2026-04-18 13:57:19 -04:00
bool stop)
{
if (stop) { StopAll(); return; }
if (!_resolved) _resolved = TryResolve();
if (!_resolved) return;
var instance = new StrobeFlashShakeInstance(
2026-04-30 07:06:38 -04:00
feedbackContext,
frequencyMode, constantFrequency, frequencyCurve, manualCurve,
modifyColorHigh, useColorHighGradient, colorHighConstant, colorHighCurve,
modifyColorLow, useColorLowGradient, colorLowConstant, colorLowCurve
2026-04-18 13:57:19 -04:00
);
_activeShakes.Add(instance);
}
private bool TryResolve()
{
if (_component != null) return true;
if (PostProcessingManager.Instance == null) return false;
if (!PostProcessingManager.Instance.GetVolumeComponent(out _component)) return false;
_initialFrequency = _component.frequency.value;
_initialColorHigh = _component.colorHigh.value;
_initialColorLow = _component.colorLow.value;
return true;
}
private void Restore()
{
if (!_resolved) return;
2026-04-30 07:06:38 -04:00
_component.enableEffect.value = false;
_component.autoFlash.value = false;
_component.manualInvert.value = false;
2026-04-18 13:57:19 -04:00
_component.frequency.value = _initialFrequency;
_component.colorHigh.value = _initialColorHigh;
_component.colorLow.value = _initialColorLow;
}
private void StopAll()
{
_activeShakes.Clear();
Restore();
}
}
}