Unity 3Dでアニメーションを考慮したジャンプ その1（単アニメーション）


# はじめに

[Unity 3DでUpdateとFixedUpdate間のタイミングを考慮したジャンプ（基礎） - Qiita](https://qiita.com/mkgask/items/6d04d0be13cc0b14d4fb) の続きです。

上記記事で作成したジャンプの基礎処理をベースに、ジャンプアニメーションを付けていきます。



# 想定環境

- Windows 10
- Unity 2018.2.9f1
- プレイヤーキャラクターに [Unity Technologies Japanオリジナルキャラクター Unityちゃん](http://unity-chan.com/) を利用



# ジャンプにアニメーションを追加

[前回記事](https://qiita.com/mkgask/items/6d04d0be13cc0b14d4fb) で作った基礎的なジャンプ処理に、まずはアニメーション一個をそのまま追加してみます。

ユニティちゃんのアセットには、UnityChan/Animations/unitychan_JUMP00 の中の JUMP00 にジャンプアニメーションも入っているので、これを使わせていただきます。
![clipboard01](https://user-images.githubusercontent.com/8291395/45929182-ff086d80-bf88-11e8-84ef-cbb678ee85a4.jpg)
`Animator` の説明をしてから使いますので、今は場所の確認だけです。



## Animation Controller と Animator と Animation Clip

Unityでアニメーションを行うには、モーションの再生/停止等を管理する `Animation Controller` と、Animation ControllerとGameObjectとの橋渡しとなる `Animator` と、実際のアニメーションのモーションひとつ分となる `Animation Clip` の3つの要素が必要です。

まず `Animator` は、`GameObject` に `Component` としてアタッチ出来るので、Add Component から選択してアタッチします。
![clipboard02](https://user-images.githubusercontent.com/8291395/45929193-1ba4a580-bf89-11e8-9adc-3291ed49085f.jpg)
![clipboard03](https://user-images.githubusercontent.com/8291395/45929198-2a8b5800-bf89-11e8-9e96-d8f223c2baf1.jpg)
`Animator` のプロパティに `Controller` を設定する部分がありますので、ここに `Animation Controller` を設定します。

UnityChan/Animators の中にサンプルのAnimation Controllerがいくつか入っているのですが、今回使いたい用途に合うものがありませんので、新しく作ってしまいます。

Assets/Animators ディレクトリを作成し、その中に右クリックメニュー -> Create -> Animator Controller でAnimator Controllerを新規作成します。
![clipboard04](https://user-images.githubusercontent.com/8291395/45929208-3ecf5500-bf89-11e8-8e21-2f5dfc8a2a01.jpg)
名前は JumpAnimator としましたが、ここは自分がわかれば何でも大丈夫です。
![clipboard05](https://user-images.githubusercontent.com/8291395/45929210-4c84da80-bf89-11e8-819e-7cd482a9bc34.jpg)
作った JumpAnimator をAnimatorにアタッチします。
![clipboard06](https://user-images.githubusercontent.com/8291395/45929211-59093300-bf89-11e8-853a-71d0748725ee.jpg)
アタッチした Animator Controller は、Animator Windowで設定を行う必要があります。

Animator Windowが表示されていない方は、上部メニューの Window -> Animation -> Animator から表示できます。
![clipboard07](https://user-images.githubusercontent.com/8291395/45929220-68887c00-bf89-11e8-8588-2f903c7a350c.jpg)
Animator Windowを表示して、JumpAnimator を選択すると、デフォルトの設定が表示されます。
![clipboard08](https://user-images.githubusercontent.com/8291395/45929225-7807c500-bf89-11e8-9b10-1bf417fc6d33.jpg)
このままでは動かないので、ジャンプ入力がない時（Idle状態）と、あった時（Jump状態）のステートを追加します。
ステートを追加したら、Inspectorで名前を付けて整理しやすくします。
![clipboard09](https://user-images.githubusercontent.com/8291395/45929228-7dfda600-bf89-11e8-9664-a16ddd0ab09e.jpg)
![clipboard10](https://user-images.githubusercontent.com/8291395/45929238-b7ceac80-bf89-11e8-9192-2141885b49e1.jpg)
Jumpステートを選択すると、InspectorにMotionの欄があります。
さきほど場所を確認したユニティちゃんのジャンプアニメーションをここにアタッチします。
![clipboard18](https://user-images.githubusercontent.com/8291395/45929247-d5037b00-bf89-11e8-8207-05d09c2c8250.jpg)
また、Idleのほうも UnityChan/Animations/unitychan_WAIT00 に WAIT00 があるので、これを設定します。
![clipboard19](https://user-images.githubusercontent.com/8291395/45929248-da60c580-bf89-11e8-89c3-6c6599f8701b.jpg)
ステートは、Entryから始まってExitで終わるのが基本ですが、今回はゲーム再生中はずっと入力を受け付けてジャンプアニメーションが起こって欲しいので、Exitは使用しません。

先に作ったIdleにEntryからトランジションが接続されていると思いますが、これがステートの変遷を表します。
![clipboard10](https://user-images.githubusercontent.com/8291395/45929238-b7ceac80-bf89-11e8-9192-2141885b49e1.jpg)
Idleを右クリックして Make Transition を選択、矢印が引っ張れるようになるので、Jumpを選択して接続します。
Jumpが終わったらIdleに帰ってきて欲しいので、逆方向にも同じように接続します。
![clipboard11](https://user-images.githubusercontent.com/8291395/45929258-04b28300-bf8a-11e8-919a-661708e90ae4.jpg)
接続完了ですが、これだと無条件で遷移することになってしまうので、遷移するための条件付けを行います。

Animator Windowの左側をParametersタブを表示して、＋マークをクリック、Boolを選択します。
![clipboard12](https://user-images.githubusercontent.com/8291395/45929266-2d3a7d00-bf8a-11e8-983a-e23b3a5a086d.jpg)
Float、Intはそれぞれ数値が一致したときや不一致の時、上回った時、下回った時なんかに状態が遷移するように出来て、BoolはTrueになった時またはFalseになった時に状態を遷移出来るようにします。
Triggerはちょっと毛色が違って、一瞬だけONになりすぐにOFFになる性質があります。

今回はBoolを2つ追加し、それぞれIdle、Jumpと名付けます。

それからトランジションの矢印を選択して、InspectorのConditionsの＋マークを押します。
![clipboard14](https://user-images.githubusercontent.com/8291395/45929269-45aa9780-bf8a-11e8-80a5-d924a2dc7a18.jpg)
![clipboard15](https://user-images.githubusercontent.com/8291395/45929313-cec1ce80-bf8a-11e8-83ae-6704538a2561.jpg)
Parametersのリストの先頭のアイテムが自動で選択されていますが、これを、
Idleの状態の時にJumpのtrueが来たらJump状態に、Jump状態の時にIdleのtrueが来たらIdle状態に戻る、としたいので、IdleからJumpへの矢印は `Jump, true` を、JumpからIdleへの矢印は `Idle, true` を、それぞれ選択します。
![clipboard16](https://user-images.githubusercontent.com/8291395/45929315-d6817300-bf8a-11e8-94b1-3340849851b5.jpg)
![clipboard17](https://user-images.githubusercontent.com/8291395/45929317-dd0fea80-bf8a-11e8-9a4e-79a6bff79637.jpg)
これで、Animation Controllerの設定は一通り終わりました。
あとはコードからAnimator.SetBoolを発行すれば、それぞれの条件にあった状態遷移が行われます。



## コード



```cs:PlayerController.cs
```
```cs
//（前略）

    ///<summery>
    ///    ジャンプ処理に使用するRigidbody
    ///</summery>
    private Rigidbody _rigidBody;

    ///<summery>
    ///    ジャンプアニメーションを担当するAnimator
    ///</summery>
    private Animator _animator;    // <- 追加


    ///<summery>
    ///    Start()
    ///</summery>
    private void Start()
    {
        _rigidBody = GetComponent<Rigidbody>();
        _animator = GetComponent<Animator>();    // <- 追加
    }

    ///<summery>
    ///    Update()
    ///</summery>
    private void Update()
    {
        // 接地判定して着地していたら着地処理
        CheckGroundDistance(() => {
            _jumpInput = false;
            _isJumping = false;
            _animator.SetBool("Idle", true);    // <- 追加
            _animator.SetBool("Jump", false);    // <- 追加
        });

        // 既にジャンプ入力が行われていたら、ジャンプ入力チェックを飛ばす
        if (_jumpInput || JumpInput()) _jumpInput = true;
    }

    ///<summery>
    ///    FixedUpdate()
    ///</summery>
    private void FixedUpdate()
    {
        // ジャンプ判定
        if (_jumpInput && !_isJumping) {
            // ジャンプ処理
            _isJumping = true;
            DoJump();
            _animator.SetBool("Jump", true);    // <- 追加
            _animator.SetBool("Idle", false);    // <- 追加
        }
    }

//（後略）
```

略した部分は[前回記事](https://qiita.com/mkgask/items/6d04d0be13cc0b14d4fb)をご確認ください。
追加したのは3箇所のみです。

- Animatorコンポーネントの取得
- ジャンプ処理が行われたらジャンプモーション開始（Animator.SetBool("Jump", true)）
- 着地したらアイドルモーションに戻る（Animator.SetBool("Idle", true)）

次のモーションへ移る際に、今のモーションに入ってきた時のフラグをOFFしておかないと、自動では片付けてくれません。
これを忘れると遷移条件が次々全部ONになって、状態を遷移しまくってしまい各状態のアニメーションが成立しなくなってしまいます。

`Animator.parameters()` で遷移条件に使うParametersのリストが取得できるので、必要な設定だけを行い他の条件はデフォルトに戻すようなメソッドを用意するのもアリかもしれません。



## 実行
![20](https://user-images.githubusercontent.com/8291395/45929325-f87af580-bf8a-11e8-8521-fd69659fb017.gif)
ジャンプアニメーションが起こるようになりました。

しかし、細かく見てみると、飛び上がってからジャンプアニメーションが開始されており、モーション開始とジャンプ開始のタイミングがズレています。

それに、定時間でアニメーションが終了してしまうため、ジャンプの強さを変えると着地のタイミングもズレているのが分かります。
![21](https://user-images.githubusercontent.com/8291395/45929329-02045d80-bf8b-11e8-94d9-6b104b5c554b.gif)
簡単なジャンプアニメーションならこれでも十分なのですが、次回、ジャンプアニメーションのタイミングの調整と溜めて大ジャンプの記事が書ければと思います。

長くなってしまったので本記事はこれまで。