UnityでRPGを作るpart1 歩行アニメーションと操作

# はじめに
お仕事はWeb系のエンジニアでReactやらSpringやらなんかあれば触るんですが
趣味のゲームを作りたい欲からUnityを触り始めてみました。

直近の目標は昔ながらのDQっぽいシステムのRPGを作るお勉強なので学んだことをまとめる
そう、備忘録です :muscle:

- とりあえずUnityをPCに入れた人
- プログラムを少し触ったことある人

を前提に書きます。
また、環境はMacなのでWinの人はいい感じに読み解いていただけるとありがたいです:pray: 
C#使いますが、Unity以外のC#の書き方云々とかは基本的に説明書きません

### 今回つくるもの
歩行アニメーションとキーボードでキャラクターの操作

### 準備するもの

- Unity
    - これがないと始まらない
- Visual Studio
    - スクリプトの編集のおとも。入力候補が表示されるのでUnityのAPIを雰囲気理解でも助かる
- キャラクター歩行素材(透過png)を用意
    - ここでは自分で用意しちゃいましたが、勉強だけの使用なら素材はおまかせ
    - 前後左右にそれぞれ3パターン の計12パターンをおさめた１枚の画像
    - RPGツクールの歩行グラフィックと調べてみるとたくさんでてきます

RPGツクールの歩行素材を参考にオリジナルキャラのドットを作りました
よくみるパラパラアニメをするための絵を一つの画像ファイル(透過png)にまとめたものです
ドット絵作成は [FireAlpaca](https://firealpaca.com/ja/) つかいました。フリーなのにできる子です。
<img width="239" alt="スクリーンショット 2019-06-02 18.43.53.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/f38e4707-ab3a-d64d-f878-538772c9e778.png">

# 作業詳細
Unityを立ち上げ、プロジェクトを作成してLet`s Try!

## 画像を読み込みと分割
用意した画像を`Project`の`Assets`にドラッグ&ドロップするとプロジェクトに画像が登録される。
ここから、前後左右が描かれている歩行アニメーションの画像を分割してUnity内で別々に扱えるようにしていく。
アニメーションを作るための事前準備。

### 画像の設定をする

登録した画像を選択すると右の`inspector`タブに画像の詳細設定が表示される
<img width="650" alt="imageload1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/f917f5e2-4253-615c-785e-957792727402.png">

ここでは初期値から以下の設定を変更している

|項目|設定する値|項目の説明|
|:---:|:---:|:---:|
|Texture Type|Sprite(2D and UI)|このテクスチャをどう利用するかの設定。今回は2Dゲーム用のSpriteとして使う|
|Sprite Mode|Multiple|一つの画像を複数のSpriteとして設定する|
|Mesh Type|Full Rect|Tight指定をするとアルファの余計な部分をクロップされるのでとりあえずFull Rect|
|Pixels Per Unit|1|ドット絵をベースにしているので1指定。扱う絵によっていい感じに指定する値。ユニットについては下記参考|
|Filter Mode|Pointer (no filter)|ドット絵をはっきり見せるため。Filterを指定するとaliasがかかる|
|Compression|None|圧縮形式の指定。サイズはそんなに大きくないのでとりあえず圧縮しない。 [テクスチャについて](https://docs.unity3d.com/ja/current/Manual/class-TextureImporter.html)|

下3つはドットをキレイに見せるための指定なのでなくてもいいけどあると良い。

> [Sprite](https://docs.unity3d.com/ja/current/ScriptReference/Sprite.html)
> キャラクター、アイテム、発射物や他の 2D ゲーム要素として使用される 2D グラフィックスオブジェクト

> [スケールとユニット](https://unity3d.com/jp/learn/tutorials/projects/creating-believable-visuals/where-start)
> 尺度（スケール）と測定単位（ユニット）は、現実のようなシーンを作る上で非常に重要な役割を果たします。 リアリスティックなビジュアルを目指す作品の場合、一般的には 1 Unity ユニット = 1m（100cm）と想定することが推奨されます。多くの物理システムの単位のサイズがこの想定になっているからです

### 画像を分割する

上記の設定を行ったら、同画面にある`Sprite Editor`を開く
<img width="689" alt="spriteeditor.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/400793ca-12f0-6a40-4dd7-0446b0a36cae.png">

左上の`Slice`を選択して、一番上に表示されている`Type: Automatic`を
`Type: Grid by Cell Count`に変更して、ColumnとRowに分割する値を設定する。

RPGツクールの歩行画像は以下のような形で`Column: 3 Row: 4で配置されているので
今回RPGツクールを参考につくった画像もそのとおりに値を指定する。

```
前1, 前2, 前3
左1, 左2, 左3
右1, 右2, 右3
後1, 後2, 後3
```
で、指定後にSpriteボタンを押して上部のApplyを押すと完了。
Assets内の画像の右についてる矢印を押すと、下のように分割した状態で展開される

<img width="379" alt="imagesprite.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/4a07adbb-80b4-affb-3c4c-59445fb40327.png">

## Animation Clip ファイルの作成
画像を分割したので次はAnimationの作成をしていきます。
ぱらぱらアニメ作成のターンです。ここが動くとだいぶテンションあがってきます。

Assets内にある読み込んだ画像ファイルを左上のHierarchyタブにドラッグ&ドロップをすると
画像の名前でオブジェクトが追加され、画面上に画像のキャラクタ(Spriteで分割した左上の部分)が表示されると思います。

その後、追加されたオブジェクトを選択した状態で
`Window` -> `Animation` -> `Animation`
を選択します

<img width="650" alt="objectanimat.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/4ea49712-ae62-67a5-5618-fc648ae7142a.png">

そうすると別ウインドウに`To begin Animating ...`といった文言と
`Create`ボタンが表示されるので、ボタンを押すとAnimationファイルの新規作成を行います。

左上にファイル名が表示され、その下に `Add Property`といったボタンがあるので押し
`Sprite Renderer` -> `Sprite`を選択します。
プロパティが追加されたら、ファイル名横に表示されている `Samples`を4にします。

RPGツクールのそれぞれの方向の画像(Column)は3つしかありませんが、以下の通りにアニメーションを繰り返します

```
右足前 -> 静止 -> 左足前 -> 静止 -> (繰り返し)
```

そのため、分割した画像を以下の順に読み込ませます。

```
前1, 前2, 前3, 前2
```
こうすることで自然なアニメーションになります
…自然というよりは昔ながらのRPGっぽい歩行になります。

そして以下のように作れたら１方向のアニメーション作成は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/dde0b7ca-413f-1802-a710-3e5d54d05b16.png)

