読者です 読者をやめる 読者になる 読者になる

tanaka's Programming Memo

プログラミングについてのメモ。

Phaserをサンドボックスで試す

f:id:am1tanaka:20170419210146p:plain

HTML5ゲームエンジンPhaserのチュートリアルを実装する記事です。Phaserのサンドボックスを使うので、最新のWebブラウザーが動くインターネットに接続された環境で、インストール作業をせずに試すことができます。

am1tanaka.hatenablog.com

am1tanaka.hatenablog.com

am1tanaka.hatenablog.com

am1tanaka.hatenablog.com

am1tanaka.hatenablog.com

am1tanaka.hatenablog.com

am1tanaka.hatenablog.com

Phaserをサンドボックスで試す(7)文字の表示とスコアの実装

f:id:am1tanaka:20170417231648p:plain

前へ

仕上げに、文字を表示して、スコアを実装します。Phaser公式チュートリアルMaking your first Phaser game: Part 8 - Finishing touches - Learn - Phaserを参考にして進めます。

(6)星を作成するの続きです。

先のサンドボックスを閉じてしまっていたら、こちらを右クリックして[新しいウィンドウで開く]で開いて、作業を始めてください。

スコアの定義と文字の表示

createタブを開いて、以下の場所に必要な変数を定義します。

f:id:am1tanaka:20170418180948p:plain

追加するコードは以下の通りです。

// 9:
// (A Valiable of the score)
var score = 0;
// (A Valiable of the Text)
var scoreText;

