Files
Cielonos/Assets/Scripts/MainGame/Effects/Feedbacks/Shakers/RGBSplitGlitchShaker.cs
SoulliesOfficial 47125f95f4 地图初步
2026-04-30 07:06:38 -04:00

186 lines
5.9 KiB
C#

using System.Collections.Generic;
using SLSUtilities.Feedback;
using SLSUtilities.Rendering.PostProcessing;
using UnityEngine;
namespace Cielonos.MainGame.Effects.Feedback
{
/// <summary>
/// RGB分离故障震动事件。
/// </summary>
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);
}
}
/// <summary>
/// RGB分离故障震动实例。
/// </summary>
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;
}
}
/// <summary>
/// RGBSplitGlitch 的震动聚合器。
/// </summary>
[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<RGBSplitGlitchShakeInstance> _activeShakes = new List<RGBSplitGlitchShakeInstance>();
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();
}
}
}