【Unity】【C#】現在再生中のアニメーションの経過時間を取得する 
2020/02/29 Sat [edit]
なぜかググっても簡単な例が見つからなかったので、とりあえずのものを書いておく。長さの取得例は多いんだけどね。基本的には AnimatorStateInfo や AnimationState あたりで取得できる情報を使えば良いだけなのだが、毎回書くのは面倒だったので、拡張メソッドを定義しておくと楽になると思う。
(※) Unity 2019.2.20f1 / Windows10(x64) で確認
■Animator から経過時間/長さを取得
●Animator から経過時間/長さを取得
using UnityEngine;
public static class Extensions //※名前は任意
{
/// <summary>
/// 現在のアニメーションの経過時間を取得する
/// </summary>
/// <param name="animator">対象のアニメータ</param>
/// <param name="layerIndex">レイヤーのインデクス</param>
/// <returns>経過時間(秒), null のときは常に 0</returns>
public static float GetCurrentTime(this Animator animator, int layerIndex = 0)
{
if (animator == null)
return 0;
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(layerIndex); //現在のステートを取得
return stateInfo.length * stateInfo.normalizedTime;
}
/// <summary>
/// 現在のアニメーションの長さを取得する
/// </summary>
/// <param name="animator">対象のアニメータ</param>
/// <param name="layerIndex">レイヤーのインデクス</param>
/// <returns>アニメーションの長さ(秒), null のときは常に 0</returns>
public static float GetLength(this Animator animator, int layerIndex = 0)
{
if (animator == null)
return 0;
AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(layerIndex); //現在のステートを取得
return stateInfo.length;
}
}
●使用例(メインコード等)
using UnityEngine;
var animator = GetComponent<Animator>();
Debug.Log("time = " + animator.GetCurrentTime()); //※アクセスしているアニメーションが動いている方がわかりやすい
Debug.Log("length = " + animator.GetLength());
GetLength() の方はついでに作っておいただけのものなので、実際には同時に取得したいなら、普通に AnimatorStateInfo 取得してプロパティを使った方が良いかも知れない。特に長さは途中で変わるものではないから、使い回すときには結果をキャッシュした方が良いこともあるね。
・AnimatorStateInfo
■Animation から経過時間/長さを取得
●Animation から経過時間/長さを取得
using UnityEngine;
public static class Extensions //※名前は任意
{
/// <summary>
/// 現在のアニメーションの経過時間を取得する
/// </summary>
/// <param name="animation">対象のアニメーション</param>
/// <param name="allowWrapMode">ラップモードに従う:true = 永久ループ系(Loop, PingPong)のとき長さ以上も許可 / false = 曲の長さ以内</param>
/// <returns>経過時間(秒), null のときは常に 0</returns>
public static float GetCurrentTime(this Animation animation, bool allowWrapMode = false)
{
if (animation == null || animation.clip == null)
return 0;
AnimationState state = animation[animation.clip.name]; //現在のステートを取得
//WrapMode が永久ループ系(Loop, PingPong)のとき、長さ(length)より大きくなることもある
//https://docs.unity3d.com/ja/current/ScriptReference/WrapMode.html
//また、再生速度のプロパティ:speed は1(1倍)で考えているが、1でないときは time は現実時間とは違うので注意(長さに対する位置と考えるとわかりやすい)
return allowWrapMode ? state.time : (state.time % state.length);
}
/// <summary>
/// 現在のアニメーションの長さを取得する
/// </summary>
/// <param name="animation">対象のアニメーション</param>
/// <returns>アニメーションの長さ(秒), null のときは常に 0</returns>
public static float GetLength(this Animation animation)
{
if (animation == null || animation.clip == null)
return 0;
return animation.clip.length;
}
}
●使用例(メインコード等)
using UnityEngine;
var animation = GetComponent<Animation>();
Debug.Log("time = " + animation.GetCurrentTime()); //※アクセスしているアニメーションが動いている方がわかりやすい
Debug.Log("length = " + animation.GetLength());
GetLength() の方はついでに作っておいただけのものなので、実際には同時に取得したいなら、普通に AnimationState 取得してプロパティを使った方が良いかも知れない。特に長さはステートからでも clip プロパティ(AnimationClip) からも取得できるのでメソッド無くても良いしね(まぁ、Animator のと同じように統一して定義しておくと、迷わなくて済むというだけ(笑))。
AnimationState にも AnimatorStateInfo のように正規化された時間(曲の長さを1とし、0~1で位置を表す):normalizedTime があるので、「state.length * state.normalizedTime」でも経過時間を求められる。必要あればその方法で計算をするのも良いだろう(この例では別段必要はないので time の方にした)。
・AnimationState
また、ここではアニメーションの再生速度のプロパティ:speed は1(=1倍)で考えているが、1でないときは time は現実時間とは違うので注意しよう(長さに対する位置と考えるとわかりやすい)。その場合、現実時間は以下のようにすれば求まる。
●speed が1以外のとき、現実の時間を求める
var animation = GetComponent<Animation>();
AnimationState state = animation[animation.clip.name];
float realTime = (1f / state.speed) * state.time;
再生速度に関わらず現実時間に合わせたいなら「state.speed * state.time」で良い。まぁ、このような比率的な計算をするなら normalizedTime を使った方が直感的に書けるというメリットがある。用途に合わせて使い分けると良いだろう。
(関連記事)
【Unity】AnimationCurve をコードで初期化する
【Unity】5.6 のアニメーションは非アクティブ化でリセットされない(5.6のアニメーション挙動の違い)
- 関連記事
トラックバック
トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/346-bf0b2b0d
この記事にトラックバックする(FC2ブログユーザー)
| h o m e |