文字を表示するテキストを作成して、変数scoreTextに代入します。一番上に表示したいので、function create() {の最後に追加します。

f:id:am1tanaka:20170418181137p:plain

追加するのは以下のコードです。

    // 86:
    scoreText = game.add.text(12, 12, 'Score: 0', { font: "24px", fill: "#000" });

左から12ピクセル、上から12ピクセルの座標に、Score: 0と表示するテキストを作成して、変数scoreTextに代入します。フォントサイズは24ピクセル、黒で塗りつぶします。

PLAYタブに切り替えて画面を確認してください。文字が表示されます。

f:id:am1tanaka:20170417223847p:plain

スコアを加算する

星を取った時に、点数が10点入るようにします。どこにプログラムを書き足せばよいでしょうか?

星を取った時に、星を消すコードを前の記事で書きました。その場所にスコアを10点増やすコードを追加すれば、目的を達することができそうです。

updateタブを開いて、関数collectStar内の以下の場所に、点数を加算するコードを追加します。

f:id:am1tanaka:20170418181400p:plain

追加するコードは以下の通りです。

    // 44:
    //  Add and update the score
    score += 10;
    scoreText.text = 'Score: ' + score; 

PLAYタブに切り替えたら、星を集めてください。点数が加算されます。

f:id:am1tanaka:20170417231648p:plain

コードを書く場所を工夫することで、自動的に「星をとった時」に点数を加算することができました。プログラミングは、「どこに」「どのような順番で」コードを書くかによって、同じコードでも意味が変わることがあるのです。

ここまでのまとめ

このチュートリアルは、これで完成です。利用する画像の指定の仕方、画像やパターンを持ったスプライトの読み込み、グループの作成、スプライトの表示、物理エンジンの活用、キー操作方法、キャラクターが重なった時の処理、文字の表示方法など、多くのことを実装してきました。これを応用すれば、もっと色々なことができるでしょう。例えば、クリアやゲームオーバー要素がありません。星と同様の方法で障害物を作成して、プレイヤーと重なったらプレイヤーを削除するようにすればゲームオーバーが作れます。あるいは、ゲームオーバー要素はなくして、以下に短い時間で星を全て集められるかを競うようにすることも考えられます。発想を広げるための画像が http://examples.phaser.io/assets/ に用意されています。

ここで示したチュートリアル以外にも、コミュニティーで作成された700を越えるチュートリアル(Tutorial - Learn - Phaser)や、公式チュートリアル(Official Phaser Tutorials - Learn - Phaser)が公式サイトで公開されています。自分が作りたいゲームに近いものを探したり、似た処理をしているサンプルを探して、どのようにプログラムが作られているかを知ることができます。

Phaser Forumに疑問や質問を書き込めば、コミュニティーの人たちが助けてくれるかも知れませんので活用してみてください(英語ですが)。

完成版

以下、完成版のサンドボックスプロジェクトです。

完成版

最後に

Phaserで思い通りにゲームを作るには、JavaScriptというプログラミング言語の理解が必要になります。基礎を独学で学べる便利なサービスがありますので紹介します。

Phaserは安価なPCでも動かすことができる、モダンなゲームエンジンです。英語の情報が多いですが、サンプルのプログラムは沢山ありますので、プログラムを見て勉強することができるでしょう。

前へ

参考URL

Phaserをサンドボックスで試す(6)星を作成する

f:id:am1tanaka:20170417221324p:plain

前へ | 次へ

プレイヤーが集める星を作ります。Phaser公式チュートリアルMaking your first Phaser game: Part 7 - Starshine - Learn - Phaserを参考にして進めます。

(5)プレイヤーの操作の続きです。

先のサンドボックスを閉じてしまっていたら、こちらを右クリックして[新しいウィンドウで開く]で開いて、作業を始めてください。

星を登場させる

プレイヤーが集めるべきアイテムの星を作ります。星は複数登場して、プレイヤーとの接触を物理エンジンに委ねます。プレイヤーと地面を衝突させる時を思い出してください。衝突させる時に、 game.physics.arcade.collide(player, platforms); として、衝突する対象を指示しました。星を個別に作成した場合、全ての星に対してこの指定をしなければならず面倒です。そこで、地面の時と同じく、新しくstarsというグループを作成して、そこに星を登録していくことにしましょう。

createタブを開いて、まずは以下の場所にstarsを定義します。

f:id:am1tanaka:20170418174449p:plain

追加するコードは以下の通りです。

// 7:
// (A valiable of the group contains the stars)
var stars;

function create() {に星のグループを作成して、星を作成しながら物理エンジンなどの設定をします。以下の場所です。

f:id:am1tanaka:20170418174756p:plain

追加するのは以下のコードです。

    // 65:
    stars = game.add.group();

    stars.enableBody = true;

    //  Here we'll create 12 of them evenly spaced apart
    for (let i = 0; i < 12; i++)
    {
        //  Create a star inside of the 'stars' group
        let star = stars.create(i * 50, 0, 'star');

        //  Let gravity do its thing
        star.body.gravity.y = 6;

        //  This just gives each star a slightly random bounce value
        star.body.bounce.y = 0.7 + Math.random() * 0.2;
    }

PLAYタブに切り替えて動きを見てください。星が作成されて落下をします。ただ、床は通り抜け、プレイヤーで取ろうとしても取れません。

f:id:am1tanaka:20170417210700p:plain

コードの意味

// 8:
var stars;

すでに何回か似たようなコードが出ていますね。これでstarsという名前の変数を定義しています。これに、作成した星のグループを代入して利用します。

    // 65:
    stars = game.add.group();

    stars.enableBody = true;

65行目で、グループを作成して、変数starsに代入しています。67行目で、星グループの物理エンジンを有効にしています。地面と同じ設定です。

    // 70:
    for (let i = 0; i < 12; i++)
    {

これはfor文という構文で、プログラムを繰り返すのに使います。細かい意味は後回しにして、一先ずここでは以下のことを確認しておいてください。

  • ローカル変数i
  • 0から1ずつ増えながら
  • 11になるまで
  • {}の間のコードを繰り返します

つまり、iが0~11まで変化しながら、{}の間を12回繰り返し処理されます。

        // 73:
        let star = stars.create(i * 50, 0, 'star');

星のグループに、X座標は現在のiに50を掛けた場所、Y座標は最上段に、starの名前のグラフィックを作成して、そのインスタンスをローカル変数starに代入します。iは繰り返すごとに、0 > 1 > 2 > … > 11 と変化していきますので、X座標が 0 > 50 > 100 > 150 > … と、50ピクセルごとに並ぶことになります。

        // 76:
        star.body.gravity.y = 6;

星に重力加速度を設定します。1秒で6ピクセル/秒加速するように重力落下させます。

        // 79:
        star.body.bounce.y = 0.7 + Math.random() * 0.2;

星のY方向の弾性係数を設定します。Math.random()は、乱数を生成するためのコードで、0以上1未満の範囲の乱数を返します。0以上1未満の乱数に0.2を掛けた値を0.7に足していますので、0.7以上0.9未満の弾性係数を設定しています。

今はまだ跳ね返らないので画面外まで星が落ちてしまいますが、跳ね返りを設定すれば、星ごとに少し異なる高さで跳ね返るはずです。作業を進めて、予想が合っていたかを確認することも大切な作業です。

星と地面を衝突させる

星と地面を衝突させるコードを追加します。これはプレイヤーと地面に当たり判定を付けた時と同じメソッドを利用して、パラメータを星のグループと地面のグループにします。

updateタブに切り替えて、以下の場所にコードを追加します。

f:id:am1tanaka:20170418175442p:plain

追加するコードは以下の通りです。

    // 5:
    game.physics.arcade.collide(stars, platforms);

これで星が地面で跳ね返ります。PLAYタブに切り替えて確認してください。

f:id:am1tanaka:20170417213658p:plain

予想通り、星が異なる高さで跳ね返ります。

星を取れるようにする

プレイヤーと星グループの重なりを確認して、重なっていたらその星を消すようにします。地面の時は、接触したかと、どこと接触したかを確認すればよかったですが、今回はどの星と接触したかを把握する必要があります。そのために新しい構文を使います。

updateタブに切り替えたら、以下の場所にコードを追加します。

f:id:am1tanaka:20170418175645p:plain

追加するのは以下のコードです。

    // 6:
    game.physics.arcade.overlap(player, stars, collectStar, null, this);

playerstarsグループが重なる(overlap)かを確認して、重なっていたらcollectStar関数を呼び出します。重なった時の追加的なチェックはせず(null)、collectStar関数はthisから実行します。

collectStar関数が必要になりましたので、updateタブの最後に追加します。これまでと違って、最後の}の下に追加するので注意してください。

f:id:am1tanaka:20170418180114p:plain

追加するコードは以下の通りです。

    // 39:
function collectStar(player, star) {

    // Removes the star from the screen
    star.kill();    

}

関数collectStarを定義しています。プレイヤーと星グループ内の星のどれかが接触した時に、Phaserが自動的に呼び出してくれます。このような関数をコールバック関数と呼びます。collectStar関数は2つ引数を取ります。overlap関数の接触対象に並べた順番で、接触したオブジェクトのインスタンスを渡してくれます。

42行目のstar.kill();は、starを星グループから削除するコードです。starは引数で受け取ったものですので、プレイヤーと重なった星がこれで画面から消えます。

PLAYタブに切り替えて操作します。星を集めることができるようになりました。

f:id:am1tanaka:20170417221324p:plain

まとめ

地面を作成した時と同じような手順で星のグループを作成して、星を作成しました。星を12個登場させるために、繰り返し文forを利用しました。物理エンジンの振る舞いを設定した上で、地面との接触、プレイヤーとの接触を有効にして、プレイヤーと重なった星を消す処理を実装しました。

ここまで実装したサンドボックスは以下で確認できます。

(6)のサンドボックス

以上で、このチュートリアルでのゲームの動きは完成です。最後の仕上げに、文字を表示して、スコアを実装します。

前へ | 次へ

参考URL

Phaserをサンドボックスで試す(5)プレイヤーの操作

f:id:am1tanaka:20170417204848p:plain

前へ | 次へ

プレイヤーをキーボードで操作できるようにします。Phaser公式チュートリアルMaking your first Phaser game: Part 6 - Controlling the player with the keyboard - Learn - Phaserを参考にして進めます。

(4)プレイヤーの作成・当たり判定・処理落ち対策の続きです。

先のサンドボックスを閉じてしまっていたら、こちらを右クリックして[新しいウィンドウで開く]で開いて、作業を始めてください。

キーボードを使う

Phaserでキーボードのカーソルキーの入力を利用するために、createで準備をします。createタブに切り替えて、以下のような場所にコードを追加します。

f:id:am1tanaka:20170418170215p:plain

追加するコードは以下の通りです。

// 5:
// (A valiable of the keyboard cursor)
var cursors;

続いて、function create() {の中にキーボードのカーソルのコントローラーを作成するコードを追加します。以下のようにcreateの一番上にコードを追加します。

f:id:am1tanaka:20170418170533p:plain

追加するコードは以下の通りです。

    // 10:
    cursors = game.input.keyboard.createCursorKeys();

プレイヤーを左に動かす

変数cursorsに代入したインスタンスを使って、カーソルキーが押されているかを調べられます。例えば左が押されているかを確認したいときは、cursors.left.isDowntrueかを判定します。右の場合はleftの部分がright。上はup、下はdownで同じように確認できます。

左移動を作ります。updateタブに切り替えて、先に追加した衝突を指示するコードの下にコードを追加します。

f:id:am1tanaka:20170418171120p:plain

追加するコードは以下の通りです。

    // 5:
    //  Reset the players velocity (movement)
    player.body.velocity.x = 0;

    if (cursors.left.isDown)
    {
        //  Move to the left
        player.body.velocity.x = -120;

        player.animations.play('left');
    }

PLAYタブに切り替えて、左キーを押してください。キーを押している間、左に移動するようになります。また、走るアニメを開始します。

f:id:am1tanaka:20170412230829p:plain

左に移動するコード

追加したコードについて見ていきます。

createタブ

// 6:
var cursors;

キーボードのカーソルキーの状態を読み取るためのインスタンスを記録しておくための変数cursorsを定義します。

    // 10:
    cursors = game.input.keyboard.createCursorKeys();

ゲームオブジェクト > 入力(input) > キーボード > カーソルキー(CursorKeys)を作成(create) を呼び出しています。作成したカーソルを読み取るためのインスタンスを、変数cursorsに代入します。

以上がcreate処理に実装した内容です。

updateタブ

プレイヤーの動きは、画面を書き換えるたびに実行を繰り返します。そのようなプログラムはupdateタブに書きます。操作を反映させたり、当たり判定をしたり、ゲームを進めたり、updateがゲームを動かす場所です。

    // 6:
    player.body.velocity.x = 0;

プレイヤーの速度(velocity)のX方向に0を代入します。プレイヤーは物理エンジンを有効にしていますので、動かしたい速度を設定すれば、Phaserがその通りに移動させてくれます。0を代入したのでプレイヤーは横方向を停止します。

    // 8:
    if (cursors.left.isDown)
    {

ifは、条件に応じてプログラムを動かしたり、動かさなかったりするためのスイッチのような命令です。()内の計算結果がtrue(真=成立)していたら、その下に続く{から}の間のプログラムを実行します。成立していなかった場合は、{から}の処理は実行しません。

cursors.left.isDownは、左のキーが押されるとtrueに、押されていないとfalseになります。つまり、左のキーが押されていたら、{}の間のプログラムを実行することになります。

        // 11:
        player.body.velocity.x = -120;

        player.animations.play('left');
    }

左キーが押された時に実行するプログラムです。11行目では、X方向の速度に-120を設定しています。X座標は、大きい値ほど右を表しますので、120ピクセル、1秒間で動かすということになります。

13行目は、leftという名前のアニメを再生する指示です。

14行目で、左ボタンが押された時の処理は終了です。

左ボタンを離したらどうなるでしょうか。

  • 6行目で速度を0にしていますので、X方向は停止します
  • if文は成立しないので{}内のコードは実行されませんのでそのまま停止です
  • アニメに関しては何もしないので、左アニメが動きっぱなしになります

左への移動は停止するけど、アニメが停止しない理由が分かりました。

右移動と停止

左の動きができました。右移動と、キーを離した時にアニメを停止する処理を入れます。左移動のすぐ下に以下のようにコードを追加します。

f:id:am1tanaka:20170418172156p:plain

追加するコードは以下の通りです。

    // 15:
    else if (cursors.right.isDown) {
        //  Move to the right
        player.body.velocity.x = 120;

        player.animations.play('right');
    }
    else {
        //  Stand still
        player.animations.stop();

        player.frame = 4;
    }

PLAYタブに切り替えたら、左右キーを押してください。左右に歩くようになります。

f:id:am1tanaka:20170412232004p:plain

また、キーを離すとアニメが停止して、正面を向くようになりました。player.frame = 4;は、プレイヤーのアニメをパターン4にするという意味です。パターン4が何を表すかは、以下のパターンの並びから予想してみましょう。

プレイヤーの画像

基本的な処理は左移動と同じです。どのような処理なのかを予想してみましょう。

ジャンプを実装

上キーを押したらジャンプするようにします。左右移動と考え方は同じです。左右操作の続きの以下の場所にコードを追加します。

f:id:am1tanaka:20170418172443p:plain

追加するコードは以下の通りです。

    // 28:
    //  Allow the player to jump if they are touching the ground.
    if (cursors.up.isDown)
    {
        player.body.velocity.y = -250;
    }

PLAYタブに切り替えたら、上キーを押してください。ジャンプします。

しかし、なにか動きが変です。上キーを押しっぱなしにすると上昇を続けますし、上キーを押すといつでもジャンプできます。

地面を歩くタイプのゲームを作る時は、地面に立っている時と、空中にいる時の処理を分けて作ります。Phaserに限らず、どのような環境でも共通する考え方です。

ジャンプは地面に立っていないとできないのが自然です。そこで、上キーが押されているかを判定するときに、下方向が接触しているかと、地面に接触しているかも判定に加えます。これにより、空中ジャンプを抑制するのです。

f:id:am1tanaka:20170418172709p:plain

修正するコードは以下の通りです。

    // 29:
    if (cursors.up.isDown && player.body.touching.down && hitPlatform)

PLAYタブに切り替えて、操作してください。今度は、空中でジャンプすることはなくなりました。

スーパーマリオスマブラなどでは、地面にいる時と空中の時で横方向の動き方が変わります。今回は、地面でも空中でも横方向の動きは同じですが、考え方が分かれば好きなように改造することができます。

ここまでのまとめ

プレイヤーの操作を実装しました。移動は、速度(velocity)を設定すれば、あとは重力の時と同じく物理エンジンが動かしてくれます。このタイプのゲームで、地面などの障害物の上に乗っかったり、ぶつかったりする処理を作るのは工夫が必要なのですが、大幅に手間を省略することができました。Unityでも、同じような考え方で動かします。

ジャンプがあるゲームでは、地面に立っているかどうかで動きを変える必要があることを確認して、Phaserでどのように地面に立っているかを判定するかを示しました。

次に行く前に、updateタブで以下の物理エンジンに与えたパラメーターを変更して、動きの変化を確認してみてください。

  • 13行目のplayer.body.velocity.x = -120;-120を、-50などに変更してみる
  • 20行目のplayer.body.velocity.x = 120;120を、50などに変更してみる
  • 36行目のplayer.body.velocity.y = -250;-250を、-100などに変更してみる

それぞれの数値をどのように調整すればどのように動くのかを確認してみてください。

ここまで実装したサンドボックスは以下で確認できます。

(5)のサンドボックス

次は集めための星を作ります。

前へ | 次へ

参考URL

Phaserをサンドボックスで試す(4)プレイヤーの作成・当たり判定・処理落ち対策

f:id:am1tanaka:20170412220639p:plain

前へ | 次へ

Phaserの公式チュートリアルMaking your first Phaser game: Part 4 - Groups - Learn - PhaserMaking your first Phaser game: Part 5 - The Body and Velocity: A world of physics - Learn - Phaserサンドボックスで動かし、プレイヤーを実装します。(3)ゲームの舞台を作るの続きです。

先のサンドボックスを閉じてしまっていたら、こちらを右クリックして[新しいウィンドウで開く]で開いて、作業を始めてください。

プレイヤーを作成する

プレイヤーキャラクターを作成します。まずは作成したプレイヤーのインスタンスを記録しておくための変数を定義します。createタブを開いてください。3~4行目に以下のコードを追加します(手で入力する場合は、コメント行の3行目は省略してかまいません)。

// 3:
// (A valiable of the player)
var player;

次にプレイヤーを作成するコードを追加します。createタブのcreateメソッドの最後、以下の場所にコードを追加します。

f:id:am1tanaka:20170418155804p:plain

追加するコードは以下の通りです。

    // 41:
    // The player and its settings
    player = game.add.sprite(32, game.world.height - 120, 'dude');
    player.scale.setTo(0.75, 0.75);

    //  We need to enable physics on the player
    game.physics.arcade.enable(player);

    //  Player physics properties. Give the little guy a slight bounce.
    player.body.bounce.y = 0.2;
    player.body.gravity.y = 225;
    player.body.collideWorldBounds = true;

    //  Our two animations, walking left and right.
    player.animations.add('left', [0, 1, 2, 3], 10, true);
    player.animations.add('right', [5, 6, 7, 8], 10, true);

PLAYタブに切り替えて実行してください。

f:id:am1tanaka:20170412214607p:plain

プレイヤーキャラクターが左下の方に登場して、画面下まで落下します。

コードの意味

追加したプログラムコードの各行について説明します。先のゲームの舞台を作成したコードと似たものも多いので、思い出しながらご確認ください。

// 4:
var player;

作成したプレイヤーのスプライトを後で操作するために、インスタンスを記録しておくための変数の定義です。

    // 42:
    player = game.add.sprite(32, game.world.height - 120, 'dude');

ゲームフィールドのX座標32ピクセル、Y座標は画面下から120ピクセルの位置に、dudeで定義したプレイヤーのスプライトを作成します。作成したプレイヤーのインスタンスは、4行目で定義した変数playerに代入します。

    // 43:
    player.scale.setTo(0.75, 0.75);

作成したプレイヤーの大きさを画面に合わせるために、縦横とも75%に縮小します。

    // 46:
    game.physics.arcade.enable(player);

プレイヤーのArcade物理エンジンを有効にします。

物理エンジンとは、物理の力学で習う様々な運動の法則をプログラム化したものです。必要なパラメーターを設定すれば、物理エンジンが物体の動きを自然に見えるように処理してくれますし、当たり判定もしてくれます。Unityなどの最近のゲームエンジン物理エンジンを持っていますので、便利に活用しましょう。今回のプログラムでは、重力落下、移動、ジャンプ、地面との接触、星の当たり判定に利用します。

    // 49:
    player.body.bounce.y = 0.2;
    player.body.gravity.y = 225;
    player.body.collideWorldBounds = true;

プレイヤーの物理的な性質を設定します。player.body.bounce.yは、Y方向の跳ね返り係数です。他の物理オブジェクトに衝突したら、20%跳ね返ります。player.body.gravity.yは、Y方向の重力加速度(gravity)です。1秒で速度を225ピクセル加速します。player.body.collideWorldBoundsは、他の物理オブジェクトに衝突するかどうかを設定するものです。trueなので有効にしています。

プレイヤーはArcade物理エンジンを有効にしてありますので、あとは上記の設定に従ってPhaserが自動的にプレイヤーを制御してくれます。

    // 54:
    player.animations.add('left', [0, 1, 2, 3], 10, true);
    player.animations.add('right', [5, 6, 7, 8], 10, true);

54行目ではプレイヤーに、leftという名前で、0 > 1 > 2 > 3 のパターンを、10ミリ秒で、ループ再生するアニメーションを追加しています。

55行目ではプレイヤーに、rightという名前で、5 > 6 > 7 > 8 のパターンを、10ミリ秒で、ループ再生するアニメーションを追加しています。

アニメーションパラメーターの考察

アニメーションのパラメーターの意味はどういったものでしょう。ヒントは以下のグラフィックです。

dudeのイメージ

左端のパターンを0として、次が1、その次が2とパターンに番号を振ります。その番号と、54行目、55行目のパターンのパラメーターを照らし合わせて、意味を予想してみましょう。

正面向きのパターンを表示するパターン番号はいくつでしょう。あとで出てきますので、予想しておいてください。

地面を通り過ぎないようにする

地面(platforms)とプレイヤーのどちらにも、物理エンジンを有効にする設定をしてあります。そのため、両者の衝突は物理エンジンに任せることができます。そのための1行を追加します。

updateタブを開きます。function update() {}の間に、以下のようにコードを追加します。

f:id:am1tanaka:20170418160402p:plain

追加するコードは以下の通りです。

    // 3:
    let hitPlatform = game.physics.arcade.collide(player, platforms);

PLAYタブに切り替えて動きを確認します。

f:id:am1tanaka:20170412220639p:plain

プレイヤーが地面に乗るようになりました。少し弾むのは、player.body.bounce.y = 0.2;の設定が機能したからです。

処理落ち対策

Phaserはデフォルトでは、実際の処理速度に関わらず、決められたタイミングで動いているものと見なして動きます。処理速度が十分なPCなら滑らかに動くのでよい設定なのですが、性能が低いPCだと処理が間に合わず、動きが遅くなってしまいます。そのような状態を処理落ちすると言います。

そこで、実際に更新処理にかかった時間に応じて経過時間を変化させて移動距離を大きくすることで、性能が低いPCでも同じように動かす設定があります。createタブに切り替えて、function create() {の行の下にコードを追加します。

f:id:am1tanaka:20170418160746p:plain

追加するコードは以下の通りです。

    // 8:
    game.forceSingleUpdate = false;

PLAYタブに切り替えて動きを確認してください。dude君の落下速度が先程より速くなるようでしたら、PCの速度が遅くて予定の速度が出ていなかったことになります。この設定のまま進めましょう。

速さは同じぐらいで動きがぎこちなくなった場合は、PCの性能は十分です。この行は削除した方が綺麗に動きますので、削除しても構いません。

Phaserでは、処理が想定の速度でているかを検出する機能があります。実際に作成する場合はその機能を利用して、このフラグをONにしたり、OFFにしたりして、最低な動きになるようにします。

ここまでのまとめ

プレイヤーを表示して、落下するようにして、プレイヤーと地面が接触するようにしました。地面に衝突したら、プレイヤーが少し弾む設定もしました。Phaserでの処理落ち対策も施しました。

ここまで実装したサンドボックスは以下で確認できます。

(4)のサンドボックス

次は、プレイヤーを操作できるようにします。

前へ | 次へ

参考URL

Phaserをサンドボックスで試す(3)ゲームの舞台を作る

f:id:am1tanaka:20170416005545p:plain

前へ | 次へ

Phaserの公式チュートリアル「Making your first game」のMaking your first Phaser game: Part 3 - World Building - Learn - Phaserサンドボックスで動かして、ゲームの舞台を作ります。(2)画像の読み込みと仮表示の続きです。

先のサンドボックスを閉じてしまっていたら、こちらを右クリックして[新しいウィンドウで開く]で開いて、作業を始めてください。

ゲーム画面の座標系

これから背景と地面をゲームを追加して、ゲームの舞台を作ります。その前に、画面の座標について知っておきましょう。以下をご覧ください。

f:id:am1tanaka:20170416002612p:plain

画面の幅は600ピクセル、画面の高さは450ピクセルに設定しました。座標は、画面の左上が(0, 0)です。横方向はX座標で表します。X座標は、右ほど大きい値になり、600で画面外になります。縦方向はY座標で表します。Y座標は、下ほど大きい値になり、450で画面外になります。

画面外に出ると描画はされなくなりますが、値は有効です。マイナスの値にしたり、画面よりも大きい値を設定したりしても大丈夫です。

ゲームの世界である game world の操作には、game.worldや、ゲームワールド内に配置したキャラクターが持っているプロパティー(属性)やメソッド(命令)を使います。必要になったら調べてみてください。

ゲームエンジンのカメラ

座標の(0, 0)が常に画面の左上になる訳ではありません。実際には(0, 0)はゲームの世界の中心を表しています。それが左上に表示されるのは、カメラがそのように配置されているからです。

PhaserやUnityなどのゲームエンジンでは、映画撮影のように画面に表示したい場所をカメラを移動させて表示するという考え方をします。このようにすることで、ゲームの世界を動かさなくても、カメラを動かすだけで画面をスクロールできます。今回は利用しませんが、頭の片隅に置いておいてください。

ゲームの舞台を作成

座標が理解できたので、ゲームの舞台を作成します。createタブを開きます。まずは以下の場所にコードを追加します。

f:id:am1tanaka:20170418144454p:plain

追加するコードは以下の通りです。

// (A valiable of the group contains the ground and the 2 ledges)
var platforms;

次に、function create() {と、最後の}の間にあった1行を削除して、以下の場所にコードを追加します。

f:id:am1tanaka:20170418144756p:plain

追加するコードは以下の通りです。

    // 6:
    //  We're going to be using physics, so enable the Arcade Physics system
    game.physics.startSystem(Phaser.Physics.ARCADE);

    //  A simple background for our game
    let sky = game.add.sprite(0, 0, 'sky');

    // (Scale it to fit the game screen.)
    sky.scale.setTo(0.75, 0.75);

    //  The platforms group contains the ground and the 2 ledges we can jump on
    platforms = game.add.group();

    //  We will enable physics for any object that is created in this group
    platforms.enableBody = true;

    // Here we create the ground.
    let ground = platforms.create(0, game.world.height - 32, 'ground');

    //  Scale it to fit the width of the game (the original sprite is 400x32 in size)
    ground.scale.setTo(1.5, 0.5);

    //  This stops it from falling away when you jump on it
    ground.body.immovable = true;

    //  Now let's create two ledges
    let ledge = platforms.create(300, 300, 'ground');
    ledge.scale.setTo(0.75, 0.5);
    ledge.body.immovable = true;

    ledge = platforms.create(-110, 185, 'ground');
    ledge.scale.setTo(0.75, 0.5);
    ledge.body.immovable = true;

//から始まる行には、その行が何をしているのかのコメントを書いてあります。コメントは入力しなくてもプログラムの動作には影響しませんので、手で入力する場合は省いて構いません。

Phaserサンドボックスを利用する時の注意点

Phaserサンドボックスを利用する時は、以下の2点に気を付けてください。

  • 日本語などの全角文字を使わない
  • 予め用意されているfunction create() {などの関数を定義する行を、コピー&ペーストで上書きしない

上記をやると保存できなくなります。このチュートリアルで、まとめてコピー&ペーストをする指示がないのは、2番目の問題があるからです。コピー&ペーストをする時は、関数を定義する行と}の間にペーストしてください。

PLAYタブに切り替えて、以下のような画面が表示されれば成功です。うまく行かない場合は、入力ミスを探して、修正してください。

f:id:am1tanaka:20170416005545p:plain

コードの意味

createタブに入力したプログラムの意味は以下の通りです。

// 2:
var platforms;

地面を記録しておくための変数platformsの定義です。

    // 7:
    game.physics.startSystem(Phaser.Physics.ARCADE);

物理エンジン Arcade Physics を開始します。

    // 10:
    let sky = game.add.sprite(0, 0, 'sky');

preloadでskyという名前で読み込んだ画像を、画面左上(0, 0)に追加します。また、生成したスプライトのインスタンスを後で加工ができるようにskyという名前のローカル変数を定義して代入します。

letvarと同様、変数を定義するためのキーワードですが、letは直近の{}の中でのみ有効です。一時的に利用したい変数は、なるべくletで定義します。

インスタンス(=実体)とは、何かを生成した時にコンピューターの中に確保されたものを表すプログラミング用語です。インスタンスを変数に保存しておくと、あとでその実体の属性(プロパティー)振る舞い(メソッド)を操作することができます。

    // 13:
    sky.scale.setTo(0.75, 0.75);

ローカル変数skyに代入した空のインスタンスにアクセスして、幅と高さをどちらも75%に縮小します。

    // 16:
    platforms = game.add.group();

ゲームにグループを追加して、2行目で定義した変数platformsに代入しました。この段階では、platformsは空のグループです。このplatformsに地面と足場を2つ追加して、地面のグループにします。

    // 19:
    platforms.enableBody = true;

platforms物理エンジンを有効にします。これにより、力学的な動きや衝突をPhaserが自動的に動かしてくれます。

    // 22:
    let ground = platforms.create(0, game.world.height - 32, 'ground');

platformsグループのX座標が0、Y座標が画面の下から32ピクセル上の場所に、groundで読み込んだ画像を配置します。後で操作できるように、ローカル変数groundを定義して生成した地面のインスタンスを代入します。

    // 25:
    ground.scale.setTo(1.5, 0.5);

画面のサイズに合わせるために、地面の横幅を1.5倍、縦を半分にします。

    // 28:
    ground.body.immovable = true;

地面を動かないように設定します。物理エンジンを有効にしていると、様々な物理現象が再現されます。例えば、キャラクターが地面の上に飛び乗った場合、地面にはキャラクターから下向きの力を加えられることになります。そのままだと、地面はその影響で下に動いてしまいます。地面は画面に固定しておきたいので、動かないもの=immovableですよ、という設定をしているのです。

    // 31:
    let ledge = platforms.create(300, 300, 'ground');
    ledge.scale.setTo(0.75, 0.5);
    ledge.body.immovable = true;

platformsグループのX座標300ピクセル、Y座標も300ピクセルの位置に、groundで読み込んだ画像を生成します。あとで加工ができるようにローカル変数ledgeを定義して、代入しています。

ledgeを画面サイズに合わせるために、横幅を75%、縦を半分のサイズに縮小します。

ledgeも動かないようにするために、immovableを有効にしています。

    // 35:
    ledge = platforms.create(-110, 185, 'ground');
    ledge.scale.setTo(0.75, 0.5);
    ledge.body.immovable = true;

platformsグループのX座標-110ピクセル、Y座標180ピクセルの位置に、groundで読み込んだ画像を生成して、もう一つ足場を作ります。あとで加工できるように、先ほど宣言していたledgeに代入します。値を書き換えたので、これ以降のledgeへの操作は、新しく作った方の足場に対しての指示になります。

サイズと動かない設定を、1つ目の足場と同じように設定しています。

以上が、createタブに追加したプログラムの意味です。

ここまでのまとめ

Phaserの座標を説明して、ゲームの舞台を構築しました。プログラムの各行の解説をしましたので、気になった箇所を修正して、画面にどのような変化が起きるか観察してみるのもよいでしょう。

ここまで実装したサンドボックスは以下で確認できます。

(3)のサンドボックス

次は、プレイヤーを実装します。

前へ | 次へ

参考URL

Phaserをサンドボックスで試す(2)画像の読み込みと仮表示

phaser.io

前へ | 次へ

Phaserの公式チュートリアル「Making your first game」をサンドボックスで動かします。この記事の続きです。

はじめに

公式チュートリアルは、エディターやCloud9で開発する手順が書かれています。ここでは、サンドボックスで動かすように読み替えて紹介します。

ここを右クリックして、[新しいタブで開く]などで開くと、これから実装するゲームを試すことができます。

f:id:am1tanaka:20170417231648p:plain

やることです。

  • 必要な画像を読み込む
  • ゲームの舞台を作成する
  • プレイヤーキャラクターのDude君を左右矢印キーで左右に移動、スペースキーでジャンプさせる
  • 物理エンジンであるArcade Physicsで重力落下や、衝突判定を行う
  • 星を表示して、それを取れるようにする
  • 文字を表示して、スコアを実装する

画面サイズは、公式チュートリアルの800x600ピクセルではなく、600x450ピクセルに縮小しました。座標や移動パラメーターが公式チュートリアルとは異なります。

アセットの読み込み

チュートリアルのPart1は環境構築で、今回はサンドボックスを利用するので不要です。Part2 - LoadingAssetsからはじめます。

アセットとは、グラフィックやサウンドなどのゲームを構成する素材のことです。先に試したようにpreloadで処理します。以下のような背景の空、地面、星、主人公のキャラクターの4つの画像を読み込みます。

1) 背景の空(sky)

背景の空

2) 地面(ground)

地面

3) 星(star)

星

4) 主人公のキャラクター(dude)

