tanaka's Programming Memo

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

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

Phaserをサンドボックスで試す(1)Phaserの概要とサンドボックスの操作

phaser.io

次へ

PCとスマホのいずれでも動作するゲームが作れるHTML5ゲームフレームワークPhaserを試します。Phaserの公式サイトにあるチュートリアル Making your first Phaser game で紹介されている記事を参考にして、Webブラウザー上でPhaserを簡単に試すことができる Phaser サンドボックスで実装してみます。

Phaserとは

デスクトップやモバイルで動くHTML5ゲームを作るためのフレームワーク(=枠組み)です。ゲームを動かすフレームワークのことをゲームエンジンといいます。ゲームエンジンの最有力なものの一つにUnityがあります。とても使いやすい上に、高度なゲームが作れる優秀なゲームエンジンなのですが、機能が充実しているために相応の性能のPCが必要になります。そのようなPCを持っていない人向けによさそうなのがPhaserです。

Phaserを選んだのは以下のポイントが決め手でした。

  • HTML5で動くので、最新のWebブラウザーが動く環境であれば性能の低いPCでも動かすことができる
  • JavaScriptやTypeScriptといった実務ですぐに役立つ言語が使える
  • 物理シミュレーションをする物理エンジンを持っているので、移動や当たり判定などをUnityと同じように考えて実装できる
  • 初期化のための儀式のようなプログラムはPhaserが裏で処理してくれるので、プログラマーは自分のコードに集中することができる
  • Phaserサンドボックスですぐに試せる

Phaserで学んだ考え方の多くはUnityに応用できます。手元にある古いPCや、1万円程度で入手できる安価な中古PCでまずはPhaserを学習しておいて、Unityが動くPCを手に入れたらUnityに進む、という展望です。

HTML5とは、Webブラウザーの核となるHTML(Hypertext Markup Language)言語のバージョン5のことです。Webブラウザー上で実行できるスクリプト言語であるJavaScriptで制御することで、高度なアプリをWebブラウザー上で動かすことができます。HTML5は共通仕様なので、最新のWebブラウザーがインストールされている環境であれば、Windows, Mac, Linux, Android, iOSなどに関わらず、同じプログラムを実行することができるので、近年重要となっている技術です。

Phaserのサンドボックス

Phaserの公式ページにあるサンドボックスを使うと、Webブラウザー上ですぐに試すことができます。いくつかのテンプレートが用意されているので、真っ新な状態から始めなくて済みます。また、コード補完が効くので入力が簡単にできます。

Phaser - Sandbox - Online Phaser Code Editorを右クリックして、新しいタブで開きましょう。下にスクロールさせると[QuickStart Templates]という項目があります。

f:id:am1tanaka:20170409230902p:plain

  • BLANKETY BLANK
    • 何もない状態から開始
  • SINGLE SPRITE
    • スプライトを1つ表した状態から開始
  • BARE BONES PLATFORMER
    • プレイヤーと地面を表示して、物理エンジンの一つであるArcade Physicsを実装した状態から開始

以上の3種類からはじめの状態を選べます。下に書いてある[Click here]をクリックすると、マウスやタップでビットマップにペイントできる[ART ATTACK]、キーボードで操作できる宇宙船の表示と弾を発射できる[SHOOT-EM-UP]、ドロップゾーンにドラッグ&ドロップできるスプライトを表示する[DRAG AND DROP]が追加で表示されます。

今回は、[SINGLE SPRITE]で開始したいので、[SINGLE SPRITE]を右クリックして、[新しいタブで開く]を選んでください。以下のようなページが表示されます。

f:id:am1tanaka:20170409231522p:plain

Phaserサンドボックスの使い方

サンドボックスのページを開くと、[preload][create][update][render][PLAY][Help]というタブが並び、その下に選択されているタブに応じたものが表示されます。Phaserがゲームを動かす流れは、以下のようになっています。

f:id:am1tanaka:20170415223947p:plain

ゲームに必要な画像や音声を読み込んだり(preload)、ゲームに登場させるものを生成したり(create)、プレイヤーの操作に応じて主人公を動かしたり、敵を動かしたり(update)、Phaserが自動的に描画しない内容を描画したり(render)、そのような処理はそれぞれのタブに書いてきます。

preloadタブ

preloadタブには、プログラムを動かす際の準備の処理を書きます。最初は以下のようなコードが書かれています。

function preload() {

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

    game.load.image('phaser', 'sprites/phaser-dude.png');

}

function preload() {は、準備の処理を書きますよ、という宣言です。最後の}との間に準備の処理コードを書きます。準備するためのコードが3行すでに書かれています(3, 4, 6行目)。3行目は http://examples.phaser.io/assets/ をベースURLに指定しています。例えばここを、自分の画像をアップロードしたURLに変更すれば、自分で用意したリソースを読み込ませることができます。

http://examples.phaser.io/assets/ を右クリックして、[新しいタブで開く]を選ぶと以下のようなページが開きます。

f:id:am1tanaka:20170409232801p:plain

