4方向スプライトキャラクターの歩行アニメーションを実装する

ページ更新日 :
ページ作成日 :

検証環境

Windows
  • Windows 11
Unity エディター
  • 2020.3.25f1
入力システムパッケージ
  • 1.2.0

この Tips の前提設定

この Tips の説明の前提として以下の設定を事前に行っています。

参考サイト

歩行グラフィックの用意

まず歩行アニメーションを行うには複数の画像を常に切り替え歩いているように見せることによって実現しています。 そのため移動方向や歩く動作を見せるために必要な数だけ画像を用意する必要があります。

最も簡単な歩くアニメーションを実現するためには以下のような画像を用意するのが一般的です。 このパターンは多くの RPG などでも採用されています。

まず上下4行分の区分けですが歩いたときに向く方向を示しています。上から「下、左、右、上」となっています。

そして左右についてはその方向の歩くモーションとなります。一般的な流れとしては「中、左、中、右、中...」という繰り返しで動く形になります。

今回用意したキャラクターの1セル分のサイズは 32x32px です。それを 3x4 マス分用意しているので実際の画像ファイルの大きさは 96x128px となっています。 ちなみに1キャラクターのサイズの制約はないので 32x48px や 64x64px なども可能です。

※今回用意した画像は筆者が昔に作ったいわまる君です。動作検証としてなら使っても構いません。

プロジェクトの作成と画像の準備

今回作成するサンプルはキャラクターを配置してキーボードのカーソルキーで移動できるものとします。

まずは新規で 2D のプロジェクトを作成します。プロジェクトに用意したキャラクター画像を追加します。

追加した画像を選択し、インスペクターで以下の設定を行います。

項目名 備考
テクスチャタイプ スプライト
スプライトモード 複数
ユニット毎のピクセル数 32 ビューに配置したときのサイズに影響します
メッシュタイプ 完全な矩形
フィルターモード ポイント 必要であれば
圧縮 なし 必要であれば

設定したら下にある「適用する」ボタンをクリックします。

次に Unity で画像を切り替えられるように分割します。インスペクターに「Sprite Editor」ボタンがあるのでクリックします。

スプライトエディターダイアログが表示されるので「スライス」ドロップダウンをクリックし「タイプ」を「Grid By Cell Size」、 ピクセルサイズ XY を 32 (これはキャラクターのサイズによって変えてください) と入力し、「スライス」ボタンをクリックします。

すると指定したサイズで画像が分割されます。分かりにくい場合は Ctrl キーを押すと分割線が表示されます。

分割したら「適用する」ボタンをクリックして閉じます。

プロジェクトにある画像ファイルの丸右ボタンをクリックして展開すると画像が分割されていることを確認できると思います。

アニメーションデータの作成

前項で作成した画像をビューにドロップします。

すると画像が追加されるのではなく保存ダイアログが表示されます。 これはアニメーション設定の保存になりますのでとりあえず「<画像名>Animation.anim」として保存します。

するとプロジェクトに2つのファイルが作成され、ビューには分割された画像が後の画像が配置されます。

ちなみにこの状態でゲームを実行するとキャラクターが勝手にアニメーションされると思います。これは12枚の画像を随時切り替えて表示している状態となります。

ゲームを実行している場合はいったん終了し、アニメーションタブを選択します。 無い場合はメニューから「ウィンドウ -> アニメーション -> アニメーション」を選択します。

ヒエラルキーから作成したオブジェクト (ここでは Iwamaru_0) を選択しておきます。

すでに自動で生成されたアニメーションがありますがいらないので後で削除します。 今回名前を付けた「IwamaruAnimation」というドロップダウンがあるのでクリックし「新しいクリップを作成」を選択します。

すると保存ダイアログが表示されます。下移動のアニメーションを作成するので「IwamaruDown」としておきます。

ヒエラルキーから「Iwamaru_0」を選択し、アニメーションを「IwamaruDown」に変更します。

今回アニメーションを「左、中、右、中」で繰り返すようにするのでサンプル数を 4 にします。 すると右のタイムラインは4分割になります。

プロジェクトから左上の画像である「Iwamaru_0」をアニメーションタイムラインの 0.0 にドロップします。

次に上中の画像である「Iwamaru_1」を 0.1 と 0.3 にドロップします。

最後に右上画像である「Iwamaru_2」を 0.2 にドロップします。

設定が終わったら再生ボタンをクリックしてみましょう。ビューのキャラクターが歩行アニメーションしているのが分かると思います。(今回のサンプル画像は少しわかりにくいですが…)

これと同様の手順で左方向、右方向、上方向のアニメーションも作成します。

アニメーションファイル名 設定画像
IwamaruDown Iwamaru_0, Iwamaru_1, Iwamaru_2, Iwamaru_1
IwamaruLeft Iwamaru_3, Iwamaru_4, Iwamaru_5, Iwamaru_4
IwamaruRight Iwamaru_6, Iwamaru_7, Iwamaru_8, Iwamaru_7
IwamaruUp Iwamaru_9, Iwamaru_10, Iwamaru_11, Iwamaru_10

最終的には以下の図のようになるはずです。

各方向正しくアニメーションすることを確認してください。

アニメーション切り替え設定

次にプロジェクトから「Iwamaru_0.controller」をダブルクリックして開きます。

するとアニメータータブが開き図のような画面が表示されます。 これは先ほど作成したアニメーションが「.controller」ファイルに含まれていることを示します。