上の再生ボタンを押すとアニメーションが確認できます
テンション上がってきますね（gifの速度は若干遅めです）
![qiita.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/7eb5f2e3-0b0d-dc36-b06a-d6b99c6aed2c.gif)

左上のファイル名をクリックすると
下のようにプルダウンメニューが表示されるので、`Create New Clip`を選択して
別方向のアニメーションファイルを作成し、前後左右のアニメーションを上の手順を繰り返して作成していきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/8d117e2b-065a-0527-77bd-8b77a0f9191f.png)

後々わかりやすいように 右向きアニメーションは `char_right` 前(↑)向きは `char_up`といった感じで向きと名前を揃えておくとコレ以降が楽になります。

## Animator Controllerの作成
次に「上移動のときは上に移動しているアニメーションを再生する」といったコントロールを行うための
**Animator Controller**を作成していきます。

### Blender Treeの作成
「X軸に進むなら右のアニメーションを再生」といった動く方向に対して
適切なアニメーションを表示するといった制御をよしなにやってくれる
**Bleder Tree**というものを利用します。

アニメーション作成時にアニメーションファイルと一緒に作成されたであろう下のアイコンのファイルをダブルクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/c31cf6c2-570c-bb70-5182-1d2be9235750.png)

画面真ん中に下のような `Entry`から先程作ったAnimationファイル名に矢印が生えたもの等が散らかってる状態になっている（散らかってないときもある）
<img width="650" alt="state.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/aab16a30-2307-4505-9801-6cd2268bc0a1.png">
とりあえず無視して `右クリック` -> `Create State` -> `From New Blend Tree`を選択して、
作成されたブロックをもう一度右クリックして `Set as Layer Default State`を選択します。
すると、`Entry`から生えている線が作ったブロックに向きます。

