Unity 6でClimbCloudを作る② ― パラパラ漫画のアニメーションと、ゴール・シーンの切り替え(PC版)

広告

ClimbCloudの2回目です。前回は、Rigidbody2DとCollider2Dで物理を付けて、猫が雲の上を歩き、クリックでジャンプするところまで作りました。今回はゲームとして完成させます。

Unity 6でClimbCloudを作る① ― Rigidbody2Dで歩いて、クリックでジャンプする(PC版)

回内容
①(前回)Rigidbody2DとCollider2Dで物理を付ける/AddForceで右へ歩かせる/クリックでジャンプする
②(今回)歩く・ジャンプのアニメーション/旗に着いたらゴール/クリア画面への切り替え/落ちたらやり直し

この記事で作るもの

  • 歩いているときは、2枚の画像を交互に切り替えて歩いているように見せる
  • ジャンプ中は、ジャンプ用の画像に切り替える
  • 旗に触れたら、クリア画面(ClearScene)に切り替わる
  • 雲から落ちて画面の下に消えたら、最初からやり直し

今回も、前回の PlayerController に機能を足していきます。使う画像は、歩く姿2枚(catWalkA.png・catWalkB.png)、ジャンプの姿(catJump.png)、旗(flag.png)、クリア画面の背景(backgroundClear.png)です。

1. パラパラ漫画のアニメーション

猫が歩いているように見せるために、0.1秒ごとに2枚の画像を交互に切り替えます。パラパラ漫画と同じ仕組みです。画像の切り替えは、SpriteRenderer(画像を表示するコンポーネント)の sprite を入れ替えるだけでできます。

画像を入れておく変数を用意する

PlayerControllerに、次の変数を追加します。

public Sprite[] walkSprites;      // 歩く画像(2枚)
public Sprite jumpSprite;         // ジャンプの画像
float time = 0;                   // 画像を切り替えてからの経過時間
int idx = 0;                      // 今表示している歩く画像の番号(0か1)
SpriteRenderer spriteRenderer;    // 猫の SpriteRenderer

Sprite[] の [] は配列(同じ種類のものを複数まとめて入れる箱)の印です。public にしたので、Inspectorから画像を設定できます。スクリプトを保存したら、猫のInspectorで次のように設定しましょう。

Inspectorの欄設定するもの
Walk Sprites のサイズ2
Walk Sprites → Element 0catWalkA
Walk Sprites → Element 1catWalkB
Jump SpritecatJump

Start では、SpriteRendererを取り出しておきます。

spriteRenderer = GetComponent<SpriteRenderer>();

0.1秒ごとに画像を切り替える

Update の中に、次のコードを追加します。

// アニメーション
if (rigid2D.linearVelocityY != 0)
{
    // 空中にいるときは、ジャンプの画像
    spriteRenderer.sprite = jumpSprite;
}
else
{
    // 着地しているときは、0.1秒ごとに歩く画像を切り替える
    time += Time.deltaTime;
    if (time > 0.1f)
    {
        time = 0;
        spriteRenderer.sprite = walkSprites[idx];
        idx = 1 - idx;   // 0 → 1 → 0 → 1 … と交互に切り替える
    }
}

0.1秒を数える仕組みは、CatEscapeで矢を1秒ごとに作ったときと同じです(Time.deltaTime をためていく)。上下に動いているとき(linearVelocityY != 0)は空中なので、ジャンプの画像を表示します。前回のジャンプの条件(== 0)のちょうど逆ですね。

Unity 6でCatEscapeを作る① ― 猫の移動と、Prefabで矢を降らせる仕組み(PC版)

idx = 1 – idx で0と1を行ったり来たり

idx = 1 - idx; は、0と1を交互に切り替える定番の書き方です。

今の idx1 – idx次に表示する画像
01 – 0 = 1walkSprites[1](catWalkB)
11 – 1 = 0walkSprites[0](catWalkA)

本格的なアニメーションはUnityのAnimator(アニメーションの専用機能)で作るのが一般的ですが、2枚を切り替えるくらいなら、このようにスクリプトだけでも作れます。仕組みが見えるので、まずはこの方法で「アニメーションはパラパラ漫画」という感覚をつかみましょう。

0.1秒ごとにcatWalkAとcatWalkBを交互に表示し、空中ではcatJumpを表示するパラパラ漫画のアニメーション

2. 旗に触れたらゴール(OnTriggerEnter2D)

