Skip to main content

アニメーションを追加

Timmy がずっと「T-ポース」でなかなか面白くないので、走るときとジャンプの時もアニメーションを再生しましょう。このため「アニメーションコントローラー」(Animation Controller)および「アニメーター」(Animator) コンポーネントを使用し、条件でアニメーションを切り替えて、主人公を適切に動かしましょう。

シーン設定

動くのは Timmy なので、Timmy (Playerではなく) に Animator コンポーネントを追加してください。

image.png

ここで、「Controller」と「Avatar」を設定しないといけない。

Controller とは

Controller(アニメーションコントローラー)はアニメーションの遷移を管理するところである。以下のような画面でアニメーションを挿入し、「Transition」(遷移)で、アニメーションの切り替えが管理できるものである。

image.png

Timmy のコントローラーがまだできていないので、新しいのを作りましょう。Characters / Timmy / Animations の中で新しい「アニメーション ➡ アニメーションコントローラー」を作成し、「TimmyController」の名前にしてください:

image.png

これを「Animator」コントローラーの「Controller」に設定ください。

Avatar とは

Avatar は、3Dモデルの「骸骨」(スケルトン)である。アバターの「骨」(ボーン)を動かすことにより、モデルが正しく変形する。この情報3Dモデルのデザイナーさんが作るべき。開発者はモデルからデータを抽出するだけ。プロジェクトフォルダでTimmyのモデルを選択しましょう(Characters / Timmy / Models / Timmy)

image.png

ここで「Rig」を確認しましょう。このモデルからアバターを作るので、いくつかの設定を変えないといけない。

  • Animation Type:Generic から Humanoid に更新(一般 → 人間っぽい)
  • Avatar Definition:No Avatar から Create From This Model (アバターなし → このモデルから作成)

image.png

その後は「Apply」ボタンを押してください。大きく変わらないが、ボーンを確認ができる。「Configure」ボタンを押すと

image.png

アバターが抽出されたことが確認ができる。アバターができたので、Timmy の Animator コンポーネントの Avatar を設定しましょう 

image.png

アニメーションファイルのアバターも!

これで、キャラクターの骸骨(アバター)を設定できたが、次に、このモデルが使うアニメーションにもアバターの設定が必要。Characters / Timmy / Animation の中にいろんなファイルが入っているが、TimmyController 以外はすべてアニメーションである:

image.png

このアニメーションは「Timmyのアニメーションだよ!」を指定するために、このファイルに作ったばかりのアバターを指定しなければならない。すべてのアニメーションを選択し、また「Rig」を確認しましょう。ここでは

  • Animation Type:Generic から Humanoid に更新(一般 → 人間っぽい)
  • Avatar Definition:No Avatar から Copy From Other Avatar(アバターなし → 他のアバターからコピーする)
  • Source:TimmyAvatar を選択し、同じアバターを利用

image.png

最後に、「Apply」を押してください。これで、アニメーションファイルと Timmy の3Dモデルの紐づけができる。

アニメーション

待機/アイドル(Idle)

まず、キャラクターが何もしてないときのアイドルアニメーションを作成しましょう。コントローラーの中に「idle」のアニメーションをドラッグドロップで追加

image.png

今回のアニメーションが Mixamo からダウンロードしたので、アニメーションの名前は「mixamo_com」になってしまう。これでわかりにくいので、Inspector で「Idle」という名前にしましょう。これがデフォルトアニメーションになるので、このままで実行してみましょう:

image.png

「T-ポーズ」ではなく、待機アニメーションになった!ただし、少し長めに待つと、アニメーションが止まってしまいます。なぜなら、デフォルトとしてアニメーションがループしないから。プロジェクトで「idle」を選択し「Animation」の設定を Inspector で更新しましょう:

image.png

ここで「Loop Time」のチェックが外しているため、アニメーションがループはしない。チェックを入れ、もう一度確認しましょう。

走る(Running)

つぎに、走るアニメーションを追加しましょう。プロジェクトから「running」をアニメーションコントローラーに追加し、アニメーション名を「Running」にしましょう。このアニメーションもループできるように設定を変えてくださいね

image.png

次、遷移(Transition)を作らないといけない。Idle → Running と Running → Idle それぞれの遷移を「右クリック」→「Make Transition」で作成しましょう:

image.png

これで実行すると、待機→走る→待機 の繰り返しが続ける。走り始めると、Idle → Running の遷移し、止まったら Running → Idle に戻るようにしましょう。そのため、「今走っているのか?」のパラメータを追加しましょう。アニメーターコントローラーで Bool 型の IsRunning のパラメータを追加してください:

image.png

これが遷移するかしないかのパラメータにしましょう。Idle → Running で IsRunning は true だったら、遷移する。そして、Running → Idle には、 IsRunning が false の時遷移しましょう:

image.png

image.png

これで実行し、アニメーションコントローラーのパラメータ IsRunning を変えながら、挙動を確認してみてください。

問題:すぐ遷移しない

これで問題が明らかになった。 IsRunning を変えても、すぐ遷移しない。アニメーションが終わってから遷移するので、反応が遅い。これを直すには、「アニメーション終了まで待たず、すぐ遷移しろ!」の設定すれば良いでしょう。遷移での「Has Exit Time」(終了時間あり)のチェックを外してください。

スクリプト

最後は、C#からアニメーションコントローラーのパラメターを設定し、走っている間には IsRunning を true にしましょう。PlayerMove スクリプト移動の処理しているので、ここで簡単にパラメターを設定ができる。まず、Animator の参照が必要で:

