mirror of https://github.com/Cysharp/UniTask
feat: add animator extensions
parent
996a2cfa5b
commit
97f0c7a62b
|
@ -0,0 +1,179 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Cysharp.Threading.Tasks
|
||||||
|
{
|
||||||
|
public static partial class UnityAsyncExtensions
|
||||||
|
{
|
||||||
|
public static UniTask WaitAnimationComplete(this Animator animator, string animationName, int layer = 0,
|
||||||
|
IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.PostLateUpdate)
|
||||||
|
{
|
||||||
|
return WaitAnimationComplete(animator, Animator.StringToHash(animationName), layer, progress, timing,
|
||||||
|
cancellationToken: animator.GetCancellationTokenOnDestroy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask WaitAnimationComplete(this Animator animator, int layer = 0,
|
||||||
|
IProgress<float> progress = null, PlayerLoopTiming timing = PlayerLoopTiming.PostLateUpdate)
|
||||||
|
{
|
||||||
|
return WaitAnimationComplete(animator, -1, layer, progress, timing,
|
||||||
|
cancellationToken: animator.GetCancellationTokenOnDestroy());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static UniTask WaitAnimationComplete(this Animator animator, int animationHash = -1, int layer = 0,
|
||||||
|
IProgress<float> progress = null,
|
||||||
|
PlayerLoopTiming timing = PlayerLoopTiming.PostLateUpdate, CancellationToken cancellationToken = default,
|
||||||
|
bool cancelImmediately = false)
|
||||||
|
{
|
||||||
|
if (animator == null)
|
||||||
|
throw new ArgumentNullException(nameof(animator));
|
||||||
|
|
||||||
|
if (cancellationToken.IsCancellationRequested) return UniTask.FromCanceled(cancellationToken);
|
||||||
|
|
||||||
|
return new UniTask(
|
||||||
|
AnimatorStateSource.Create(animator, animationHash, layer, timing, progress, cancellationToken,
|
||||||
|
cancelImmediately,
|
||||||
|
out var token), token);
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class AnimatorStateSource : IUniTaskSource, IPlayerLoopItem, ITaskPoolNode<AnimatorStateSource>
|
||||||
|
{
|
||||||
|
private static TaskPool<AnimatorStateSource> _pool;
|
||||||
|
private AnimatorStateSource _nextNode;
|
||||||
|
|
||||||
|
public ref AnimatorStateSource NextNode => ref _nextNode;
|
||||||
|
|
||||||
|
static AnimatorStateSource()
|
||||||
|
{
|
||||||
|
TaskPool.RegisterSizeGetter(typeof(AnimatorStateSource), () => _pool.Size);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Animator _animator;
|
||||||
|
private int _animationHash;
|
||||||
|
private int _layer;
|
||||||
|
private IProgress<float> _progress;
|
||||||
|
private CancellationToken _cancellationToken;
|
||||||
|
private CancellationTokenRegistration _cancellationTokenRegistration;
|
||||||
|
private bool _cancelImmediately;
|
||||||
|
private bool _completed;
|
||||||
|
|
||||||
|
private UniTaskCompletionSourceCore<AsyncUnit> _core;
|
||||||
|
|
||||||
|
AnimatorStateSource()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IUniTaskSource Create(Animator animator, int animation, int layer, PlayerLoopTiming timing,
|
||||||
|
IProgress<float> progress, CancellationToken cancellationToken, bool cancelImmediately, out short token)
|
||||||
|
{
|
||||||
|
if (cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return AutoResetUniTaskCompletionSource.CreateFromCanceled(cancellationToken, out token);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_pool.TryPop(out var result))
|
||||||
|
{
|
||||||
|
result = new AnimatorStateSource();
|
||||||
|
}
|
||||||
|
|
||||||
|
result._animator = animator;
|
||||||
|
result._animationHash = animation;
|
||||||
|
result._layer = layer;
|
||||||
|
result._progress = progress;
|
||||||
|
result._cancellationToken = cancellationToken;
|
||||||
|
result._cancelImmediately = cancelImmediately;
|
||||||
|
result._completed = false;
|
||||||
|
|
||||||
|
if (result._cancelImmediately && result._cancellationToken.CanBeCanceled)
|
||||||
|
{
|
||||||
|
result._cancellationTokenRegistration = cancellationToken.RegisterWithoutCaptureExecutionContext(
|
||||||
|
state =>
|
||||||
|
{
|
||||||
|
var source = (AnimatorStateSource)state;
|
||||||
|
source._core.TrySetCanceled(source._cancellationToken);
|
||||||
|
}, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
TaskTracker.TrackActiveTask(result, 3);
|
||||||
|
PlayerLoopHelper.AddAction(timing, result);
|
||||||
|
|
||||||
|
token = result._core.Version;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void GetResult(short token)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_core.GetResult(token);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!(_cancelImmediately && _cancellationToken.IsCancellationRequested))
|
||||||
|
{
|
||||||
|
TryReturn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus GetStatus(short token)
|
||||||
|
{
|
||||||
|
return _core.GetStatus(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UniTaskStatus UnsafeGetStatus()
|
||||||
|
{
|
||||||
|
return _core.UnsafeGetStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnCompleted(Action<object> continuation, object state, short token)
|
||||||
|
{
|
||||||
|
_core.OnCompleted(continuation, state, token);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (_completed || _animator == null || !_animator.enabled)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
_core.TrySetCanceled(_cancellationToken);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatorStateInfo stateInfo = _animator.GetCurrentAnimatorStateInfo(_layer);
|
||||||
|
|
||||||
|
if (_animationHash != -1 && stateInfo.shortNameHash != _animationHash)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
float normalizedTime = stateInfo.normalizedTime;
|
||||||
|
float progressValue = Mathf.Clamp01(normalizedTime);
|
||||||
|
|
||||||
|
_progress?.Report(progressValue);
|
||||||
|
|
||||||
|
if (progressValue < 1f)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
_core.TrySetResult(AsyncUnit.Default);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool TryReturn()
|
||||||
|
{
|
||||||
|
TaskTracker.RemoveTracking(this);
|
||||||
|
|
||||||
|
_core.Reset();
|
||||||
|
_animator = default;
|
||||||
|
_progress = default;
|
||||||
|
_cancellationToken = default;
|
||||||
|
_cancellationTokenRegistration.Dispose();
|
||||||
|
_cancelImmediately = default;
|
||||||
|
|
||||||
|
return _pool.TryPush(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 65a937d944608b444ba2255ad7a80677
|
Loading…
Reference in New Issue