You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CrowdControl/Assets/Plugins/Animancer/Internal/Core/AnimancerEvent.cs

170 lines
6.8 KiB
C#

1 month ago
// Animancer // Copyright 2020 Kybernetik //
using System;
using System.Text;
using UnityEngine;
namespace Animancer
{
/// <summary>
/// A <see cref="callback"/> delegate paired with a <see cref="normalizedTime"/> to determine when to invoke it.
/// </summary>
public partial struct AnimancerEvent
{
/************************************************************************************************************************/
#region Event
/************************************************************************************************************************/
/// <summary>The <see cref="AnimancerState.NormalizedTime"/> at which to invoke the <see cref="callback"/>.</summary>
public float normalizedTime;
/// <summary>The delegate to invoke when the <see cref="normalizedTime"/> passes.</summary>
public Action callback;
/// <summary>The largest possible float value less than 1.</summary>
public const float AlmostOne = 0.99999994f;
/************************************************************************************************************************/
/// <summary>Constructs a new <see cref="AnimancerEvent"/>.</summary>
public AnimancerEvent(float normalizedTime, Action callback)
{
this.normalizedTime = normalizedTime;
this.callback = callback;
}
/************************************************************************************************************************/
/// <summary>Returns "AnimancerEvent(normalizedTime, callbackTarget.CallbackMethod)".</summary>
public override string ToString()
{
var text = new StringBuilder()
.Append("AnimancerEvent(")
.Append(normalizedTime)
.Append(", ");
if (callback == null)
{
text.Append("null)");
}
else if (callback.Target == null)
{
text.Append(callback.Method.Name)
.Append(")");
}
else
{
text.Append(callback.Target)
.Append('.')
.Append(callback.Method.Name)
.Append(")");
}
return text.ToString();
}
/************************************************************************************************************************/
/// <summary>Appends the details of this event to the `text`.</summary>
public void AppendDetails(StringBuilder text, string name, string delimiter = "\n")
{
text.Append(delimiter).Append(name).Append(".NormalizedTime=").Append(normalizedTime);
if (callback != null)
{
text.Append(delimiter).Append(name).Append(".Target=").Append(callback.Target);
text.Append(delimiter).Append(name).Append(".Method=").Append(callback.Method);
}
}
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
#region Invocation
/************************************************************************************************************************/
/// <summary>The <see cref="AnimancerState"/> currently triggering an event using <see cref="Invoke"/>.</summary>
public static AnimancerState CurrentState { get { return _CurrentState; } }
private static AnimancerState _CurrentState;
/************************************************************************************************************************/
/// <summary>The <see cref="AnimancerEvent"/> currently being triggered by <see cref="Invoke"/>.</summary>
public static AnimancerEvent CurrentEvent { get { return _CurrentEvent; } }
private static AnimancerEvent _CurrentEvent;
/************************************************************************************************************************/
/// <summary>
/// Sets the static <see cref="CurrentState"/> and <see cref="CurrentEvent"/> then invokes the <see cref="callback"/>.
/// <para></para>
/// This method catches and logs any exception thrown by the <see cref="callback"/>.
/// </summary>
/// <exception cref="NullReferenceException">Thrown if the <see cref="callback"/> is null.</exception>
public void Invoke(AnimancerState state)
{
var previousState = _CurrentState;
var previousEvent = _CurrentEvent;
_CurrentState = state;
_CurrentEvent = this;
try
{
callback();
}
catch (Exception ex)
{
Debug.LogException(ex);
}
_CurrentState = previousState;
_CurrentEvent = previousEvent;
}
/************************************************************************************************************************/
/// <summary>
/// Returns either the `minDuration` or the <see cref="AnimancerState.RemainingDuration"/> of the
/// <see cref="CurrentState"/> state (whichever is higher).
/// </summary>
public static float GetFadeOutDuration(float minDuration = AnimancerPlayable.DefaultFadeDuration)
{
var state = CurrentState;
if (state == null)
return minDuration;
var time = state.Time;
var speed = state.EffectiveSpeed;
float remainingDuration;
if (state.IsLooping)
{
var previousTime = time - speed * Time.deltaTime;
var inverseLength = 1f / state.Length;
// If we just passed the end of the animation, the remaining duration would technically be the full
// duration of the animation, so we most likely want to use the minimum duration instead.
if (Math.Floor(time * inverseLength) != Math.Floor(previousTime * inverseLength))
return minDuration;
}
if (speed > 0)
{
remainingDuration = (state.Length - time) * speed;
}
else
{
remainingDuration = time * -speed;
}
return Math.Max(minDuration, remainingDuration);
}
/************************************************************************************************************************/
#endregion
/************************************************************************************************************************/
}
}