次はゴールです。旗の画像をシーンに置き、Position を (9.8, -1, 0) にします。そして、旗に BoxCollider2D を追加して、Is Trigger にチェックを入れます。

Is Trigger とは

Is Triggerぶつかったとき呼ばれるメソッド使う場面
オフぶつかって止まる・上に乗れるOnCollisionEnter2D雲(床)、壁
オンすり抜ける。でも「触れた」ことは分かるOnTriggerEnter2Dゴール、アイテム、ワープ地点

旗は「ぶつかって止まる」必要はなく、「触れたかどうか」だけ分かればよいので、Is Triggerをオンにします。こうしておくと、猫が旗に触れた瞬間に、猫のスクリプトの OnTriggerEnter2D メソッドが自動で呼ばれます。PlayerControllerに次のメソッドを追加しましょう。

// 旗(Is Trigger のコライダー)に触れたときに呼ばれる
void OnTriggerEnter2D(Collider2D collision)
{
    Debug.Log("ゴール");
}

再生して旗まで進み、Consoleに「ゴール」と表示されれば成功です。CatEscapeでは当たり判定を自分で計算しましたが、Collider2Dを使うと、Unityが当たりを調べてメソッドを呼んでくれます。

Unity 6でCatEscapeを作る② ― 当たり判定とHPゲージ、スクリプト同士の連携(PC版)

OnTriggerEnter2D が呼ばれるには、ぶつかる2つのうち少なくとも片方にRigidbody2Dが必要です。今回は猫に付いているので大丈夫です。

3. クリア画面に切り替える(シーン遷移)

ゴールしたら、クリア画面に切り替えます。Unityでは、ゲームの画面をシーンという単位で作ります。今遊んでいる画面が GameScene なので、クリア画面用に ClearScene を新しく作ります。

ClearScene を作る

  1. メニューの File → New Scene で新しいシーンを作り、File → Save As で ClearScene という名前で保存する
  2. ClearSceneに backgroundClear.png を配置して保存する
  3. ProjectウィンドウのGameSceneをダブルクリックして、ゲームのシーンに戻る

Build Profiles のシーンリストに登録する

スクリプトからシーンを切り替えるには、使うシーンをシーンリストに登録しておく必要があります。Unity 6では、メニューの File → Build Profiles を開き、Scene List にProjectウィンドウから2つのシーンをドラッグ&ドロップします。

番号シーン
0GameScene(最初に表示されるシーン)
1ClearScene

以前のUnityでは「Build Settings」の「Scenes In Build」という名前でした。ネットの記事で古い名前を見かけたら、Build Profilesのことだと読み替えてください。

Unity 6 の「Build Profiles」とは?

LoadScene でシーンを切り替える

PlayerControllerの先頭に using UnityEngine.SceneManagement; を追加し、OnTriggerEnter2D を次のように書き換えます。

void OnTriggerEnter2D(Collider2D collision)
{
    Debug.Log("ゴール");
    SceneManager.LoadScene("ClearScene");   // クリア画面に切り替える
}

SceneManager.LoadScene("シーン名") で、指定したシーンに切り替わります。旗に触れた瞬間に、クリア画面が表示されれば成功です。

旗のIs Triggerに触れたらClearSceneへ、落ちたらGameSceneを読み込み直す。シーンはBuild ProfilesのScene Listに登録する

4. 落ちたら最初からやり直し

雲から落ちてしまったときの処理も作ります。Update の最後に、次のコードを追加します。

// 画面の下に落ちたら、最初からやり直し
if (transform.position.y < -10)
{
    SceneManager.LoadScene("GameScene");
}

自分自身のシーン(GameScene)をもう一度読み込むと、猫の位置も速さも、すべてシーンを保存したときの状態に戻ります。「やり直し」を1行で作れるのが、シーンを読み込み直す方法の便利なところです。

5. 完成したコード

using UnityEngine;
using UnityEngine.InputSystem;        // Mouse を使うために必要
using UnityEngine.SceneManagement;    // LoadScene を使うために必要

public class PlayerController : MonoBehaviour
{
    Rigidbody2D rigid2D;
    float jumpForce = 600.0f;         // ジャンプの力
    float walkForce = 30.0f;          // 歩く力
    float maxWalkSpeed = 2.0f;        // 歩く速さの上限
    public Sprite[] walkSprites;      // 歩く画像(2枚)
    public Sprite jumpSprite;         // ジャンプの画像
    float time = 0;                   // 画像を切り替えてからの経過時間
    int idx = 0;                      // 今の歩く画像の番号
    SpriteRenderer spriteRenderer;

