初心者がUnityでなんかしちゃうぞBlog

Unity初心者は、ゲーム開発の夢を見るか?

SimpleAnimationで常にtrueにならず、ちゃんとisPlayingを取得できるようにする方法

間が空きすぎてると話題のBlogですが、どうぞよろしくお願いします。 仕事でもUnityを扱ってるので少しずつできることが増えてきているんです。ほんとですよ!?

さて「SimpleAnimation」という超絶便利なものを使いはじめたのですが、isPlayingが常にtrueになってしまう という 致命的な状況に陥りました。 これに対しての解決方法がわかった気がするので備考録として書いておきます。

SimpleAnimationの基本的なことをまずはご紹介していきますね。

SimpleAnimation

さて、今回は3DのプロジェクトについてキャラクターをAnimationさせたいと思うことは、みなさんよくあるかと思います。 基本的なやり方としてはAnimatorを使って分かりづらい遷移をゴリゴリ書いていくのですが、見づらいです。 それをAnimationを直接呼び出せるセクシーなコンポーネントがあります。それが、SimpleAnimation というものなのです。 github.com

使い方

SimpleAnimationのフォルダをガッツリもらってきたら、自分のプロジェクトに打ち込むだけ。It's Easy! 読み込んだら、さっそくAnimationを適用したいキャラクターにぶちこんであげましょう!

f:id:yuu9048:20190324171132p:plain

そしたらインスペクターをチェックしてみましょう。

Animator部分は、Controllerだけ外しておきます。Animationの管理はSimpleAnimation側でやるためです。

f:id:yuu9048:20190324171718p:plain

次にSimpleAnimationをチェックします。

f:id:yuu9048:20190324171423p:plain

まずは、初期状態(idle)のアニメーションクリップを設定してあげましょう。

f:id:yuu9048:20190324171501p:plain

ここにクリップをD&Dしてあげると・・・。

f:id:yuu9048:20190324171853p:plain

はい、これでDefaultのモーションが設定できました。実行して確認してみましょう!

f:id:yuu9048:20190324172138g:plain

This is kawaii.

複数のAnimationの設定

Default以外にも登録していきたいときはAnimationsの数値を変えてクリップを登録していきます。 デフォルト以外は名前も変えられるので管理しやすいような名前をつけてクリップを設定していきましょう。

f:id:yuu9048:20190324172840p:plain

スクリプト側からこのAnimationの再生を切り替えることができます。 再生方法はいろいろあるのですがよく使うのが CrossFade("Animation名", 秒数); だと思います。 「Hello」というAnimationを設定し、ざっくりとテスト用スクリプトを書いてみました。ちょっと横着をしていますが、やってることはSimpleAnimationコンポーネントの中のCrossFadeを呼び出してるだけです

    void Update()
    {
        if (Input.GetMouseButtonDown(0)) {
            GameObject.Find("UnitySan").GetComponent<SimpleAnimation>().CrossFade("Hello", 0.2f);
        }


    }

とりあえずこれをユニティちゃんにアタッチして、クリックしてみると!!!!

f:id:yuu9048:20190324175112g:plain

クリックされたら挨拶をするKawaii Girlです。 Animatorの遷移条件とかを書く必要がないのでスクリプト側からガンガンかいていけて便利かつシンプルですね。

SimpleAnimationでisPlayingを取得したい

さて、本題に入りましょう。Animationが再生しているのか、終わっているのかを取得するためのisPlayingですがSimpleAnimationの仕様?としてうまく動作しないはずです。 その理由については下記サイトを参考にしました。

qiita.com

原因

何が起きているのかというと、割と単純で「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ちゃんを動かそう!!!!