316 lines
11 KiB
C#
316 lines
11 KiB
C#
using System.Collections.Generic;
|
||
using SLSUtilities.Feedback;
|
||
using SLSUtilities.Rendering.PostProcessing;
|
||
using UnityEngine;
|
||
|
||
namespace Cielonos.MainGame.Effects.Feedback
|
||
{
|
||
/// <summary>
|
||
/// 暗角震动事件。
|
||
/// </summary>
|
||
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,
|
||
Vector2CurveChannel centerCurve,
|
||
Vector2 center,
|
||
bool modifyColors,
|
||
ColorCurveChannel colorOuter,
|
||
ColorCurveChannel colorInner,
|
||
Color outColor,
|
||
Color innerColor,
|
||
bool modifyShape,
|
||
FloatCurveChannel smoothnessCurve,
|
||
FloatCurveChannel roundnessCurve,
|
||
float smoothness,
|
||
float roundness,
|
||
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,
|
||
Vector2CurveChannel centerCurve = default,
|
||
Vector2 center = default,
|
||
bool modifyColors = false,
|
||
ColorCurveChannel colorOuter = default,
|
||
ColorCurveChannel colorInner = default,
|
||
Color outColor = default,
|
||
Color innerColor = default,
|
||
bool modifyShape = false,
|
||
FloatCurveChannel smoothnessCurve = default,
|
||
FloatCurveChannel roundnessCurve = default,
|
||
float smoothness = 0f,
|
||
float roundness = 0f,
|
||
bool stop = false)
|
||
{
|
||
OnEvent?.Invoke(feedbackContext, intensityCurve, modifyCenter, centerCurve, center,
|
||
modifyColors, colorOuter, colorInner, outColor, innerColor, modifyShape,
|
||
smoothnessCurve, roundnessCurve, smoothness, roundness, stop);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 暗角震动实例。
|
||
/// </summary>
|
||
public class VignetteShakeInstance : ShakeInstanceBase
|
||
{
|
||
public readonly FloatCurveChannel intensityCurve;
|
||
public readonly bool modifyCenter;
|
||
public readonly Vector2CurveChannel centerCurve;
|
||
public readonly Vector2 center;
|
||
public readonly bool modifyColors;
|
||
public readonly ColorCurveChannel colorOuter;
|
||
public readonly ColorCurveChannel colorInner;
|
||
public readonly Color outColor;
|
||
public readonly Color innerColor;
|
||
public readonly bool modifyShape;
|
||
public readonly FloatCurveChannel smoothnessCurve;
|
||
public readonly FloatCurveChannel roundnessCurve;
|
||
public readonly float smoothness;
|
||
public readonly float roundness;
|
||
|
||
public VignetteShakeInstance(
|
||
FeedbackContext feedbackContext,
|
||
FloatCurveChannel intensityCurve,
|
||
bool modifyCenter,
|
||
Vector2CurveChannel centerCurve,
|
||
Vector2 center,
|
||
bool modifyColors,
|
||
ColorCurveChannel colorOuter,
|
||
ColorCurveChannel colorInner,
|
||
Color outColor,
|
||
Color innerColor,
|
||
bool modifyShape,
|
||
FloatCurveChannel smoothnessCurve,
|
||
FloatCurveChannel roundnessCurve,
|
||
float smoothness,
|
||
float roundness)
|
||
: base(feedbackContext.timeSettings, feedbackContext.player.TimeProvider, feedbackContext.duration)
|
||
{
|
||
this.intensityCurve = intensityCurve;
|
||
this.modifyCenter = modifyCenter;
|
||
this.centerCurve = centerCurve;
|
||
this.center = center;
|
||
this.modifyColors = modifyColors;
|
||
this.colorOuter = colorOuter;
|
||
this.colorInner = colorInner;
|
||
this.outColor = outColor;
|
||
this.innerColor = innerColor;
|
||
this.modifyShape = modifyShape;
|
||
this.smoothnessCurve = smoothnessCurve;
|
||
this.roundnessCurve = roundnessCurve;
|
||
this.smoothness = smoothness;
|
||
this.roundness = roundness;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// AdvancedVignette 的震动聚合器。
|
||
/// </summary>
|
||
[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;
|
||
|
||
[Tooltip("暗角强度的下限")]
|
||
public float minIntensity = 0f;
|
||
[Tooltip("暗角强度的上限,Unity默认最高为1")]
|
||
public float maxIntensity = 1f;
|
||
|
||
private readonly List<VignetteShakeInstance> _activeShakes = new List<VignetteShakeInstance>();
|
||
|
||
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;
|
||
|
||
float curveValue = shake.intensityCurve.Evaluate(normalizedTime);
|
||
if (shake.intensityCurve.relativeToInitial)
|
||
{
|
||
additiveIntensity += curveValue;
|
||
}
|
||
else
|
||
{
|
||
absoluteIntensity = curveValue;
|
||
hasAbsolute = true;
|
||
}
|
||
|
||
latestCenter = shake.modifyCenter
|
||
? shake.centerCurve.Evaluate(normalizedTime, _initialCenter)
|
||
: shake.center;
|
||
hasCenter = true;
|
||
|
||
latestColorOuter = shake.modifyColors
|
||
? shake.colorOuter.Evaluate(normalizedTime)
|
||
: shake.outColor;
|
||
latestColorInner = shake.modifyColors
|
||
? shake.colorInner.Evaluate(normalizedTime)
|
||
: shake.innerColor;
|
||
hasColors = true;
|
||
|
||
latestSmoothness = shake.modifyShape
|
||
? shake.smoothnessCurve.Evaluate(normalizedTime)
|
||
: shake.smoothness;
|
||
latestRoundness = shake.modifyShape
|
||
? shake.roundnessCurve.Evaluate(normalizedTime)
|
||
: shake.roundness;
|
||
hasShape = true;
|
||
|
||
if (shake.IsFinished)
|
||
{
|
||
_activeShakes.RemoveAt(i);
|
||
}
|
||
}
|
||
|
||
float finalIntensity = hasAbsolute ? absoluteIntensity : _initialIntensity + additiveIntensity;
|
||
finalIntensity = Mathf.Clamp(finalIntensity, minIntensity, maxIntensity);
|
||
_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,
|
||
Vector2CurveChannel centerCurve,
|
||
Vector2 center,
|
||
bool modifyColors,
|
||
ColorCurveChannel colorOuter,
|
||
ColorCurveChannel colorInner,
|
||
Color outColor,
|
||
Color innerColor,
|
||
bool modifyShape,
|
||
FloatCurveChannel smoothnessCurve,
|
||
FloatCurveChannel roundnessCurve,
|
||
float smoothness,
|
||
float roundness,
|
||
bool stop)
|
||
{
|
||
if (stop) { StopAll(); return; }
|
||
if (!_resolved) _resolved = TryResolve();
|
||
if (!_resolved) return;
|
||
|
||
var instance = new VignetteShakeInstance(
|
||
feedbackContext,
|
||
intensityCurve,
|
||
modifyCenter,
|
||
centerCurve,
|
||
center,
|
||
modifyColors,
|
||
colorOuter,
|
||
colorInner,
|
||
outColor,
|
||
innerColor,
|
||
modifyShape,
|
||
smoothnessCurve,
|
||
roundnessCurve,
|
||
smoothness,
|
||
roundness
|
||
);
|
||
_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();
|
||
}
|
||
}
|
||
}
|