[Unity]アニメーションのコールバック

## 環境
　・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はオブジェクトプール管理してるエフェクトとかで終了時にプールに戻すときにめっちゃ使う