主人公のキャラクター

先の記事で開いたサンドボックスに切り替えて、preloadタブをクリックして開きます。先のサンドボックスを閉じてしまっていたら、こちらを右クリックして[新しいウィンドウで開く]で開いて、作業を始めてください。

以下の場所にコードを追加します。

f:id:am1tanaka:20170418135353p:plain

追加するコードは以下の通りです。function preload() {}の間にコピーペーストしても構いません。

最初の4行目までは変更はありません。アセットを読み込む元のURLに http://examples.phaser.io/assets/ を指定して、 anonymous でアクセスします。

    // 3:
    game.load.baseURL = 'http://examples.phaser.io/assets/';
    game.load.crossOrigin = 'anonymous';

    game.load.image('sky', 'particlestorm/sky10.png');
    game.load.image('ground', 'sprites/platform.png');
    game.load.image('star', 'games/starstruck/star2.png');
    game.load.spritesheet('dude', 'games/starstruck/dude.png', 32, 48);

コード補完(Phaser Code Completion)の利用

自分で入力する場合は、[Ctrl]+[Space]キーによるオートコンプリート機能を利用することができます。例えば、6行目を入力する場合は以下のようにキー操作をしてみてください。

  • 6行目にloadと入力
    • f:id:am1tanaka:20170418135838p:plain
  • [Ctrl]キーを押しながら、[Space]キーを押します
  • loadに関連する候補が表示されるので、今回やりたいLoad Imageをクリックするか、選択した状態で[Enter]キーを押して選択します
    • f:id:am1tanaka:20170418140018p:plain
  • game.load.image('key', 'url');という行が自動的に入力されます
  • skyと入力して、画像の名前をskyにします
    • f:id:am1tanaka:20170418140153p:plain
  • [Tab]キーを押して候補を次に移動します
  • urlが選択状態になるので、そのままparticlestorm/sky10.pngと入力して、画像へのパスに書き換えます
    • f:id:am1tanaka:20170418140302p:plain
  • [Tab]キーを押して行末にカーソルが移動したら、[Enter]キーで改行します