    void Start()
    {
        Application.targetFrameRate = 60;
        rigid2D = GetComponent<Rigidbody2D>();
        spriteRenderer = GetComponent<SpriteRenderer>();
    }

    void Update()
    {
        // ジャンプする(着地しているときだけ)
        if (Mouse.current.leftButton.wasPressedThisFrame && rigid2D.linearVelocityY == 0)
        {
            rigid2D.AddForce(transform.up * jumpForce);
        }

        // 右へ歩く(速さの上限まで)
        if (rigid2D.linearVelocityX < maxWalkSpeed)
        {
            rigid2D.AddForce(transform.right * walkForce);
        }

        // アニメーション
        if (rigid2D.linearVelocityY != 0)
        {
            spriteRenderer.sprite = jumpSprite;
        }
        else
        {
            time += Time.deltaTime;
            if (time > 0.1f)
            {
                time = 0;
                spriteRenderer.sprite = walkSprites[idx];
                idx = 1 - idx;
            }
        }

        // 画面の下に落ちたら、最初からやり直し
        if (transform.position.y < -10)
        {
            SceneManager.LoadScene("GameScene");
        }
    }

    // 旗に触れたらゴール
    void OnTriggerEnter2D(Collider2D collision)
    {
        Debug.Log("ゴール");
        SceneManager.LoadScene("ClearScene");
    }
}

6. よくあるつまずき

旗に触れても何も起きない

エラーが出ないのに OnTriggerEnter2D が呼ばれないときは、次の点を確認しましょう。

  • 旗のBoxCollider2Dの Is Trigger にチェックが入っているか
  • メソッド名が OnTriggerEnter2D と1文字も違わず書けているか(OnTriggerEnter は3D用で、2Dでは呼ばれない)
  • 引数が Collider2D になっているか(Collision2D ではない)
  • 猫にRigidbody2Dが付いているか

OnTriggerEnter2D は、Unityが名前で探して呼び出す特別なメソッドです。名前を間違えてもエラーにはならず、ただ「呼ばれない」だけなので、気づきにくいつまずきです。

クリア画面に切り替わらず、エラーが出る

Scene 'ClearScene' couldn't be loaded because it has not been added to the ...

ClearSceneがBuild ProfilesのScene Listに登録されていません。File → Build Profiles を開いて、ClearSceneを追加しましょう。シーン名のつづり(大文字・小文字)が LoadScene の文字列と一致しているかも確認します。

歩くと IndexOutOfRangeException が出る

IndexOutOfRangeException: Index was outside the bounds of the array.

Inspectorの Walk Sprites のサイズが0のままで、画像が入っていません。サイズを2にして、catWalkAとcatWalkBを設定しましょう。

SceneManager が見つからないというエラーが出る

error CS0103: The name 'SceneManager' does not exist in the current context

ファイルの先頭に using UnityEngine.SceneManagement; がありません。

7. もう一歩:クリア画面からもう一度遊ぶ

今のままだと、クリア画面に来たらそこで終わりです。ClearSceneに空のオブジェクト ClearDirector を作り、次のスクリプトを付けると、クリックでゲームに戻れるようになります。

using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;

public class ClearDirector : MonoBehaviour
{
    void Update()
    {
        // クリックしたら、ゲームのシーンに戻る
        if (Mouse.current.leftButton.wasPressedThisFrame)
        {
            SceneManager.LoadScene("GameScene");
        }
    }
}

このように、シーンごとに「監督」を置いてシーンの切り替えを担当させると、タイトル画面・ゲーム画面・結果画面…と、画面を増やしていくのも簡単になります。

まとめ

  • SpriteRendererの sprite を0.1秒ごとに入れ替えると、パラパラ漫画のアニメーションになる
  • idx = 1 - idx; で0と1を交互に切り替えられる
  • Is Trigger をオンにしたコライダーは、すり抜けるが「触れた」ことは OnTriggerEnter2D で分かる
  • シーンを切り替えるには、Build Profiles の Scene List に登録して SceneManager.LoadScene を使う
  • 自分のシーンを読み込み直すと、「最初からやり直し」を1行で作れる

これでClimbCloudの完成です。物理エンジン、アニメーション、シーンの切り替えと、2Dゲームづくりの土台になる機能がそろいました。

訪問数 1 回, 今日の訪問数 1回

広告