📗
【Unity】AnimationManagerについて
はじめに
初めての方も、そうでない方もこんにちは!
現役ゲームプログラマーのたむぼーです。
自己紹介を載せているので、気になる方は見ていただければ嬉しいです!
今回は
AnimationManager
について紹介します
アニメーション統合クリップ
前回の記事のアニメーション統合クリップを使用した、アニメーションマネージャーを実装しました。
UniRx/UniTask
Task管理などでUniRx/UniTaskを利用しています。
CancellationTokenHelperについては、こちらの記事の最後にあります。
使い方
// 対象のオブジェクト(target)のShowアニメーションを実行
AnimationManager.Instance.AddAnimationObject(target, "Show");
// 対象のオブジェクト(target)のHideアニメーションを実行
AnimationManager.Instance.AddAnimationObject(target, "Hide");
型 | 変数 | 説明 |
---|---|---|
GameObject | obj | Animatorをアタッチしたオブジェクト |
string | stateName | どのステートのアニメーションをさせるか |
Animator | animator | アニメーター |
Action | beforeAction | アニメーション開始前に実行するアクション |
Action | afterAction | アニメーション終了後に実行するアクション |
スクリプト
アニメーションマネージャー
AnimationManager.cs
using System;
using System.Collections.Generic;
using UnityEngine;
using UniRx;
using Cysharp.Threading.Tasks;
using System.Threading;
using System.Linq;
namespace Utils
{
sealed public class AnimationManager
{
private static AnimationManager _instance = null;
public static AnimationManager Instance
{
get
{
_instance ??= new AnimationManager();
return _instance;
}
}
private List<AnimationObject> _animationObjects = new List<AnimationObject>();
/// <summary>
/// アニメーションする対象を追加
/// </summary>
public AnimationObject AddAnimationObject(GameObject obj, string stateName, Animator animator = null, Action beforeAction = null, Action afterAction = null)
{
if (string.IsNullOrEmpty(stateName))
{
return null;
}
if (animator == null)
{
animator = obj.GetComponent<Animator>();
if (animator == null)
{
return null;
}
}
AnimationObject existingAnimationObject = _animationObjects.FirstOrDefault(a => a.obj == obj);
if (existingAnimationObject != null)
{
CancelAnimation(existingAnimationObject);
_animationObjects.Remove(existingAnimationObject);
}
AnimationObject animationObject = new AnimationObject()
{
obj = obj,
animator = animator,
stateName = stateName,
beforeAction = beforeAction,
afterAction = afterAction,
ctsHelper = new CancellationTokenHelper()
};
_animationObjects.Add(animationObject);
ApplyAndPlayAnimation(animationObject).Forget();
return animationObject;
}
/// <summary>
/// アニメーションする対象を事前読み込み
/// </summary>
public AnimationObject PreloadAddAnimationObject(GameObject obj, string stateName, Animator animator = null, Action beforeAction = null, Action afterAction = null)
{
if (string.IsNullOrEmpty(stateName))
{
return null;
}
if (animator == null)
{
animator = obj.GetComponent<Animator>();
if (animator == null)
{
return null;
}
}
AnimationObject existingAnimationObject = _animationObjects.FirstOrDefault(a => a.obj == obj);
if (existingAnimationObject != null)
{
CancelAnimation(existingAnimationObject);
_animationObjects.Remove(existingAnimationObject);
}
AnimationObject animationObject = new AnimationObject()
{
obj = obj,
animator = animator,
stateName = stateName,
beforeAction = beforeAction,
afterAction = afterAction,
ctsHelper = new CancellationTokenHelper()
};
_animationObjects.Add(animationObject);
return animationObject;
}
/// <summary>
/// 事前に読み込んだアニメーションオブジェクトを実行
/// </summary>
public void ActivatePreloadedAnimation(AnimationObject animationObject)
{
ApplyAndPlayAnimation(animationObject).Forget();
}
/// <summary>
/// アニメーションプロパティの適用
/// </summary>
public void ApplyAnimationProperties(Animator animator, GameObject target, string stateName)
{
AnimationController.ApplyProperties(animator, target, stateName);
}
/// <summary>
/// アニメーションを再生
/// </summary>
public async UniTask PlayAnimation(Animator animator, string stateName, Action beforeAction, Action afterAction, CancellationToken token)
{
await AnimationController.Play(animator, stateName, beforeAction, afterAction, token);
}
/// <summary>
/// アニメーションの時間を取得
/// </summary>
public float GetAnimationTime(AnimationObject animationObject)
{
return AnimationController.GetAnimationTime(animationObject.animator, animationObject.stateName);
}
/// <summary>
/// アニメーションをキャンセル
/// </summary>
public void CancelAnimation()
{
foreach (var animationObject in _animationObjects)
{
CancelAnimation(animationObject);
}
}
/// <summary>
/// 特定のアニメーションをキャンセル
/// </summary>
public void CancelAnimation(AnimationObject animationObject)
{
animationObject.ctsHelper.Dispose();
_animationObjects.Remove(animationObject);
}
/// <summary>
/// アニメーションを適用し再生する処理
/// </summary>
private async UniTaskVoid ApplyAndPlayAnimation(AnimationObject animationObject)
{
ApplyAnimationProperties(animationObject.animator, animationObject.obj, animationObject.stateName);
try
{
await PlayAnimation(animationObject.animator, animationObject.stateName, animationObject.beforeAction, animationObject.afterAction, animationObject.ctsHelper.Token);
}
catch (OperationCanceledException)
{
// キャンセル時の処理
}
_animationObjects.Remove(animationObject);
}
}
}
アニメーションコントローラー
AnimationController.cs
using System;
using UnityEngine;
using Cysharp.Threading.Tasks;
using System.Threading;
using System.Linq;
namespace Utils
{
[Serializable]
sealed public class AnimationController
{
/// <summary>
/// 最初のフレームのプロパティを適用
/// </summary>
static public void ApplyProperties(Animator animator, GameObject target, string stateName)
{
// アニメーションクリップを取得
AnimationClip animationClip = animator.runtimeAnimatorController.animationClips.FirstOrDefault(clip => clip.name == stateName);
if (animationClip != null)
{
// アニメーションの初期フレームをターゲットに適用
animator.enabled = false;
animationClip.SampleAnimation(target, 0);
}
}
/// <summary>
/// 再生処理
/// </summary>
static public async UniTask Play(Animator animator, string stateName, Action beforeAction, Action afterAction, CancellationToken token)
{
beforeAction?.Invoke();
animator.enabled = true;
// アニメーションの再生
await PlayAnimation(animator, stateName, token);
afterAction?.Invoke();
}
/// <summary>
/// アニメーションを実行し、完了を待つ
/// </summary>
static private async UniTask PlayAnimation(Animator animator, string stateName, CancellationToken token)
{
if (animator == null)
{
return;
}
animator.Play(stateName);
await UniTask.WaitUntil(() =>
{
if (animator == null || animator.gameObject == null)
{
return true;
}
return animator.GetCurrentAnimatorStateInfo(0).IsName(stateName) &&
animator.GetCurrentAnimatorStateInfo(0).normalizedTime >= 1.0f;
}, cancellationToken: token);
}
/// <summary>
/// 指定されたステート名のアニメーションの時間を取得
/// </summary>
static public float GetAnimationTime(Animator animator, string stateName)
{
if (animator == null)
{
return 0.0f;
}
AnimationClip animationClip = animator.runtimeAnimatorController.animationClips.FirstOrDefault(clip => clip.name == stateName);
return animationClip != null ? animationClip.length : 0f;
}
}
}
アニメーション対象のオブジェクト
AnimationObject.cs
using System;
using UnityEngine;
namespace Utils
{
sealed public class AnimationObject
{
public GameObject obj;
public Animator animator;
public string stateName;
public Action beforeAction;
public Action afterAction;
public CancellationTokenHelper ctsHelper;
}
}
Discussion