何もないところを右クリックして「ステートの作成 -> 新規のフレンドツリーから」を選択します。

新しく「Blend Tree」が作成されるのでこれを右クリックして「レイヤーデフォルトステートとして設定する」を選択します。

すると Entry が Blend Tree を見るようになります。これによりアニメーションが動いたときに最初に動くのが Blend Tree となります。

今後は Blend Tree でアニメーションを設定するので既存のアニメーションはすべて削除します。

左に「パラメーター」タブがあるので選択して + ボタンから「Float」を追加します。

パラメーターが2つになるのでそれぞれ名前を「X」「Y」とします。

Blend Tree をダブルクリックします。

表示された Blend Tree を選択します。

インスペクターからブレンドタイプを「2D Simple Dictional」に変更します。

Parameters を「X」「Y」にします。

Motion の + ボタンから「モーションフィールドを追加」を「4回」選択します。

初期値が違う場合がありますが図のようになるはずです。

追加した4項目の Motion にプロジェクトにある上下左右の .anim を設定していきます。

そして各アニメーションをどの方向を向いたときに動かすかを指定していきます。

方向 X Y
0 -1
0 1
-1 0
1 0

これでアニメーションの設定は終わりです。

最後に、自動で生成されたアニメーションファイルは不要なので削除して問題ありません。

移動制御

移動はキーボードのキーを押して動かすのでスクリプトを作成して制御します。 今回スクリプトはキャラクターにアタッチするので「CharacterMove」としておきます。

スクリプトは以下のようにします。

using UnityEngine;
using UnityEngine.InputSystem;

public class CharacterMove : MonoBehaviour
{
  // あらかじめ Animator コンポーネントを持っておくようにする
  private Animator _animator;

  // 最初のフレーム更新の前に開始が呼び出されます
  void Start()
  {
    // オブジェクトに紐付いている Animator を取得する
    _animator = GetComponent<Animator>();

    // 最初の向き (下) を設定する
    _animator.SetFloat("X", 0);
    _animator.SetFloat("Y", -1);
  }

  /// <summary>一定時間ごとに呼ばれるメソッドです。</summary>
  void FixedUpdate()
  {
    // キーボードの入力方向を取得
    var move = GetMove();

    if (move != Vector2.zero)
    {
      // 入力されている場合はアニメーターに方向を設定
      _animator.SetFloat("X", move.x);
      _animator.SetFloat("Y", move.y);

      // 入力した方向に移動
      transform.Translate(move * 0.2f);
    }
  }

  /// <summary>キーボード入力による移動方向を取得します。</summary>
  /// <returns>キーボード入力による移動方向。</returns>
  private Vector2 GetMove()
  {
    Vector2 move = Vector2.zero;
    if (Keyboard.current.upArrowKey.isPressed)
    {
      move += new Vector2(0, 1);
    }
    if (Keyboard.current.downArrowKey.isPressed)
    {
      move += new Vector2(0, -1);
    }
    if (Keyboard.current.leftArrowKey.isPressed)
    {
      move += new Vector2(-1, 0);
    }
    if (Keyboard.current.rightArrowKey.isPressed)
    {
      move += new Vector2(1, 0);
    }

    // 入力した値がある場合は正規化して返す
    return move == Vector2.zero ? move : move.normalized;
  }
}

以下各箇所の説明です。

// あらかじめ Animator コンポーネントを持っておくようにする
private Animator _animator;

// 最初のフレーム更新の前に開始が呼び出されます
void Start()
{
  // オブジェクトに紐付いている Animator を取得する
  _animator = GetComponent<Animator>();

  // 最初の向き (下) を設定する
  _animator.SetFloat("X", 0);
  _animator.SetFloat("Y", -1);
}

まず Start メソッドで Animator コンポーネントを取得します。これは Update で使用するのであらかじめ持っておきます。

Animator.SetFloat メソッドは指定したパラメータ名に対して値をセットすることができます。 アニメーションの設定では X, Y の値によってどのアニメーションを使用するかを設定をしたので、 X, Y のパラメータに方向を設定すればその方向を向くアニメーションが実行されるようになります。 初期状態では下を向かせたいので (X: 0, Y: -1) を指定しています。 ちなみにパラメータ名の大文字小文字は区別されるので注意してください。

/// <summary>一定時間ごとに呼ばれるメソッドです。</summary>
void FixedUpdate()
{
  // キーボードの入力方向を取得
  var move = GetMove();

  if (move != Vector2.zero)
  {
    // 入力されている場合はアニメーターに方向を設定
    _animator.SetFloat("X", move.x);
    _animator.SetFloat("Y", move.y);

    // 入力した方向に移動
    transform.Translate(move * 0.2f);
  }
}

FixedUpdate メソッドでは定期的にキーボードの入力状態をチェックして入力があったら処理をするようにしています。

GetMove メソッドはキーボードの入力に合わせて方向を返すようにしています。 処理内容はキーボードの入力 Tips で説明しているものをベースにしているので割愛します。

キーボードの入力があったら Animator.SetFloat メソッドに方向をセットします。これで移動した方向のアニメーションが有効になります。 後は transform.Translate メソッドでオブジェクトを移動させています。

スクリプトを作成したらキャラクターオブジェクトにアタッチします。

実行

これで全ての工程が完了です。ゲームを実行してキーボードのカーソルキーを押して移動してみてください。 キャラクターが押した方向に移動し、グラフィックの向きが向いた方向に変化しつつ歩行アニメーションが動いていれば完了です。