SimpleAnimationで常にtrueにならず、ちゃんとisPlayingを取得できるようにする方法
間が空きすぎてると話題のBlogですが、どうぞよろしくお願いします。 仕事でもUnityを扱ってるので少しずつできることが増えてきているんです。ほんとですよ!?
さて「SimpleAnimation」という超絶便利なものを使いはじめたのですが、isPlayingが常にtrueになってしまう という 致命的な状況に陥りました。 これに対しての解決方法がわかった気がするので備考録として書いておきます。
SimpleAnimationの基本的なことをまずはご紹介していきますね。
SimpleAnimation
さて、今回は3DのプロジェクトについてキャラクターをAnimationさせたいと思うことは、みなさんよくあるかと思います。 基本的なやり方としてはAnimatorを使って分かりづらい遷移をゴリゴリ書いていくのですが、見づらいです。 それをAnimationを直接呼び出せるセクシーなコンポーネントがあります。それが、SimpleAnimation というものなのです。 github.com
使い方
SimpleAnimationのフォルダをガッツリもらってきたら、自分のプロジェクトに打ち込むだけ。It's Easy! 読み込んだら、さっそくAnimationを適用したいキャラクターにぶちこんであげましょう!
そしたらインスペクターをチェックしてみましょう。
Animator部分は、Controllerだけ外しておきます。Animationの管理はSimpleAnimation側でやるためです。
次にSimpleAnimationをチェックします。
まずは、初期状態(idle)のアニメーションクリップを設定してあげましょう。
ここにクリップをD&Dしてあげると・・・。
はい、これでDefaultのモーションが設定できました。実行して確認してみましょう!
This is kawaii.
複数のAnimationの設定
Default以外にも登録していきたいときはAnimationsの数値を変えてクリップを登録していきます。 デフォルト以外は名前も変えられるので管理しやすいような名前をつけてクリップを設定していきましょう。
スクリプト側からこのAnimationの再生を切り替えることができます。
再生方法はいろいろあるのですがよく使うのが CrossFade("Animation名", 秒数); だと思います。
「Hello」というAnimationを設定し、ざっくりとテスト用スクリプトを書いてみました。ちょっと横着をしていますが、やってることはSimpleAnimation
コンポーネントの中のCrossFade
を呼び出してるだけです
void Update() { if (Input.GetMouseButtonDown(0)) { GameObject.Find("UnitySan").GetComponent<SimpleAnimation>().CrossFade("Hello", 0.2f); } }
とりあえずこれをユニティちゃんにアタッチして、クリックしてみると!!!!
クリックされたら挨拶をするKawaii Girlです。 Animatorの遷移条件とかを書く必要がないのでスクリプト側からガンガンかいていけて便利かつシンプルですね。
SimpleAnimationでisPlayingを取得したい
さて、本題に入りましょう。Animationが再生しているのか、終わっているのかを取得するためのisPlaying
ですがSimpleAnimationの仕様?としてうまく動作しないはずです。
その理由については下記サイトを参考にしました。
原因
何が起きているのかというと、割と単純で「Animationが終了したことを検知できていない」んだそうです。
逆に言えば、Animation Clip の WrapMode が 「Once」 ならAnimationの終了をちゃんと検知できる とのこと。
基本的にAnimation Clip側の設定を使うのでDefaultという設定になるのですが、それだとループしてる前提で判断してしまうようで・・・ループするAnimationに終了なんてものはないので常に再生されている状態、つまりtrueが返ってきてしまうそうです。
これで何がよろしくないのかというと、たとえばモーションが終わったら~~したい。という処理が作れなくなってしまいます。アイテムを拾う動作が終わったらインベントリを開く。とかやりたいですよね。でもできないんです。それは問題だ!
対策
対策に関してもこちらのサイトにかかれていたことを少し書き換えてやるとうまくいきました。 qiita.com
まず、SimpleAnimationPlay.cs
を開きましょう。DoAddClip
メソッドを探します。
StateInfo newState = m_States.InsertState();
の下に付け加えるように、こんな感じで書いていきます。
private StateInfo DoAddClip(string name, AnimationClip clip) { //Start new State StateInfo newState = m_States.InsertState(); //LoopしないものはWrapModeにOnceを明示的に指定 if (!clip.isLooping && clip.wrapMode == WrapMode.Default) { clip.wrapMode = WrapMode.Once; } newState.Initialize(name, clip, clip.wrapMode); //Find at which input the state will be connected int index = newState.index; (以下略)
付け加えたのはこのコードだけです。
//LoopしないものはWrapModeにOnceを明示的に指定 if (!clip.isLooping && clip.wrapMode == WrapMode.Default) { clip.wrapMode = WrapMode.Once; }
やってることは単純で、Animation Clipをチェックしてそれがループしてるかを見ています。WarpModeがDefaultかもチェックしてますが、これはなくてもよかったかも?
ループしないクリップってことは、つまり1回再生したら終わりですよね。だから、明示的にclip.wrapMode = WrapMode.Once;
を指定してあげます。
WrapModeがOnceならばisPlayingが働くようなので、こうすることでAnimationの終了をスクリプト側で取得することができるようになりました。
さぁ、めんどくさいAnimatorとはおさらばして、SimpleAnimationでUnityちゃんを動かそう!!!!