残ったそれ以外の色がついていない四角はとりあえず消しましょう。
今回は利用しません。

### Parametersにパラメータの追加
上記の次にこのAnimator Controllerで扱うパラメータを追加します。
移動ベクトルに応じて変化させたいので `x`と`y`という名前で追加。
型は`Float`を選びます。


### Blender Treeの設定
上でつくったBleder TreeのStateをダブルクリックすると下記のように何も設定されていない
状態のBleder Treeが表示されます。

<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/c3c9bcaa-a43c-4104-f933-3bf62e679888.png">
真ん中に表示されているブロックをクリックすると右の`inspector`に
下のような表示がされるのでそれぞれ設定を変更します。
<img width="350" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/df8f0407-0582-e4dc-be63-c71f24b8711b.png">

|項目|説明|
|---|---|
|Blend Type| 2次元の歩行アニメーションなので2D Simple Directionalを指定|
|Parameters|前項で作成したxとyを設定|
入力したら`Motion`の下にある +マークをクリック -> `Add Motion Field`を押します。
すると、アニメーションファイル一覧を表示したウインドウが表示されるので
先程作成したファイルを選択します。これを全方向分追加します。

追加したファイルの名前の横に `Pos X` `Pos Y`という項目があると思うのでそれぞれ下のように入力してください。
進む方向とアニメーションの向きを揃えた設定をするだけです。

|アニメーションの向き|Pos X|Pos Y|
|---|---|---|
|上|0|1|
|右|1|0|
|下|0|-1|
|左|-1|0|

これらが終わると下のような状態になると思います
<img width="650" alt="blendtree.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/bf54fb9c-e84f-72da-efa5-2e8ca72c5f39.png">

とりあえずこれでAnimator Controllerの設定は完了です。
もうわかってきたかもしれませんが、x軸とy軸の移動に対してそれぞれのアニメーションを切り替える作業をこれがよしなにやってくれるようになります。

ただ、これだけでは実行しても向きも変わらないし位置も変わらないので
最後にやっとスクリプトを書きます。