以上の機能を活用することで、入力する文字数を減らせて、入力ミスも防げるので、積極的に利用しましょう。

コードの概要

6,7,8行目はそれぞれ、背景の空、地面、星を一枚絵で読み込んでいます。最初にあったコードと基本文法は同じで、()内が少し異なります。

9行目は少し異なり、spritesheet()で読み込んでいます。スプライトシート、つまり、スプライトを表形式で読み込んでいます。32, 48というパラメータが追加されています。これらについては後ほど触れます。

スプライトの作成

読み込みが完了したので、PLAYタブに切り替えて結果見てみましょう。画面に緑色の四角形が表示されました。これは失敗です。

f:id:am1tanaka:20170415233743p:plain

createタブをクリックして、スプライトを作成するコードを確認します。以下のようなコードになっています。

function create() {

    var sprite = game.add.sprite(100, 100, 'phaser');

}

これは「座標(100, 100)に、phaserという名前のスプライトを作成する」という意味でした。問題はphaserの部分です。preloadタブで読み込んだ画像の中に、phaserという名前は見当たりません。付けた名前はskygroundstardudeです。このうちのいずれかにしないと画像が特定できないので、緑色の四角で誤魔化してしまったのです。

それでは、以下のように変更して星を表示してみましょう。

function create() {

    var sprite = game.add.sprite(100, 100, 'star');

}

