【Part10(最終回)】スマホで作るPhaserゲーム〜チュートリアル編〜

ゲーム

どうもです。タドスケです。

スマホだけで作るPhaserゲームも今回でいよいよ完成です。

最後の仕上げに障害物とゲームオーバー処理を入れましょう。




動かしてみる

最後なので全てのコードを載せます。

JSタブに丸ごとコピペしてください。(パスは適宜置き換えてください)

//---------------------------
// グローバル変数
//---------------------------
// ゲーム設定
var config = {
    type: Phaser.AUTO,
    width: 300,
    height: 400,
    physics: {
        default: 'arcade',
        arcade: {
            gravity: { y: 300 },
            debug: false
        }
    },
    scene: {
        preload: preload,
        create: create,
        update: update
    }
};
// ゲーム本体
var game = new Phaser.Game(config);
// プレイヤー
var player;
// 足場グループ
var platforms;
// 星グループ
var stars;
// ボムグループ
var bombs;
// スコア
var score = 0;
// スコア表示テキスト
var scoreText;

//---------------------------
// ロード
//---------------------------
function preload ()
{
    this.load.image('star', 'img/20210425182551.png');
    this.load.image('sky', 'img/20210425175550.png');
    this.load.image('ground', 'img/20210425175525.png');
    this.load.image('bomb', 'img/20210425182611.png');
    this.load.spritesheet('dude', 
        'img/20210425182602.png',
        { frameWidth: 32, frameHeight: 48 }
    );
}

//---------------------------
// 足場の生成
//---------------------------
function createPlatforms(scene)
{
    // 足場グループを生成
    platforms = scene.physics.add.staticGroup();

    // 足場1
    platforms.create(300, 150, 'ground').setScale(0.5).refreshBody();

    // 足場2
    platforms.create(0, 250, 'ground').setScale(0.5).refreshBody();

    // 地面
    platforms.create(150, 385, 'ground');
}

//---------------------------
// プレイヤーの生成
//---------------------------
function createPlayer(scene)
{
    // プレイヤー
    player = scene.physics.add.sprite(150, 200, 'dude');
    player.setBounce(0.2);
    player.setCollideWorldBounds(true);

    // プレイヤーアニメーション:正面
    scene.anims.create({
        key: 'turn',
        frameRate: 20,
        frames: 
            [{ key: 'dude', frame: 4 }],
    });

    // プレイヤーアニメーション:左
    scene.anims.create({
        key: 'left',
        frameRate: 10,
        repeat: -1,
        frames:         
              scene.anims.generateFrameNumbers(
                'dude', 
                { start: 0, end: 3 }
            ),
    });
 
    // プレイヤーアニメーション:右
    scene.anims.create({
        key: 'right',
        frameRate: 10,
        repeat: -1,
        frames: 
            scene.anims.generateFrameNumbers(
                'dude',
                { start: 5, end: 8 }
            ),
    });
}

//---------------------------
// 星の生成
//---------------------------
function createStars(scene)
{
    // グループの生成
    stars = scene.physics.add.group({
        key: 'star',
        repeat: 4,
        setXY: { x: 13, y: 0, stepX: 68 }
    });

    // 星の物理挙動を設定
    stars.children.iterate(function (child) {
        child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
    });
}

//---------------------------
// 新しいボムを生成する
//---------------------------
function createNewBomb()
{
    // プレイヤーから離れたランダムな場所
    var x = (player.x < 150) 
        ? Phaser.Math.Between(150, 300) 
        : Phaser.Math.Between(0, 150);

    // ボムの生成
    var bomb = bombs.create(x, 16, 'bomb');
    bomb.setBounce(1);
    bomb.setCollideWorldBounds(true);
    bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
}

//---------------------------
// 衝突の設定
//---------------------------
function colliderSetting(scene)
{
    // プレイヤーと星
    scene.physics.add.collider(stars, platforms);
    scene.physics.add.overlap(player, stars, collectStar, null, this);

    // プレイヤーと足場
    scene.physics.add.collider(player, platforms);

    // ボムと足場
    scene.physics.add.collider(bombs, platforms);

    // プレイヤーとボム
    scene.physics.add.collider(player, bombs, hitBomb, null, scene);
}

//---------------------------
// プレイヤーと星の衝突時に呼ばれる
//---------------------------
function collectStar (player, star)
{
    // 星を消す
    star.disableBody(true, true);

    // スコアを加える
    score += 10;
    scoreText.setText('Score: ' + score);

    // 全ての星を取った時
    if (stars.countActive(true) === 0)
    {
        // 星を復活させる
        stars.children.iterate(function (child) {
            child.enableBody(true, child.x, 0, true, true);
        });

        createNewBomb();
    }
}

