54
67

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2019-06-11

はじめに

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

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

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

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

今回つくるもの

歩行アニメーションとキーボードでキャラクターの操作

準備するもの

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

RPGツクールの歩行素材を参考にオリジナルキャラのドットを作りました
よくみるパラパラアニメをするための絵を一つの画像ファイル(透過png)にまとめたものです
ドット絵作成は FireAlpaca つかいました。フリーなのにできる子です。
スクリーンショット 2019-06-02 18.43.53.png

作業詳細

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

画像を読み込みと分割

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

画像の設定をする

登録した画像を選択すると右のinspectorタブに画像の詳細設定が表示される
imageload1.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 圧縮形式の指定。サイズはそんなに大きくないのでとりあえず圧縮しない。 テクスチャについて

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

Sprite
キャラクター、アイテム、発射物や他の 2D ゲーム要素として使用される 2D グラフィックスオブジェクト

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

画像を分割する

上記の設定を行ったら、同画面にあるSprite Editorを開く
spriteeditor.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内の画像の右についてる矢印を押すと、下のように分割した状態で展開される

imagesprite.png

Animation Clip ファイルの作成

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

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

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

objectanimat.png

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

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

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

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

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

前1, 前2, 前3, 前2

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

そして以下のように作れたら1方向のアニメーション作成は完了です。
image.png

上の再生ボタンを押すとアニメーションが確認できます
テンション上がってきますね(gifの速度は若干遅めです)
qiita.gif

左上のファイル名をクリックすると
下のようにプルダウンメニューが表示されるので、Create New Clipを選択して
別方向のアニメーションファイルを作成し、前後左右のアニメーションを上の手順を繰り返して作成していきます。
image.png

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

Animator Controllerの作成

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

Blender Treeの作成

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

アニメーション作成時にアニメーションファイルと一緒に作成されたであろう下のアイコンのファイルをダブルクリックします。
image.png

画面真ん中に下のような Entryから先程作ったAnimationファイル名に矢印が生えたもの等が散らかってる状態になっている(散らかってないときもある)
state.png
とりあえず無視して 右クリック -> Create State -> From New Blend Treeを選択して、
作成されたブロックをもう一度右クリックして Set as Layer Default Stateを選択します。
すると、Entryから生えている線が作ったブロックに向きます。

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

Parametersにパラメータの追加

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

Blender Treeの設定

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

真ん中に表示されているブロックをクリックすると右の`inspector`に 下のような表示がされるのでそれぞれ設定を変更します。
項目 説明
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

これらが終わると下のような状態になると思います
blendtree.png

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

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

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

スクリプトの作成とオブジェクトの操作

最後にキャラクターを動かすためのスクリプトを書きましょう。

Rigidbody 2Dをセットする

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

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

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

Rigidbody 2D - Unity マニュアル

スクリプトファイルを作成

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

Visual Studio Tools for Unity の使用を開始する - Visual Studio | Microsoft Docs

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

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

キー操作でオブジェクトを動かすスクリプト

スクリプトファイルを作成でつくったファイルにコードを足していきます。
とりあえずファイルはMoveControllerとつけます

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

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

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,yの入力値を得る
        // それぞれ+や-の値と入力の関連付けは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にセットしています

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

image.png

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

image.png

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

out.gif

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

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

サンプルコードをみる
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;
    }
}

長いので、必要あれば展開してください!
とりあえず最低限それっぽく動くコードです。コメントを一応書いていますが、コピって動かして後で理解でも良いと思います。
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

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

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

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

次回以降

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

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

参考

54
67
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
67

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?