PLAYタブに切り替えると、無事に星が表示されました。

f:id:am1tanaka:20170415233917p:plain

保存

サンドボックスの内容は、保存して後で作業を再開したり、他のデバイスで表示させることができます。現在選択しているタブ(例えばPLAYタブ)上にマウスカーソルを移動させてください。表示が[save]に変わるのでクリックします。

f:id:am1tanaka:20170410215435p:plain

これで保存ができました。ブラウザーのアドレスバーを見てください。URLが変化しています。

f:id:am1tanaka:20170410215521p:plain

このURLをWebブラウザーで開けば、保存した状態を再現することができます。スマートフォンを持っていたら、Webブラウザーで表示されたURLを開いてみてください。スマホでも結果を表示することができます。

saveしてもURLが変化しない場合

[Ctrl]+[S]キーを押して保存してみてください。それでも変化しない場合は、Webブラウザーの履歴を削除してから、もう一度サンドボックスを開いて、保存してください。

それでも保存ができない場合、コードの中に日本語が使われていないかを確認してください。Phaserのサンドボックスは日本語が扱えません。コメントの中であろうと、日本語があると保存に失敗します。

ここまでのまとめ

以上でチュートリアルの Part2 Loading Assets の内容は完了です。ゲームに必要なイメージをpreloadで読み込んで、createで試しに星を表示しました。最後に、続きからできるように保存(save)をしました。

ここまで実装したサンドボックスは以下で確認できます。

(2)のサンドボックス

次は、ゲームの舞台を作ります。

前へ | 次へ

参考URL