Files
Cielonos/Assets/Scripts/MainGame/Effects/Feedbacks/Shakers/StrobeFlashShaker.cs
2026-04-18 13:57:19 -04:00

191 lines
6.1 KiB
C#

using System.Collections.Generic;
using SLSUtilities.Feedback;
using SLSUtilities.Rendering.PostProcessing;
using UnityEngine;
namespace Cielonos.MainGame.Effects.Feedback
{
/// <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,
float duration,
bool modifyExtra,
FloatCurveChannel frequencyCurve,
ColorCurveChannel colorHigh,
ColorCurveChannel colorLow,
bool stop
);
public static void Register(ShakeDelegate callback) { OnEvent += callback; }
public static void Unregister(ShakeDelegate callback) { OnEvent -= callback; }
public static void Trigger(
FeedbackContext feedbackContext,
float duration,
bool modifyExtra = false,
FloatCurveChannel frequencyCurve = default,
ColorCurveChannel colorHigh = default,
ColorCurveChannel colorLow = default,
bool stop = false)
{
OnEvent?.Invoke(feedbackContext, duration, modifyExtra, frequencyCurve, colorHigh, colorLow, stop);
}
}
/// <summary>
/// 黑白闪震动实例。
/// </summary>
public class StrobeFlashShakeInstance : ShakeInstanceBase
{
public readonly bool modifyExtra;
public readonly FloatCurveChannel frequencyCurve;
public readonly ColorCurveChannel colorHigh;
public readonly ColorCurveChannel colorLow;
public StrobeFlashShakeInstance(
FeedbackContext feedbackContext,
bool modifyExtra,
FloatCurveChannel frequencyCurve,
ColorCurveChannel colorHigh,
ColorCurveChannel colorLow)
: base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration)
{
this.modifyExtra = modifyExtra;
this.frequencyCurve = frequencyCurve;
this.colorHigh = colorHigh;
this.colorLow = colorLow;
}
}
/// <summary>
/// StrobeFlash 的震动聚合器。
/// </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;
float latestFrequency = _initialFrequency;
Color latestColorHigh = _initialColorHigh;
Color latestColorLow = _initialColorLow;
bool hasExtra = false;
for (int i = _activeShakes.Count - 1; i >= 0; i--)
{
StrobeFlashShakeInstance shake = _activeShakes[i];
shake.timer += shake.timeProvider.GetDeltaTime(shake.timeSettings);
float normalizedTime = shake.timer / shake.duration;
if (shake.modifyExtra && !shake.IsFinished)
{
latestFrequency = shake.frequencyCurve.Evaluate(normalizedTime);
latestColorHigh = shake.colorHigh.Evaluate(normalizedTime);
latestColorLow = shake.colorLow.Evaluate(normalizedTime);
hasExtra = true;
}
if (shake.IsFinished)
{
_activeShakes.RemoveAt(i);
}
}
_component.enableEffect.value = true;
_component.autoFlash.value = true;
if (hasExtra)
{
_component.frequency.value = latestFrequency;
_component.colorHigh.value = latestColorHigh;
_component.colorLow.value = latestColorLow;
}
if (_activeShakes.Count == 0)
{
Restore();
}
}
private void OnShakeEvent(
FeedbackContext feedbackContext,
float duration,
bool modifyExtra,
FloatCurveChannel frequencyCurve,
ColorCurveChannel colorHigh,
ColorCurveChannel colorLow,
bool stop)
{
if (stop) { StopAll(); return; }
if (!_resolved) _resolved = TryResolve();
if (!_resolved) return;
var instance = new StrobeFlashShakeInstance(
feedbackContext, modifyExtra, frequencyCurve, colorHigh, colorLow
);
_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;
_component.frequency.value = _initialFrequency;
_component.colorHigh.value = _initialColorHigh;
_component.colorLow.value = _initialColorLow;
}
private void StopAll()
{
_activeShakes.Clear();
Restore();
}
}
}