…むしろここまでスクリプト何もいらないんだからさすがUnity先生
だいぶ昔にDxLibでなんかやろうとしたことが懐かしい(^o^

## スクリプトの作成とオブジェクトの操作
最後にキャラクターを動かすためのスクリプトを書きましょう。

### Rigidbody 2Dをセットする
アニメーション作成時にできた左側のオブジェクトをクリックして、オブジェクトのinspectorを表示すると
一番下に`Add Component`というボタンがあるので、それを押すと下のような項目一覧がでるので
`Rigidbody 2D`を選択します(入力窓に入れると見つけやすいです)

<img width="200"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/255b2e56-70f7-71ed-67ab-eeee2b48fa0b.png">

追加するとこちらのように`Rigidbody 2D`という枠が表示されるので
Body Typeを `Kinematic`にすることで、物理演算が無視されて2Dのうごきっぽくなります。

<img width="650"src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/98e0dbaa-8b68-79cc-46be-3c6eecb846d2.png">

Dynamic指定のままで動かすと、おそらくキャラクタがだんだん画面下へ落ちていくような動きになります。
Rigidbody 2Dはオブジェクトの動きを物理エンジンで制御するためのコンポーネントです。
とりあえず**オブジェクトを操作するのにセットする必要がある**ぐらいの認識でいいと思います。

[Rigidbody 2D - Unity マニュアル](https://docs.unity3d.com/ja/current/Manual/class-Rigidbody2D.html)

### スクリプトファイルを作成
右クリックから `Create` -> `C# Script`を選択してファイルを作成。
`Assets`にC#と書かれたアイコンが作成されると思うので、ダブルクリックをするとVisual Studioが開かれると思います（ちょっと時間かかります）

[Visual Studio Tools for Unity の使用を開始する - Visual Studio | Microsoft Docs](https://docs.microsoft.com/ja-jp/visualstudio/cross-platform/getting-started-with-visual-studio-tools-for-unity?view=vs-2019)

> Unity 2018.1 以降、Visual Studio は Unity の既定の C# スクリプト エディターであり、Unity Download Assistant および Unity Hub インストール ツールに含まれます。

とのことなので導入の手順は飛ばしますが、必要あればリンクを参考にしてみてください。

### キー操作でオブジェクトを動かすスクリプト
スクリプトファイルを作成でつくったファイルにコードを足していきます。
とりあえずファイルは`MoveController`とつけます

一応名前は何でも良いですが、プログラムのファイルやクラスや変数名は
それぞれが何をしているか誰でもわかるようないい名前をつけていきましょう！

visual studioでスクリプトファイルを修正し
動かしたいオブジェクトに対してドラッグ&ドロップで関連付けさせましょう

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/**
 * キャラの座標を変更するController
 */
public class MoveController : MonoBehaviour {
    [SerializeField]
    float SPEED = 1.0f;
    private Rigidbody2D rigidBody;
    private Vector2 inputAxis;

    void Start() {
        // オブジェクトに設定しているRigidbody2Dの参照を取得する
        this.rigidBody = GetComponent<Rigidbody2D>();
    }

    void Update() {
        // x,ｙの入力値を得る
        // それぞれ+や-の値と入力の関連付けはInput Managerで設定されている
        inputAxis.x = Input.GetAxis("Horizontal");
        inputAxis.y = Input.GetAxis("Vertical");
    }

    private void FixedUpdate() {
        // 速度を代入する
        rigidBody.velocity = inputAxis.normalized * SPEED;
    }
}
```
ここでは、入力されたキーを取得して`x`,`y`軸の移動量を計算してセットするのではなく
矢印キーで入力された`Horizontal`, `Vertical`の値を取得して
係数(SPEED)を掛けた値をそのまま速度として`velocity`にセットしています

`Horizontal`や`Vertical`に対して、プラス方向のキー、マイナス方向のキーがどれかといった設定は
`Edit` -> `Project Settings` -> `Input`から見れます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/d877d4dd-3ebf-13d7-8fa0-189f1774fee0.png)

また、上記ではオブジェクトの速度である`velocity`に対して値をいれることで
オブジェクトを操作していますが `Rigidbody#AddPosition`といったメソッドなど、
オブジェクトの位置を変える方法はいくつもあるのでそれぞれの特性を活かして実装していけるとよいかと思います。
今回はとりあえずvelocityに値を設定

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/10033091-61bc-77df-47b8-2a788749d99c.png)

上記のスクリプトとキャラクターのオブジェクトに関連がつけられたら
ウインドウ上部の再生ボタンを押すと実際に入力に対して動くか確認できます。

![out.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/9abd7abf-921a-708e-b88f-54f2e42fc6bf.gif)


キー操作にあわせてオブジェクトが動くようになりました。
最後に前項でつくったAnimator Controllerを組み合わせて、動く方向にあわせて向きが変わるようにしていきます。

### キー操作にあわせアニメーションに状態をわたすスクリプト

<details><summary>サンプルコードをみる</summary><div>

```C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/**
 * キャラの向き状態を変更するController
 */
public class AnimationStateController : MonoBehaviour {
    Animator animator;

    void Start() {
        // 初期化
        // コントローラをセットしたオブジェクトに紐付いている
        // Animatorを取得する
        this.animator = GetComponent<Animator>();
    }

    /**
     * Update は MonoBehaviour が有効の場合に、毎フレーム呼び出されます
     * https://docs.unity3d.com/ja/current/ScriptReference/MonoBehaviour.Update.html
     */
    void Update() {

        if (Input.anyKeyDown) {
            Vector2? action = this.actionKeyDown();
            if (action.HasValue) {
                // キー入力があればAnimatorにstateをセットする
                setStateToAnimator(vector: action.Value);
                return;
            }
        }
        // 入力からVector2インスタンスを作成
        Vector2 vector = new Vector2(
            (int)Input.GetAxis("Horizontal"),
            (int)Input.GetAxis("Vertical"));

        // キー入力が続いている場合は、入力から作成したVector2を渡す
        // キー入力がなければ null
        setStateToAnimator(vector: vector != Vector2.zero? vector : (Vector2?)null);

    }

    /**
     * Animatorに状態をセットする
     *    
     */
    private void setStateToAnimator(Vector2? vector) {
        if (!vector.HasValue) {
            this.animator.speed = 0.0f;
            return;
        }

        Debug.Log(vector.Value);
        this.animator.speed = 1.0f;
        this.animator.SetFloat("x", vector.Value.x);
        this.animator.SetFloat("y", vector.Value.y);

    }

    /**
     * 特定のキーの入力があればキーにあわせたVector2インスタンスを返す
     * なければnullを返す   
     */
    private Vector2? actionKeyDown() {
        if (Input.GetKeyDown(KeyCode.UpArrow)) return Vector2.up;
        if (Input.GetKeyDown(KeyCode.LeftArrow)) return Vector2.left;
        if (Input.GetKeyDown(KeyCode.DownArrow)) return Vector2.down;
        if (Input.GetKeyDown(KeyCode.RightArrow)) return Vector2.right;
        return null;
    }
}

```
</div></details>

長いので、必要あれば展開してください！
とりあえず最低限それっぽく動くコードです。コメントを一応書いていますが、コピって動かして後で理解でも良いと思います。
Unityがメソッド名も`UpperCamelCase`を推奨してるのに `lowerCamelCase`で書いてしまう…癖です :innocent: 

Updateメソッドの流れはざっくり下の通り

1. キーが押された瞬間 `Input.anyKeyDown = true`のときにifの条件に入る
2. `actionKeyDown`メソッドで上下左右のキーが押されていたらVector2を返して、`setStateToAnimator`で状態を反映する
3. キーが押された後 / 押されていないときの値はオブジェクトの位置を動かすときと同様に`GetAxis`で値を取得してvectorを作成する
4. `Vertical` `Horizontal`で何かしら入力されていれば値を渡す。押されていない `Vector.zero`であれば nullを渡す
5. `setStateToAnimator`で値がなければ `animator`のSpeedを0にしてアニメーションをstop。それ以外は渡された値を`animator#SetFloat`でBleder Treeで定義したxとyのパラメータにそれぞれVector2のxとyを渡す。

1で、keyDownの瞬間に方向を変えるようにしているのは
処理を外して確認するとわかるのですが、上の実装では動き始めてから一定の移動量を超えるまで
向きが変わらないため、押した瞬間に向きが変わるように制御しています。

`Input.anyKeyDown`がtrueになるのは
「何もキーが押されてない状態から押された状態になったとき」だけなので
下の完成品を見るとわかるかもですが、移動中に方向を変えたときに`Input.anyKeyDown`がtrueにならないので、

昔ながらのRPGぽくキーを押した瞬間移動方向と向きが変わっていないのがわかります。
コレ以上はこだわりポイントなのでここでは割愛します。

# 完成品

![out.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39229/35d8a956-6406-061d-cd72-709d3cb623a8.gif)

- RPGツクールのような歩行グラフィックがまとまった画像をSplitしてアニメーションさせる
- 十字キー入力でオブジェクトを移動させる
- Blender Treeでアニメーションの方向を制御する

といったことを行いました。
本業もそうですが、やっぱり完成物がこうやって動く瞬間が一番楽しいです。

アニメーション読み込みからBlender Treeの設定までは ノンプログラミングでできそうな感じ？なので
可能な限りシステムとデザイン部分を分離していい感じの作業の進め方も模索していきたい。そんなpart1でした。

# 次回以降
不定期更新の備忘録なのでまた知見がたまったら書きます

- アイテム管理するシステム
- 戦闘システム
- マップとシーン切り替え

# 参考

- [【Unity】ツクール規格の2Dキャラクターの移動を実装する - Yumineko](https://yumineko.com/game-create/unity/tkool-move)