環境
・Unity 2017.1.0p5
・.NET 4.6
・UniRx
そもそもUnityのAnimator細かいところが足りてない
・PlayしたフレームでAnimatorStateInfoとか取得できない
・再生中かどうかのプロパティが存在しない
アニメーションの終了フラグ
とりあえず共通で使える終了判定が欲しかった
AnimatorExtension.cs
public static bool IsEnd(this Animator animator, int layerIndex = 0)
{
//オブジェクトがアクティブではない時は終了と同義とする
if (!animator.gameObject.activeInHierarchy)
return true;
return animator.GetCurrentAnimatorStateInfo(layerIndex).normalizedTime >= 1;
}
Reactiveな終了フラグ
UniRxに慣れるとReactiveな終了フラグも欲しくなる
AnimatorExtension.cs
private static Dictionary<UniRx.Tuple<Animator,int>, ReactiveProperty<bool>> _reactiveProperties = new Dictionary<UniRx.Tuple<Animator, int>, ReactiveProperty<bool>>();
public static ReactiveProperty<bool> GetIsEndReactiveProperty(this Animator animator, int layerIndex = 0)
{
var key = new UniRx.Tuple<Animator, int>(animator, layerIndex);
if (_reactiveProperties.ContainsKey(key))
return _reactiveProperties[key];
_reactiveProperties.Add(key, animator.ObserveEveryValueChanged(_ => animator.IsEnd(layerIndex)).ToReactiveProperty());
//解放処理
animator.OnDestroyAsObservable().Subscribe(_ => _reactiveProperties.Remove(key));
return _reactiveProperties[key];
}
Playのオーバーロード
Play時に色々設定したい!
AnimatorExtension.cs
/// <summary>
/// アニメーション再生 コールバック指定可
/// </summary>
/// <param name="animator"></param>
/// <param name="stateName"></param>
/// <param name="layer"></param>
/// <param name="normalizedTime"></param>
/// <param name="nextFrameAction">再生開始の次フレーム時コールバック</param>
/// <param name="endAction">終了時コールバック</param>
public static void Play(this Animator animator, string stateName, int layer = 0, float normalizedTime = 0f, Action nextFrameAction = null, Action endAction = null)
{
animator.Play(stateName, layer, normalizedTime);
if (endAction != null || nextFrameAction != null)
Observable.NextFrame().Subscribe(_ =>
{
nextFrameAction?.Invoke();
if (endAction != null)
animator.GetIsEndReactiveProperty()
.First(isEnd => isEnd)
.Subscribe(__ => endAction())
.AddTo(animator);
}).AddTo(animator);
}
/// <summary>
/// アニメーション再生 コールバック指定可
/// </summary>
/// <param name="animator"></param>
/// <param name="stateNameHash"></param>
/// <param name="layer"></param>
/// <param name="normalizedTime"></param>
/// <param name="nextFrameAction">再生開始の次フレーム時コールバック</param>
/// <param name="endAction">終了時コールバック</param>
public static void Play(this Animator animator, int stateNameHash, int layer = 0, float normalizedTime = 0f, Action nextFrameAction = null, Action endAction = null)
{
animator.Play(stateNameHash, layer, normalizedTime);
if (endAction != null || nextFrameAction != null)
Observable.NextFrame().Subscribe(_ =>
{
nextFrameAction?.Invoke();
if (endAction != null)
animator.GetIsEndReactiveProperty()
.First(isEnd => isEnd)
.Subscribe(__ => endAction())
.AddTo(animator);
}).AddTo(animator);
}
使い方
hoge.cs
GetComponent<Animator>().Play("アニメーション名",
nextFrameAction:()=>{
Debug.Log("再生開始の次フレーム!アニメーションの各種情報取得できるよ!");
},
endAction:()=>{
Debug.Log("アニメーション終了!");
}
);
nextFrameActionはアニメーションスピード調整したい時によく使う
endActionはオブジェクトプール管理してるエフェクトとかで終了時にプールに戻すときにめっちゃ使う