// プレーヤーの移動を処理する
public class PlayerMove : MonoBehaviour
{
    // Unity で Animator の参照を設定
    [SerializeField]
    private Animator animator;

    // (省略)
}

そして、Update を少し更新するだけ:

private void Update()
{
    // 何も入力がない前提で、速度をゼロにする
    velocity = Vector3.zero;

    // Heightオブジェクトの向きを従って移動
    velocity += cameraYRot.right * Input.GetAxis("Horizontal");
    velocity += cameraYRot.forward * Input.GetAxis("Vertical");
    
    // 入力あれば、速度ベクトルはゼロではないはず
    bool isRunning = velocity != Vector3.zero;
    if (isRunning)
    {
        // 単位ベクトルにする
        velocity.Normalize();
        
        // 前方の向きを変える
        transform.forward = velocity;
        
        // 速度を乗算する
        velocity *= speed;
    }

    // アニメーターのパラメターを設定
    animator.SetBool("IsRunning", isRunning);
}

Unity で PlayerMove の Animator 参照を設定し、走ってみましょう!

ジャンプ(Jump)

ジャンプは走るよりも多少複雑である。ジャンプの高さにより、アニメションの長さが変わるので、3つのパーツに分割されている

  • ジャンプ開始(jumping up):ジャンプが始まるときに再生
  • 空中(falling idle):高いところからジャンプすると、ずっとこのアニメーションを再生する
  • 着陸:2種類がある
    • 移動中の着陸:着地→転がって→立つ(falling to roll)
    • 停止中の着陸:着地→立つ(hard landing)

これで遷移が難しくなるが、少し考えて遷移を整理しましょう。赤は遷移のパラメター条件(Condition)

  • 待機、または走行からジャンプキーを押すと、jumping upを再生(トリガー使用)
    • Idle → [JumpTrigger] → JumpUp
    • Running → [JumpTrigger] → JumpUp

  • 現状が関係なく、空中だったら falling idle を再生
    • Any State → [IsAir == true] → Falling

  • 空中ではなくったら、かつ、走っていれば、転がる
    • Falling → [isAir == false] [isRunning == true] → Roll → Running

  • 空中ではなくったら、かつ、止まっていれば、hard landing を再生
    • Falling → [isAir == false] [isRunning == false] → Land → Idle

まず、遷移図を作りましょう。アニメションを追加し、わかりやすい名前にしてください:

※falling idle は ループするので、アニメションの設定を忘れずに

image.png

スクリプト

遷移とその条件ができたら、次、スクリプトでパラメターの設定が必要。ジャンプに関する処理が「PlayerJump」の中にあるので、そのスクリプトを編集しましょう。まず、アニメーターの参照から:

using UnityEngine;

// ジャンプ機能を追加するスクリプト
public class PlayerJump : MonoBehaviour
{
    // Unity で Animator の参照を設定
    [SerializeField]
    private Animator animator;

    // (省略)
}

そして、Update で:

void Update()
{
    // 着地なのか?
    bool onFloor = IsOnFloor();
    
    // ジャンプしたか?
    if (onFloor && Input.GetButtonDown("Jump"))
    {
        animator.SetTrigger("JumpTrigger");
        doJump = true;
    }
    
    // アニメーターのパラメター設定
    animator.SetBool("IsAir", !onFloor);
}

遷移の改善、微調整

これで各アニメションの再選、遷移の実現ができたが、違和感のときもある。転がるのが長いし、立つアニメションも長いので、着地のすぐ後にまた走り始めると、変に見える場合もある。以下の微調整で少し見かけが改善できる。

転がるアニメーションを速くする

転がるのが長いので、スピードアップしましょう。アニメーターコントローラーで「Roll」のアニメーションを選択し、Inspector で Speed を調整してみましょう。1.5倍~2.5倍の間にお好みの数値で調整し、確かめてください。

image.png

着陸したと、また移動中かどうかを確認

以下のように遷移を調整し、Land か Roll の再生中に、走行の状況が変わったら、すぐ適切なアニメーションへ遷移する。

image.png

ジャンプポーズでフリーズする

image.png

 ジャンプ中に、連続にジャンプすれば、JumpTrigger また発動し、結果として、JumpUp のアニメーションへ遷移し、そこで止まってしまいます。

 

 JumpUpジャンプができない場合は、JumpTrigger のアニメーションし始めれるのは、「Idle」か「Running」の時だけなので、C# 側でこの状況(State)を確認しなければならない。のパラメータをリセットすれば、この問題を解決ができる。

 

 以下のように、PlayerJump のスクリプトを修正すれば、直る:

void Update()
{
    // 着地なのか?
    bool onFloor = IsOnFloor();

    // ジャンプしたか?
    if (onFloor && Input.GetButtonDown("Jump"))
    {
        // アニメーターの現状を取得
        var state = animator.GetCurrentAnimatorStateInfo(0);
        
        // Running か Idle だけの時に "アニメータの"JumpTrigger" を設定
        if (state.IsName("Running") || state.IsName("Idle"))パラメータを設定
        animator.SetTrigger("JumpTrigger");
        doJump = true;
    }
    // そうじゃない場合は、リセットする
    else
        animator.ResetTrigger("JumpTrigger");

    
    // アニメーターのパラメター設定
    animator.SetBool("IsAir", !onFloor);
}