//---------------------------
// プレイヤーとボムの衝突時に呼ばれる
//---------------------------
function hitBomb (player, bomb)
{
    this.physics.pause();
    player.setTint(0xff0000);
    player.anims.play('turn');
    gameOver = true;
}

//---------------------------
// ロード後処理
//---------------------------
function create ()
{
    // this = scene

    // マウス入力を有効にする
    this.input.mouse.capture = true

    // 背景
    this.add.image(300, 300, 'sky');

    // スコア
    scoreText = this.add.text(16, 16, 'Score: 0', { fontSize: '32px', fill: '#000' });

    // 足場
    createPlatforms(this);

    // プレイヤー
    createPlayer(this);

    // 星
    createStars(this);

    // ボム
    bombs = this.physics.add.group();

    // 衝突の設定
    colliderSetting(this);
}

//---------------------------
// 更新処理
//---------------------------
function update ()
{
    var pointer = this.input.activePointer;
    if(pointer.isDown)
    {
        // 左移動
        if(pointer.x < 150)
        {
            player.setVelocityX(-160);
            player.anims.play('left',true);
        }
        // 右移動
        else if(150 < pointer.x)
        {
            player.setVelocityX(160);
            player.anims.play('right',true);
        }

        // ジャンプ
        if(pointer.y < 200 && player.body.touching.down)
        {
            player.setVelocityY(-330);
        }
    }
    // 停止
    else
    {
        player.setVelocityX(0);
        player.anims.play('turn');
    }
}

実行して⭐️を全部取ると、ランダムな位置にボムが現れます。

ボムに触れるとゲームオーバーです。

※やり直すにはページをリロードしてください。

コード解説

create

bombs = this.physics.add.group();

ボムは途中から出てくるので、createのタイミングではグループだけ作っています。

衝突設定

// ボムと足場
scene.physics.add.collider(bombs, platforms);

// プレイヤーとボム
scene.physics.add.collider(player, bombs, hitBomb, null, scene);

足場との判定は他と同じです。

プレイヤーと当たった際にはhitBomb関数が呼ばれるように設定しています。

hitBomb内でscene要素を使えるように、最後の引数にsceneを渡しています。

プレイヤー衝突時の処理

function hitBomb (player, bomb)
{
    this.physics.pause();
    player.setTint(0xff0000);
    player.anims.play('turn');
    gameOver = true;
}

physics.pauseを呼ぶと物理計算が止まるので、ゲーム内のキャラクターやボムなどの動きも止まります。

setTintではプレイヤーの色を赤くしています(0xff0000は赤色)。

ボム・⭐️の生成

if (stars.countActive(true) === 0)

⭐️を取るとアクティブではなくなるのを利用して、アクティブな⭐️がなくなったら全ての⭐️を取ったとみなしています。

enableBodyを呼ぶことで⭐️が復活します。

同じタイミングでボムも生成しています。

ボムは画面内のプレイヤーからある程度離れた地点にランダムで出現します。

⭐️を全て取るたびに一個ずつボムが増えていくので、ゲームの難易度も上がっていきます。

まとめ

Part10まで及んだPhaserのチュートリアルもこれで終了となります。

ただチュートリアルを動かすだけではなく、記事としてコード解説を書くことで理解も深まった気がします。

今後は自分の作りたいゲームを決めて、都度ドキュメントを見ながら作っていこうかと思います。

コメント

  1. […] どうもです。タドスケです。 PCに向かえる時間が取れないけど、それでもスキマ時間にスマホでゲームを作りたい! ということで、前回の記事で調査した スマホアプリ:JS Anywhereゲームライブラリ:Phaser … 【Part8】スマホで作るPhaserゲーム〜チュートリアル編〜 【Part10(最終回)】スマホで作るPhaserゲーム〜チュートリアル編〜 […]

  2. […] […]

  3. […] […]

  4. […] PlayCanvasでスプライト機能を使ってみました。 参考にしたのはこちらのチュートリアルです。 完成品 できあがったのがこちらです。 WASDキーでキャラクターが移動します。 ※キャ… 【Part8】スマホで作るPhaserゲーム〜チュートリアル編〜 【Part10(最終回)】スマホで作るPhaserゲーム〜チュートリアル編〜 […]

タイトルとURLをコピーしました