using System.Collections.Generic; using SLSUtilities.Feedback; using SLSUtilities.Rendering.PostProcessing; using UnityEngine; namespace Cielonos.MainGame.Effects.Feedback { /// /// RGB分离故障震动事件。 /// public struct RGBSplitGlitchShakeEvent { private static event ShakeDelegate OnEvent; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void RuntimeInitialization() { OnEvent = null; } public delegate void ShakeDelegate( FeedbackContext feedbackContext, FloatCurveChannel intensityCurve, FloatCurveChannel speedCurve, bool stop ); public static void Register(ShakeDelegate callback) { OnEvent += callback; } public static void Unregister(ShakeDelegate callback) { OnEvent -= callback; } public static void Trigger( FeedbackContext feedbackContext, FloatCurveChannel intensityCurve, FloatCurveChannel speedCurve = default, bool stop = false) { OnEvent?.Invoke(feedbackContext, intensityCurve, speedCurve, stop); } } /// /// RGB分离故障震动实例。 /// public class RGBSplitGlitchShakeInstance : ShakeInstanceBase { public readonly FloatCurveChannel intensityCurve; public readonly FloatCurveChannel speedCurve; public RGBSplitGlitchShakeInstance( FeedbackContext feedbackContext, FloatCurveChannel intensityCurve, FloatCurveChannel speedCurve) : base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration) { this.intensityCurve = intensityCurve; this.speedCurve = speedCurve; } } /// /// RGBSplitGlitch 的震动聚合器。 /// [AddComponentMenu("SLS Utilities/Feedback Shakers/RGB Split Glitch Shaker")] public class RGBSplitGlitchShaker : MonoBehaviour { private RGBSplitGlitch _component; private float _initialIntensity; private float _initialSpeed; private bool _resolved; private readonly List _activeShakes = new List(); private void Awake() { _resolved = TryResolve(); } private void OnEnable() { RGBSplitGlitchShakeEvent.Register(OnShakeEvent); } private void OnDisable() { RGBSplitGlitchShakeEvent.Unregister(OnShakeEvent); StopAll(); } private void Update() { if (!_resolved || _activeShakes.Count == 0) return; float additiveIntensity = 0f; float absoluteIntensity = 0f; bool hasAbsoluteIntensity = false; float additiveSpeed = 0f; float absoluteSpeed = 0f; bool hasAbsoluteSpeed = false; for (int i = _activeShakes.Count - 1; i >= 0; i--) { RGBSplitGlitchShakeInstance shake = _activeShakes[i]; shake.timer += shake.timeProvider.GetDeltaTime(shake.timeSettings); float normalizedTime = shake.timer / shake.duration; float intensityValue = shake.intensityCurve.Evaluate(normalizedTime); if (shake.intensityCurve.relativeToInitial) { additiveIntensity += intensityValue; } else { absoluteIntensity = intensityValue; hasAbsoluteIntensity = true; } float speedValue = shake.speedCurve.Evaluate(normalizedTime); if (shake.speedCurve.relativeToInitial) { additiveSpeed += speedValue; } else { absoluteSpeed = speedValue; hasAbsoluteSpeed = true; } if (shake.IsFinished) { _activeShakes.RemoveAt(i); } } float finalIntensity = hasAbsoluteIntensity ? absoluteIntensity : _initialIntensity + additiveIntensity; float finalSpeed = hasAbsoluteSpeed ? absoluteSpeed : _initialSpeed + additiveSpeed; _component.intensity.value = finalIntensity; _component.speed.value = finalSpeed; if (_activeShakes.Count == 0) { Restore(); } } private void OnShakeEvent( FeedbackContext feedbackContext, FloatCurveChannel intensityCurve, FloatCurveChannel speedCurve, bool stop) { if (stop) { StopAll(); return; } if (!_resolved) _resolved = TryResolve(); if (!_resolved) return; var instance = new RGBSplitGlitchShakeInstance( feedbackContext, intensityCurve, speedCurve ); _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; _initialIntensity = _component.intensity.value; _initialSpeed = _component.speed.value; return true; } private void Restore() { if (!_resolved) return; _component.intensity.value = _initialIntensity; _component.speed.value = _initialSpeed; } private void StopAll() { _activeShakes.Clear(); Restore(); } } }