using System.Collections.Generic; using SLSUtilities.Feedback; using SLSUtilities.Rendering.PostProcessing; using UnityEngine; namespace Cielonos.MainGame.Effects.Feedback { /// /// 黑白闪震动事件。 /// 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); } } /// /// 黑白闪震动实例。 /// 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; } } /// /// StrobeFlash 的震动聚合器。 /// [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 _activeShakes = new List(); 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(); } } }