using System.Collections.Generic; using SLSUtilities.Feedback; using SLSUtilities.Rendering.PostProcessing; using UnityEngine; namespace Cielonos.MainGame.Effects.Feedback { /// /// 暗角震动事件。 /// public struct VignetteShakeEvent { private static event ShakeDelegate OnEvent; [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] private static void RuntimeInitialization() { OnEvent = null; } public delegate void ShakeDelegate( FeedbackContext feedbackContext, FloatCurveChannel intensityCurve, bool modifyCenter, Vector2 center, bool modifyColors, ColorCurveChannel colorOuter, ColorCurveChannel colorInner, bool modifyShape, FloatCurveChannel smoothnessCurve, FloatCurveChannel roundnessCurve, 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, bool modifyCenter = false, Vector2 center = default, bool modifyColors = false, ColorCurveChannel colorOuter = default, ColorCurveChannel colorInner = default, bool modifyShape = false, FloatCurveChannel smoothnessCurve = default, FloatCurveChannel roundnessCurve = default, bool stop = false) { OnEvent?.Invoke(feedbackContext, intensityCurve, modifyCenter, center, modifyColors, colorOuter, colorInner, modifyShape, smoothnessCurve, roundnessCurve, stop); } } /// /// 暗角震动实例。 /// public class VignetteShakeInstance : ShakeInstanceBase { public readonly FloatCurveChannel intensityCurve; public readonly bool modifyCenter; public readonly Vector2 center; public readonly bool modifyColors; public readonly ColorCurveChannel colorOuter; public readonly ColorCurveChannel colorInner; public readonly bool modifyShape; public readonly FloatCurveChannel smoothnessCurve; public readonly FloatCurveChannel roundnessCurve; public VignetteShakeInstance( FeedbackContext feedbackContext, FloatCurveChannel intensityCurve, bool modifyCenter, Vector2 center, bool modifyColors, ColorCurveChannel colorOuter, ColorCurveChannel colorInner, bool modifyShape, FloatCurveChannel smoothnessCurve, FloatCurveChannel roundnessCurve) : base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration) { this.intensityCurve = intensityCurve; this.modifyCenter = modifyCenter; this.center = center; this.modifyColors = modifyColors; this.colorOuter = colorOuter; this.colorInner = colorInner; this.modifyShape = modifyShape; this.smoothnessCurve = smoothnessCurve; this.roundnessCurve = roundnessCurve; } } /// /// AdvancedVignette 的震动聚合器。 /// [AddComponentMenu("SLS Utilities/Feedback Shakers/Vignette Shaker")] public class VignetteShaker : MonoBehaviour { private AdvancedVignette _component; private float _initialIntensity; private Vector2 _initialCenter; private Color _initialColorOuter; private Color _initialColorInner; private float _initialSmoothness; private float _initialRoundness; private bool _resolved; private readonly List _activeShakes = new List(); private void Awake() { _resolved = TryResolve(); } private void OnEnable() { VignetteShakeEvent.Register(OnShakeEvent); } private void OnDisable() { VignetteShakeEvent.Unregister(OnShakeEvent); StopAll(); } private void Update() { if (!_resolved || _activeShakes.Count == 0) return; float additiveIntensity = 0f; float absoluteIntensity = 0f; bool hasAbsolute = false; Vector2 latestCenter = _initialCenter; Color latestColorOuter = _initialColorOuter; Color latestColorInner = _initialColorInner; float latestSmoothness = _initialSmoothness; float latestRoundness = _initialRoundness; bool hasCenter = false; bool hasColors = false; bool hasShape = false; for (int i = _activeShakes.Count - 1; i >= 0; i--) { VignetteShakeInstance shake = _activeShakes[i]; shake.timer += shake.timeProvider.GetDeltaTime(shake.timeSettings); float normalizedTime = shake.timer / shake.duration; if (shake.intensityCurve.active) { float curveValue = shake.intensityCurve.Evaluate(normalizedTime); if (shake.intensityCurve.relativeToInitial) { additiveIntensity += curveValue; } else { absoluteIntensity = curveValue; hasAbsolute = true; } } if (shake.modifyCenter) { latestCenter = shake.center; hasCenter = true; } if (shake.modifyColors) { latestColorOuter = shake.colorOuter.Evaluate(normalizedTime); latestColorInner = shake.colorInner.Evaluate(normalizedTime); hasColors = true; } if (shake.modifyShape) { latestSmoothness = shake.smoothnessCurve.Evaluate(normalizedTime); latestRoundness = shake.roundnessCurve.Evaluate(normalizedTime); hasShape = true; } if (shake.IsFinished) { _activeShakes.RemoveAt(i); } } float finalIntensity = hasAbsolute ? absoluteIntensity : _initialIntensity + additiveIntensity; _component.intensity.value = finalIntensity; if (hasCenter) _component.center.value = latestCenter; if (hasColors) { _component.colorOuter.value = latestColorOuter; _component.colorInner.value = latestColorInner; } if (hasShape) { _component.smoothness.value = latestSmoothness; _component.roundness.value = latestRoundness; } if (_activeShakes.Count == 0) { Restore(); } } private void OnShakeEvent( FeedbackContext feedbackContext, FloatCurveChannel intensityCurve, bool modifyCenter, Vector2 center, bool modifyColors, ColorCurveChannel colorOuter, ColorCurveChannel colorInner, bool modifyShape, FloatCurveChannel smoothnessCurve, FloatCurveChannel roundnessCurve, bool stop) { if (stop) { StopAll(); return; } if (!_resolved) _resolved = TryResolve(); if (!_resolved) return; var instance = new VignetteShakeInstance( feedbackContext, intensityCurve, modifyCenter, center, modifyColors, colorOuter, colorInner, modifyShape, smoothnessCurve, roundnessCurve ); _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; _initialCenter = _component.center.value; _initialColorOuter = _component.colorOuter.value; _initialColorInner = _component.colorInner.value; _initialSmoothness = _component.smoothness.value; _initialRoundness = _component.roundness.value; return true; } private void Restore() { if (!_resolved) return; _component.intensity.value = _initialIntensity; _component.center.value = _initialCenter; _component.colorOuter.value = _initialColorOuter; _component.colorInner.value = _initialColorInner; _component.smoothness.value = _initialSmoothness; _component.roundness.value = _initialRoundness; } private void StopAll() { _activeShakes.Clear(); Restore(); } } }