むりこのーと

創作活動の記録や、日々思ったことをゆるく書いています。

【Phaser入門】見下ろし2Dレトロアクションゲームを作るPart4 キャラ動作編

どうも。

前回はキャラクターの画像を読み込み、表示するところまでを実装しました。まだ見ていない方はこちらもご覧ください。

www.murinote.com

今回はキャラクターを動かしたり、他のスプライトとのアクションを実装していきます。

目次

今回の記事は以下の内容になっています。

それでは見ていきましょう!

1. キャラクターを動かす

早速、表示したキャラクターを動かしてみましょう。前回まででスライムのスプライトを作成したので、今回はこのスライムをカーソルキーで動かせるように設定していきます。

実際にゲームを作るときは、ゲームがどのように遊ばれるのかを考えて実装する必要があります。例えばスマホゲームなら縦向き横向きで画面のサイズを変える必要があったりします。

が、今回はPCゲームであるとしましょう。理由は実装が楽だからです。

キー操作

ではまず、キー操作をすることをゲーム内に書きましょう。「私はキー入力を使うので、キー入力を受け付けてください」とPhaser側に申告するイメージです。

    create() {
        ...
        ...
        // カーソルキー押下を有効にする
        this.cursors = this.input.keyboard.createCursorKeys();
    }

create()の最後に、input.keyboard.createCursorKeys();を記載します。名前からわかる通り、これはカーソルキーを使えるようにする関数です。カーソルキーに特化したものなので、別のキーを使う場合は別の関数を使う必要がありますが、今は割愛します。

では実際にキー入力を使ったスライム移動のコードを見ていきましょう。

    update() {
        // 下キー押下時
        if (this.cursors.down.isDown) {
            // 下向きのアニメーションを再生
            this.slime.anims.play("moveDown", true);
            // スライムを下に移動
            this.slime.y += 3;
        }
        // 右キー押下時
        else if (this.cursors.right.isDown) {
            // 右向きのアニメーションを再生
            this.slime.anims.play("moveRight", true);
            // スライムを右に移動
            this.slime.x += 3;
        }
        // 上キー押下時
        else if (this.cursors.up.isDown) {
            // 上向きのアニメーションを再生
            this.slime.anims.play("moveUp", true);
            // スライムを上に移動
            this.slime.y -= 3;
        }
        // 左キー押下時
        else if (this.cursors.left.isDown) {
            // 左向きのアニメーションを再生
            this.slime.anims.play("moveLeft", true);
            // スライムを左に移動
            this.slime.x -= 3;
        } else {
            // いずれのキーも押されていない場合はアニメーションを停止
            this.slime.anims.stop();
        }
    }

ここでpreload()create()に次ぐ新たな関数update()が登場しました。これはcreate()が終わった後、つまりゲームシーン開始の準備が整ったら、毎フレーム実施される関数です。ここに、それぞれのキーが押されたときにどのような処理を行うのかを書いています。

まずthis.cursors.down.isDownのように記載をしています。これはdownキー(下キー)が押されている間、trueになります。カーソルキーの気持ちになってみるとわかると思いますが、キーが押されている=沈んでいる=isDownですね。逆にキーが離されているときはisUptrueになっています。

次に移動方向に対応するアニメーションの再生をします。ここは前回使ったanims.play()を使います。以前と違い、アニメーション名のあとにtrueを引数で指定していますが、これは説明すると難しくなるので一旦無視でいいです。そういうものだと思っておいてください。

最後に、slime.xなどをいじって移動方向にスプライトの座標を移動させます。

では実際にゲーム再生して確認してみましょう。

スライム君が上下左右にふよふよ動いていることがわかりますね。

2. 他のスプライトとの衝突

では次にこのスライム君がアイテムを獲得できるように衝突判定を実装していきます。今回取得するアイテムは以下のクリスタルです。大きさは48ピクセル×48ピクセルです。

アイテムの作成

ではこれをassetsフォルダに保存し、実際に表示してみましょう。

    preload() {

        ...
        ...

        // 画像を読み込む
        this.load.image("crystal", "assets/crystal.png");
    }

まずpreload()内で画像を使えるようにします。今回はスプライトシートではないので、this.add.image()を使います。

次にcreate()内で実際にクリスタルを表示しますが、今回はグループという機能を使います。Phaserにおいてグループというのは複数のスプライトをまとめるための構造のことです。まずはコードを見てみましょう。

    create() {
        ...
        ...

        // クリスタルのグループを作成する
        this.crystals = this.add.group();

        // クリスタルを一つ作成
        this.crystals.create(100, 100, "crystal");
    }

まずthis.add.group()にてグループを作成します。次に(グループ).create()で実際にそのグループに対してスプライトを作成します。今回は座標が(100, 100)の位置に作成してみます。

ではゲームを起動して確認してみましょう。

クリスタルが表示されていれば成功です。

衝突判定

では最後に衝突判定を実装していきます。

        // スライムのスプライトを作る
        this.slime = this.physics.add.sprite(
            this.scale.width / 2,
            this.scale.height / 2,
            "slime"
        );
        ...
        ...

        // クリスタルのグループを作成する
        this.crystals = this.physics.add.group();
        ...

スライムやグループの作成時に使用していたthis.addを、this.physics.addに変更しました。こうすることで、スプライトが物理ボディを持つようになります。物理ボディを持つと通常のスプライトよりもできることが増えます。まずはそれくらいの認識でいいと思います。

そして次に衝突判定を実装していきます。

        // スライムとクリスタルの衝突判定
        this.physics.add.existing(this.slime);
        this.physics.add.existing(this.crystals);
        this.physics.add.overlap(
            this.slime,
            this.crystals,
            (slime, crystal) => {
                // クリスタルに触れたときの処理
                crystal.destroy(); // クリスタルを消す
            },
            null,
            this
        );

this.physics.add.existing()は物理演算を有効化させるためのおまじないだと思っていて大丈夫です。そしてthis.physics.add.overlap()で、スプライト同士が重なったときの処理を定義していきます。

今回は重なったときにクリスタルを削除するようにします。細かい引数はそこまで気にしなくていいですが、衝突判定をしたい対象を二つ指定し、衝突した時の処理内容を書きます。今回はクリスタルを削除するので、(スプライト).destroy()を使用します。

最後にmain.jsのconfigに以下の記述を追加しましょう。

    // 物理演算の設定
    physics: {
        default: "arcade",
        arcade: {
            debug: false,
            gravity: { y: 0 },
        },
    },

これを追加することで前述の物理演算系がすべて有効化されます。では本当に削除されるか試してみましょう。

クリスタルとスライムの衝突判定ができました。まるで取得したように見えますね。

最後に

いったん基本的なところは実装できたとおもいます。ここまでできれば皆さんは独力でも(調べたりしながら)ゲームを作れるようになっているかと思います。

とはいえまだまだゲームには程遠いので、いつになるかはわかりませんが、引き続き応用講座的なものを投稿していきます!それでは!