Files
Cielonos/Assets/Scripts/MainGame/Effects/Feedbacks/Shakers/AnimeBloomShaker.cs
SoulliesOfficial 8ad26129b2 Feel滚
2026-04-29 06:16:07 -04:00

257 lines
8.7 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Generic;
using SLSUtilities.Feedback;
using SLSUtilities.Rendering.PostProcessing;
using UnityEngine;
namespace Cielonos.MainGame.Effects.Feedback
{
/// <summary>
/// AnimeBloom 震动事件。由 BloomAction 触发AnimeBloomShaker 监听。
/// </summary>
public struct AnimeBloomShakeEvent
{
private static event ShakeDelegate OnEvent;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
private static void RuntimeInitialization() { OnEvent = null; }
public delegate void ShakeDelegate(
FeedbackContext feedbackContext,
FloatCurveChannel intensityCurve,
bool modifyThreshold,
FloatCurveChannel thresholdCurve,
float threshold,
bool modifyScatter,
FloatCurveChannel scatterCurve,
float scatter,
bool modifyTint,
ColorCurveChannel tintCurve,
Color tint,
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 modifyThreshold = false,
FloatCurveChannel thresholdCurve = default,
float threshold = 1.1f,
bool modifyScatter = false,
FloatCurveChannel scatterCurve = default,
float scatter = 0.7f,
bool modifyTint = false,
ColorCurveChannel tintCurve = default,
Color tint = default,
bool stop = false)
{
OnEvent?.Invoke(feedbackContext, intensityCurve,
modifyThreshold, thresholdCurve, threshold,
modifyScatter, scatterCurve, scatter,
modifyTint, tintCurve, tint,
stop);
}
}
/// <summary>
/// AnimeBloom 震动实例。
/// </summary>
public class AnimeBloomShakeInstance : ShakeInstanceBase
{
public readonly FloatCurveChannel intensityCurve;
public readonly bool modifyThreshold;
public readonly FloatCurveChannel thresholdCurve;
public readonly float threshold;
public readonly bool modifyScatter;
public readonly FloatCurveChannel scatterCurve;
public readonly float scatter;
public readonly bool modifyTint;
public readonly ColorCurveChannel tintCurve;
public readonly Color tint;
public AnimeBloomShakeInstance(
FeedbackContext feedbackContext,
FloatCurveChannel intensityCurve,
bool modifyThreshold,
FloatCurveChannel thresholdCurve,
float threshold,
bool modifyScatter,
FloatCurveChannel scatterCurve,
float scatter,
bool modifyTint,
ColorCurveChannel tintCurve,
Color tint)
: base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration)
{
this.intensityCurve = intensityCurve;
this.modifyThreshold = modifyThreshold;
this.thresholdCurve = thresholdCurve;
this.threshold = threshold;
this.modifyScatter = modifyScatter;
this.scatterCurve = scatterCurve;
this.scatter = scatter;
this.modifyTint = modifyTint;
this.tintCurve = tintCurve;
this.tint = tint;
}
}
/// <summary>
/// AnimeBloom 的震动聚合器。监听 AnimeBloomShakeEvent驱动 AnimeBloom Volume 组件的参数动画。
/// 默认驱动 intensity可选驱动 threshold、scatter、tint。
/// </summary>
[AddComponentMenu("SLS Utilities/Feedback Shakers/Anime Bloom Shaker")]
public class AnimeBloomShaker : MonoBehaviour
{
private AnimeBloom _component;
private float _initialIntensity;
private float _initialThreshold;
private float _initialScatter;
private Color _initialTint;
private bool _resolved;
private readonly List<AnimeBloomShakeInstance> _activeShakes = new List<AnimeBloomShakeInstance>();
private void Awake()
{
_resolved = TryResolve();
}
private void OnEnable()
{
AnimeBloomShakeEvent.Register(OnShakeEvent);
}
private void OnDisable()
{
AnimeBloomShakeEvent.Unregister(OnShakeEvent);
StopAll();
}
private void Update()
{
if (!_resolved || _activeShakes.Count == 0) return;
float additiveIntensity = 0f;
float absoluteIntensity = 0f;
bool hasAbsolute = false;
float latestThreshold = _initialThreshold;
float latestScatter = _initialScatter;
Color latestTint = _initialTint;
bool hasThreshold = false;
bool hasScatter = false;
bool hasTint = false;
for (int i = _activeShakes.Count - 1; i >= 0; i--)
{
AnimeBloomShakeInstance shake = _activeShakes[i];
shake.timer += shake.timeProvider.GetDeltaTime(shake.timeSettings);
float normalizedTime = shake.timer / shake.duration;
float curveValue = shake.intensityCurve.Evaluate(normalizedTime);
if (shake.intensityCurve.relativeToInitial)
additiveIntensity += curveValue;
else
{
absoluteIntensity = curveValue;
hasAbsolute = true;
}
if (shake.modifyThreshold)
{
latestThreshold = shake.thresholdCurve.Evaluate(normalizedTime);
hasThreshold = true;
}
if (shake.modifyScatter)
{
latestScatter = shake.scatterCurve.Evaluate(normalizedTime);
hasScatter = true;
}
if (shake.modifyTint)
{
latestTint = shake.tintCurve.Evaluate(normalizedTime);
hasTint = true;
}
if (shake.IsFinished)
{
_activeShakes.RemoveAt(i);
}
}
float finalIntensity = hasAbsolute ? absoluteIntensity : _initialIntensity + additiveIntensity;
_component.intensity.value = finalIntensity;
if (hasThreshold) _component.threshold.value = latestThreshold;
if (hasScatter) _component.scatter.value = latestScatter;
if (hasTint) _component.tint.value = latestTint;
if (_activeShakes.Count == 0)
{
Restore();
}
}
private void OnShakeEvent(
FeedbackContext feedbackContext,
FloatCurveChannel intensityCurve,
bool modifyThreshold,
FloatCurveChannel thresholdCurve,
float threshold,
bool modifyScatter,
FloatCurveChannel scatterCurve,
float scatter,
bool modifyTint,
ColorCurveChannel tintCurve,
Color tint,
bool stop)
{
if (stop) { StopAll(); return; }
if (!_resolved) _resolved = TryResolve();
if (!_resolved) return;
var instance = new AnimeBloomShakeInstance(
feedbackContext,
intensityCurve,
modifyThreshold, thresholdCurve, threshold,
modifyScatter, scatterCurve, scatter,
modifyTint, tintCurve, tint
);
_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;
_initialThreshold = _component.threshold.value;
_initialScatter = _component.scatter.value;
_initialTint = _component.tint.value;
return true;
}
private void Restore()
{
if (!_resolved) return;
_component.intensity.value = _initialIntensity;
_component.threshold.value = _initialThreshold;
_component.scatter.value = _initialScatter;
_component.tint.value = _initialTint;
}
private void StopAll()
{
_activeShakes.Clear();
Restore();
}
}
}