257 lines
8.7 KiB
C#
257 lines
8.7 KiB
C#
|
|
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();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|