このページには様々なリソースが用意されています。フォルダー名をクリックしていくと中身を見ることができます。sprites>phaser-dude.pngとクリックすると、今回読み込もうとしているキャラクターの画像が表示されます。

phaser-dude.png

ここにある素材は、開発時には自由に利用することが可能です。ただし、ユーザーが投稿した素材が含まれていて、中にはライセンス的にNGと思われるものも含まれています。公開する作品に利用するのは注意しましょう。

4行目は、異なるドメインから取得したデータへのアクセス方法を指定しています。ユーザー認証などは利用しないので、anonymous (匿名)にしています。

6行目は、画像を読み込んでいます。 http://examples.phaser.io/assets/sprites/phaser-dude.png から読み込んだ画像を、phaserという名前で読み込んでいます。

以上が準備処理です。

createタブ

createタブは、Phaserの環境が生成される時に実行する処理を書く場所です。最初は以下のようなコードが書かれています。

function create() {

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

}

function create() {は、Phaserの環境が生成される時に実行する処理を書きますよ、という宣言です。最後の}との間に生成時の処理コードを書きます。1行だけコードが書かれています。

varというのは、データの入れ物である変数を宣言するものです。その後ろに書かれているspriteというのが変数の名前になります。=に続けてgame.add.sprite(0, 0, 'phaser');というコードがあります。ここでの=は、数学的なイコールではありません。代入を表しています。右辺を処理して、その結果を左辺の変数に代入するという意味です。

game.add.sprite(0, 0, 'phaser');

上記を英単語の意味で読んでいくと、「ゲーム(game)に」「追加(add)する」「スプライト(sprite)を」となります。スプライトとは、ゲームで動かすキャラクターなどの画像の呼び方です。つまり、キャラクターの画像をゲームに追加するコードだと予想できます。これはメソッド呼び出しというもので、Phaserが提供しているメソッドを呼び出して様々な処理を実現していきます。()内にはパラメーターが並んでいます。'phaser'preloadで読み込んだ画像の名前ですので、読み込んだ画像を指定していることが予想できます。では最初の0, 0,はなんでしょう。これはあとで確認します。

updateタブ

updateタブは、画面を1回描画する度に実行される更新処理を書く場所で、Phaserで最も重要なコードがここに書かれることになります。

function update() {

}

上記のようなコードが書かれています。function update() {は、更新処理を書きますよ、という宣言です。最後の}との間に更新の処理コードを書きますが、ここには何も書かれていません。つまり、実行中には何もしません。

renderタブ

renderタブは、自分で画面を描画するためのコードを書く場所です。

function render() {

}

上記のようなコードが書かれています。function render() {は、描画処理を書きますよ、という宣言です。最後の}との間に描画の処理コードを書きますが、ここには何も書かれていません。つまり、現状では自分では何も書かないということになります。

PLAYタブ

PLAYタブは、プログラムの実行結果を確認するためのタブです。クリックして切り替えると、以下のような画面が表示されます。

f:id:am1tanaka:20170409235358p:plain

これが現在のプログラムを実行した結果です。preloadタブで読み込んだPhaserの公式キャラクターであるdude君が、createタブでゲーム画面に追加されて表示されました。

デフォルトでは、画面サイズが800x600ピクセルに設定されています。スペックの低いPCだと、高さが収まらないことがありますので、ちょっと小さくしておきましょう。

Game Size欄が見当たらない時は、ページを下にスクロールさせて表示します。600x450に変更して、[update]ボタンを押してください。

f:id:am1tanaka:20170415231914p:plain

ゲームの画面サイズが少し小さくなります。

Helpタブ

Helpタブに切り替える(1)と、Phaserのヘルプが表示されます。検索ボックス(2)に調べたいPhaserの命令を入力して、知りたいことを調べることができます。

f:id:am1tanaka:20170410001708p:plain

上記は、game.add.image を検索した例です。見たい命令をクリックすると(3)、解説が表示されます。Phaserは英語圏ゲームエンジンなので英語の解説ですが、単語を調べればある程度意味が把握できると思います。また、Google Chromeを利用すると、画面を右クリックして[日本語に翻訳]を選択すると和訳できます。

f:id:am1tanaka:20170410001834p:plain

機械翻訳なので怪しい日本語ですが、単語の意味は分かるので助けになるでしょう。

日本語が怪しいので、英語のまま作業を進めます。日本語に翻訳していたら、[F5]キーを押して再読み込みして翻訳を戻してください。

プログラムを予想する

PLAYタブに切り替えて、動きを観察します。

キーを押しても、マウスで画面をクリックしても何も起きません。updateタブに何も書いていないのでこれは当然ですね。

renderタブに何も書いていないのにキャラクターが表示されたのは何故でしょう?Phaserは、スプライトを画面に追加すると、追加した画像と座標に自動的に表示する機能を持っています。座標と画像が分かっているのだから、わざわざプログラマーが描画する必要はありません。そのような処理はPhaserが自動的に処理してくれるのです。Unityなどのゲームエンジンでもこのような思想は共通です。

renderタブは、線や図形などを直接描画したい時に利用するもので、Phaserが持っている機能で画面を構築する場合は必ずしも使う必要はありません。

