170 lines
7.2 KiB
C#
170 lines
7.2 KiB
C#
// Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
|
|
|
|
using System;
|
|
using System.Runtime.CompilerServices;
|
|
using UnityEngine;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace Animancer
|
|
{
|
|
/// <summary>[Pro-Only] An object that can be updated during Animancer's animation updates.</summary>
|
|
///
|
|
/// <remarks>
|
|
/// <strong>Example:</strong>
|
|
/// Register to receive updates using <see cref="AnimancerGraph.RequirePreUpdate"/> or
|
|
/// <see cref="AnimancerGraph.RequirePostUpdate"/> and stop
|
|
/// receiving updates using <see cref="AnimancerGraph.CancelPreUpdate"/> or
|
|
/// <see cref="AnimancerGraph.CancelPostUpdate"/>.
|
|
/// <para></para><code>
|
|
/// public sealed class MyUpdatable : IUpdatable
|
|
/// {
|
|
/// // Implement IUpdatable.
|
|
/// // You can avoid this by inheriting from Updatable instead.
|
|
/// int IUpdatable.UpdatableIndex { get; set; } = IUpdatable.List.NotInList;
|
|
///
|
|
/// private AnimancerComponent _Animancer;
|
|
///
|
|
/// public void StartUpdating(AnimancerComponent animancer)
|
|
/// {
|
|
/// _Animancer = animancer;
|
|
///
|
|
/// // If you want Update to be called before the playables get updated.
|
|
/// _Animancer.Graph.RequirePreUpdate(this);
|
|
///
|
|
/// // If you want Update to be called after the playables get updated.
|
|
/// _Animancer.Graph.RequirePostUpdate(this);
|
|
/// }
|
|
///
|
|
/// public void StopUpdating()
|
|
/// {
|
|
/// // If you used RequirePreUpdate.
|
|
/// _Animancer.Graph.CancelPreUpdate(this);
|
|
///
|
|
/// // If you used RequirePostUpdate.
|
|
/// _Animancer.Graph.CancelPostUpdate(this);
|
|
/// }
|
|
///
|
|
/// void IUpdatable.Update()
|
|
/// {
|
|
/// // Called during every animation update.
|
|
///
|
|
/// // AnimancerGraph.Current can be used to access the system it is being updated by.
|
|
/// }
|
|
/// }
|
|
/// </code></remarks>
|
|
///
|
|
/// https://kybernetik.com.au/animancer/api/Animancer/IUpdatable
|
|
///
|
|
public interface IUpdatable
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The index of this object in its <see cref="IndexedList{TItem, TIndexer}"/>.</summary>
|
|
/// <remarks>Should be initialized to -1 to indicate that this object is not yet in a list.</remarks>
|
|
int UpdatableIndex { get; set; }
|
|
|
|
/// <summary>Updates this object.</summary>
|
|
void Update();
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>An <see cref="IIndexer{T}"/> for <see cref="IUpdatable"/>.</summary>
|
|
public readonly struct Indexer : IIndexer<IUpdatable>
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <inheritdoc/>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public readonly int GetIndex(IUpdatable item)
|
|
=> item.UpdatableIndex;
|
|
|
|
/// <inheritdoc/>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public readonly void SetIndex(IUpdatable item, int index)
|
|
=> item.UpdatableIndex = index;
|
|
|
|
/// <inheritdoc/>
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public readonly void ClearIndex(IUpdatable item)
|
|
=> item.UpdatableIndex = -1;
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>An <see cref="IndexedList{TItem, TAccessor}"/> of <see cref="IUpdatable"/>.</summary>
|
|
public class List : IndexedList<IUpdatable, Indexer>
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>The default <see cref="IndexedList{TItem, TIndexer}.Capacity"/> for newly created lists.</summary>
|
|
/// <remarks>Default value is 4.</remarks>
|
|
public static new int DefaultCapacity { get; set; } = 4;
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Creates a new <see cref="List"/> with the <see cref="DefaultCapacity"/>.</summary>
|
|
public List()
|
|
: base(DefaultCapacity, new())
|
|
{ }
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Calls <see cref="Update"/> on all items in this list.</summary>
|
|
/// <remarks>
|
|
/// Uses <see cref="Debug.LogException(Exception, Object)"/> to handle exceptions and continues executing
|
|
/// the remaining items if any occur.
|
|
/// </remarks>
|
|
public void UpdateAll()
|
|
{
|
|
BeginEnumeraton();
|
|
ContinueEnumeration:
|
|
try
|
|
{
|
|
while (TryEnumerateNext())
|
|
{
|
|
Current.Update();
|
|
}
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
Debug.LogException(exception, AnimancerGraph.Current?.Component as Object);
|
|
goto ContinueEnumeration;
|
|
}
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Clones any <see cref="ICloneable{T}"/> items.</summary>
|
|
public void CloneFrom(
|
|
List copyFrom,
|
|
CloneContext context)
|
|
{
|
|
var count = copyFrom.Count;
|
|
for (int i = 0; i < count; i++)
|
|
if (copyFrom[i] is ICloneable<object> cloneable &&
|
|
context.GetOrCreateClone(cloneable) is IUpdatable clone)
|
|
Add(clone);
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
|
|
/// https://kybernetik.com.au/animancer/api/Animancer/AnimancerUtilities
|
|
public static partial class AnimancerUtilities
|
|
{
|
|
/************************************************************************************************************************/
|
|
|
|
/// <summary>Is the `updatable` currently in a list?</summary>
|
|
public static bool IsInList(this IUpdatable updatable)
|
|
=> updatable.UpdatableIndex >= 0;
|
|
|
|
/************************************************************************************************************************/
|
|
}
|
|
}
|
|
|