コードを変更してみよう

createタブに切り替えてください(1)。

謎が一つ残っていました。3行目の0, 0,の意味です。以下の(2)のように、最初の0100に書き換えてください。書き換えたら、PLAYタブに切り替えて実行結果を見てみましょう。

f:id:am1tanaka:20170410000709p:plain

dude君が先ほどより右に表示されました。

f:id:am1tanaka:20170410000850p:plain

createタブに切り替えて、今度は100, 100,にしてみましょう。

f:id:am1tanaka:20170410001148p:plain

PLAYタブに切り替えると、dude君が下に表示されるようになりました。

f:id:am1tanaka:20170410001232p:plain

以上から、game.add.image()メソッドのパラメーターの意味が予想できたことでしょう。

ここまでのまとめ

  • Phaserの公式ページのサンドボックスの構成と使い方が分かりました
  • 画像や音の素材が用意されていて、すぐに利用することができました
  • 英単語を読んだり、パラメーターを変更して実行結果を見ることで、プログラムの内容を予想することができました

プログラムを学ぶ時には「観察」「予想」「変更」「確認」を自分自身で行うことが大切です。解説を理解しようとするのではなく、解説をヒントにして自ら予想をして、本当にそういう意味かが分かるようにコードを変更してみて、実行結果が予想と一致するかを確認する作業を通して、本質を自分で発見していきましょう。

Phaserサンドボックスの操作が分かりましたので、チュートリアル Making your first Phaser game の開発に進みます。開いているサンドボックスを利用しますので、そのままにして次に進んでください。

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

(1)のサンドボックス

次から、ゲームの開発を開始します。

次へ

参考URL

はてなブログのプログラムコードに行番号を表示する(2017/4/15修正)

プログラムコードに行番号を表示したかったので、はてなブログのカスタマイズの勉強がてら作成してみました。

出来上がりは以下のような感じ。

let hello = "Hello!";
console.log(hello+"行番号!");

ブログデザインのカスタマイズで、フッターにJavaScriptを追加と、奇数行の背景色が変わるようにCSSを設定しました。

(2017/4/15 フリープランのスマホレイアウトだとフッターにJavaScriptが設定できず、行数指定がおかしくなるので// 数字:の書式を追加)

以下、手順です。

手順

はてなにログインしたら、(1)アカウントをクリック > (2)ブログを選択 > (3)デザインをクリックします。

f:id:am1tanaka:20170407230957p:plain

デザイン設定画面に切り替わるので、(1)設定アイコン > (2)フッタ > (3)その下のコードをクリックします。

f:id:am1tanaka:20170407231206p:plain

「HTML を記述できます」の欄に、以下のコードを入力します。

<script>
let codes = document.getElementsByClassName('code');
[].forEach.call(codes, function(elem, key, val){
    // クラスに lang が含まれていない場合は何もしない
    if (!/lang/.test(elem.className)) {
        return;
    }

    let line_num = 1;

    // 行で分割
    let lines = elem.innerHTML.split("\n");
    let texts = elem.textContent.split("\n");

    // 最終行が空の時は削除
    if (lines[lines.length-1].length === 0) {
        lines.pop();
    }

    // 最初の1行目にコメント後の数字:か、数字:があれば、先頭の行番号にする(2017/4/15修正)
    if ((texts.length > 0) && (/(^|\/\/|\/\*) *[0-9]+:/.test(texts[0].trim()))) {
        line_num = texts[0].trim().replace(/:/, "").replace(/(\/\/|\/\*)/, "")-0;
        lines.shift();
    }

    let modi = "<ol start='"+line_num+"'>";

    lines.forEach(function(elem) {
        modi += "<li class='code-list'>"+elem+"</li>";
    });
    modi += "</ol>";
    elem.innerHTML = modi;
});
</script>

コードの奇数行用のCSSを設定します。(1)デザインCSSをクリックしたら、(2)下のコード部分をクリックして開きます。

f:id:am1tanaka:20170407231839p:plain

以下のCSSを追加します。

.code-list:nth-child(2n+1) {
    background-color: #eee;
}

最後に、保存をクリックします。

f:id:am1tanaka:20170407232124p:plain

以上です。

やっていること

JavaScriptで、codeクラスの要素を列挙します。列挙した要素のうち、langというクラス名を含んでいたら、全体をolタグで囲んで、各行をliタグで囲みます。liタグにはcode-listクラスを設定しているので、CSS.code-list:nth-child(2n+1)に背景色を指定して、奇数行に色をつけています。

クラス名にlangが含まれていないのは、言語指定をしていないブロックです。自分の場合、コマンドラインの指示などは言語指定をしておらず、その場合は行番号を表示したくなかったので、このようなコードを追加しました。

また、コードブロックの最初に// 10:などのように、//+<数字>+:の行を書いておくと、その数字から行番号が始まるようにしました。

    // 10:
    // 10から開始

上記のようなコードを、言語指定付きで書くと以下のようになります。

    // 10:
    // 10から開始

参考URL