jsc_080

JavaScript のゲームプログラミング入門

8. そこそこジャンプ:スコアと壁の変化

 

[ 7. そこそこジャンプ:壁と当たり判定 ] の続きです。

壁を表示して、移動させたり当たり判定を入れました。
ゲームオーバーも表示しましたね。

 

スコアを表示しよう

スコアの表示を入れます。
スコアが入るとゲーム画面らしさが出ますね。

表示優先を考え、処理の最後に入れます。
スコアのような情報は、一番手前に表示するのが基本です。

        Crafty.init(500,350, document.getElementById('game'));
        Crafty.background('#87ceeb');
        // 壁
        Crafty.sprite(49,147,"wall.png",{Wall:[0,0]});
        Crafty.e('Wall, 2D, Canvas, Collision')
            .attr({x:500, y:250})
            .bind('EnterFrame', function() {
                this.x -= 5;
                if (this.x < -50) this.x = 500;
            });
        // プレイヤー
        Crafty.sprite(72,100,"player.png",{Player:[0,0]});
        Crafty.e('Player, 2D, Canvas, Gravity, SpriteAnimation, Jumper, Collision')
            .attr({x:50, y:50})
            .reel('walk',300,[[0,0],[1,0]])   // 歩きアニメ設定
            .animate('walk', -1)        // 歩きアニメ再生
            .jumpSpeed(350)             // ジャンプの強さ
            .collision(15,30, 55,30, 55,85, 15,85)     // 当たり判定の範囲を変更
            .onHit('Wall', function () {  // 壁に当たったら
                Crafty.pause();           // ポーズする
                Crafty.e('2D, DOM, Text').attr({x:95, y:100, w:400})
                .text("GAME OVER").textColor('#dc143c')
                .textFont({size:'48px', weight:'bold'});
             })
            .gravity('Floor');
        // 地面
        Crafty.e('Floor, 2D, Canvas, Color')
           .attr({x:0, y:320, w:500, h:40}).color('#830');
        // スコア
        let score = 0;
        Crafty.e("Score, DOM, 2D, Text")
            .attr({ x:20, y:15, w:280 })
            .textFont({size:'20px', weight:'bold'})
            .textColor('#111')
            .text("SCORE: 0");
        // マウスのクリックを取得 注意:ClickではなくMouseDownを使う
        Crafty.s('Mouse').bind('MouseDown', function(e) {
            Crafty("Player").jump();
        });

 

実行してみます。
左上にスコアが表示されました。

スコアを表示する

 

表示の仕組みは、ゲームオーバーとほぼ同じです。
ただ、Scoreという名前を付けた点が違います。これは後で説明します。

    Crafty.e("Score, DOM, 2D, Text")    // テキスト表示のパラメータ
        .attr({ x:20, y:15, w:280 })    // 表示座標と幅
        .textFont({size:'20px', weight:'bold'}) // フォントサイズとスタイル
        .textColor('#111')  // 色
        .text("SCORE: 0");  // 表示する文字列

 

 

変数について

プログラミングでは 変数(へんすう) という入れ物を作ることができます。
文字列や数値を入れておき、計算や参照に繰り返し利用するのです。

 

例えば、財布をイメージしてください。
初めに 100円を入れたとします。
次に 1000円を入れます。このとき、財布の中を見ると 1100円あることが分かります。

そこで 500円取り出したら残りは 600円になります。
当たり前のことを書いてますが、これは財布という入れ物を使ったからできることです。

 

変数のおもな特徴は次の通りです。

変数の特徴

残念ながら変数のすべてを説明することはできません。(長くなるので)
少しずつ説明していきます。
気になることがあったら自分でも調べてみてください。

 

今回、スコア用に score という変数を宣言しました。
変数を使うときletで宣言する必要があります。
宣言と同時に初期化することもできます。
0 を代入しているので、この変数は数値として扱うことが分かります。

        // スコア
        let score = 0;

 

 

得点を入れよう

得点を入れるタイミングを考えます。

シューティングやアクションなら敵を撃破したときですよね。
このゲームでは敵を倒したりしないので、どうするのか悩みます。

考えた末、壁が画面外へ出て右へ戻すタイミングにしました。
これが一番シンプルで、難易度を上げたりしても対応できます。

        // 壁
        Crafty.sprite(49,147,"wall.png",{Wall:[0,0]});
        Crafty.e('Wall, 2D, Canvas, Collision')
            .attr({x:500, y:250})
            .bind('EnterFrame', function() {
                this.x -= 5;
                if (this.x < -50){
                    this.x = 500;
                    score += 100;
                    Crafty("Score").text("SCORE: "+score);
                }
            });

1行で書いていた if 文を波かっこ付きに変更しました。
ここにスコアの加算と表示変更の処理を入れます。

 

実行してみます。スコアが増えるようになりました。

スコアを加算する

 

処理をざっくり説明します。

    if (this.x < -50){  // x座標が -50より小さいとき
        this.x = 500;   // x座標を 500にする
        score += 100;   // score に 100 加算する
        Crafty("Score").text("SCORE: "+score);  // スコア表示の書き換え
    }

 

変数 score への加算は次のようにも書けます。
これは、score に入っている値に 100 を足して、その計算結果を score に代入しているのです。

    score = score +100;   // score に 100 加算する

 

スコア表示の書き換えについてです。
スコア表示のとき Score という名前で作成したことを覚えてますか?
その名前を使って文字列表示の内容を変更します。

Scoreオブジェクトを使う

そして文字列 “SCORE: " と score の内容を連結して text( ) で表示しています。
文字列の連結には + 記号を使います。

 

算術と同じ + の記号を使いますが、文字列を含んでいると文字列として連結されます。
下の例では 3+4 のみ結果が 7 になり、他は 34 と表示されます。

    console.log(3+4);    // 7
    console.log("3"+4);   // 34
    console.log(3+"4");   // 34
    console.log("3"+"4"); // 34

ちなみに、console.log( ) はコンソール画面に出力する命令です。
かっこの中に数式や文字列など入れて、実行中の状況を知るために使います。

 

 

壁の速度を変えよう

ゲームとしての見た目は完成しました。

ただ、遊んでみるとゲームらしさが感じられません。
それはジャンプしているだけだからかな、と思うこともあります。

でもこれは本当の理由ではありません。
一番の原因は変化がないことです。

試しに壁の速度をランダムにしてみましょう。

        // 壁
        Crafty.sprite(49,147,"wall.png",{Wall:[0,0]});
        Crafty.e('Wall, 2D, Canvas, Collision')
            .attr({x:500, y:250, speed:5})
            .bind('EnterFrame', function() {
                this.x -= this.speed;
                if (this.x < -50){
                    this.x = 500;
                    this.speed = Crafty.math.randomNumber(3,8);
                    console.log(this.speed);
                    score += 100;
                    Crafty("Score").text("SCORE: "+score);
                }
            });

実行して、壁の速度が変わることを確認しましょう。
console.log(this.speed) を入れました。
コンソールを開けば乱数の値も確認できます。

コンソールで乱数の値を確認する

 

プログラムの説明です。
まず、速度のプロパティ speed を用意します。
初期値は 5 にしました。

            .attr({x:500, y:250, speed:5})

this.speed で移動計算をします。

                this.x -= this.speed;

Crafty.math.randomNumber(3,8) は 3 から 8 までの乱数(小数点あり)を作ります。

                    this.speed = Crafty.math.randomNumber(3,8);

 

どうですか、ちょっと気を抜くとゲームオーバーになります。
これだとジャンプのタイミングを見極める必要が出てきて、ゲームらしさが増したと思います。

 

 

壁の高さを変えよう

もう一つ、変化を付けてみましょう。
壁の高さをランダムに変えてみます。

        // 壁
        Crafty.sprite(49,147,"wall.png",{Wall:[0,0]});
        Crafty.e('Wall, 2D, Canvas, Collision')
            .attr({x:500, y:250, speed:5, y0:250})
            .bind('EnterFrame', function() {
                this.x -= this.speed;
                if (this.x < -50){
                    this.x = 500;
                    this.speed = Crafty.math.randomNumber(3,8);
                    this.y = this.y0 - Crafty.math.randomInt(0,8)*5;
                    console.log(this.y);
                    score += 100;
                    Crafty("Score").text("SCORE: "+score);
                }
            });

この変更で壁の高さは次のように変わります。

壁の高さの変化

 

プログラムの説明です。
基本の高さのプロパティ y0 を用意します。
初期値は 250 にしました。

            .attr({x:500, y:250, speed:5, y0:250})

Crafty.math.randomInt(0,8) は 0 から 8 までの乱数(整数)を作ります。
それに 5 を掛けているので 0,5,10,15…35,40 と変化します。
基本の高さから乱数を引いて、y座標に入れます。

                    this.y = this.y0 - Crafty.math.randomInt(0,8)*5;

 

遊んでみてどうでしょうか?
私の感想は、思ったほど変化を感じなかったです。
複数の壁が出現するパターンだと有効かもしれませんね。

 

 

完成です

お疲れさまでした。
index.html の全プログラムを載せておきます。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8" />
    <title>そこそこジャンプ</title>
    <script src="crafty-min.js"></script>
    <style type="text/css">
        body{
            padding:0px;
            margin:0px;
        }
    </style>
</head>
<body>
    <div id="game"></div>
    <script>
        Crafty.init(500,350, document.getElementById('game'));
        Crafty.background('#87ceeb');
        // 壁
        Crafty.sprite(49,147,"wall.png",{Wall:[0,0]});
        Crafty.e('Wall, 2D, Canvas, Collision')
            .attr({x:500, y:250, speed:5, y0:250})
            .bind('EnterFrame', function() {
                this.x -= this.speed;
                if (this.x < -50){
                    this.x = 500;
                    this.speed = Crafty.math.randomNumber(3,8);
                    this.y = this.y0 - Crafty.math.randomInt(0,8)*5;
                    console.log(this.y);
                    score += 100;
                    Crafty("Score").text("SCORE: "+score);
                }
            });
        // プレイヤー
        Crafty.sprite(72,100,"player.png",{Player:[0,0]});
        Crafty.e('Player, 2D, Canvas, Gravity, SpriteAnimation, Jumper, Collision')
            .attr({x:50, y:50})
            .reel('walk',300,[[0,0],[1,0]])   // 歩きアニメ設定
            .animate('walk', -1)        // 歩きアニメ再生
            .jumpSpeed(350)             // ジャンプの強さ
            .collision(15,30, 55,30, 55,85, 15,85)     // 当たり判定の範囲を変更
            .onHit('Wall', function () {  // 壁に当たったら
                Crafty.pause();           // ポーズする
                Crafty.e('2D, DOM, Text').attr({x:95, y:100, w:400})
                .text("GAME OVER").textColor('#dc143c')
                .textFont({size:'48px', weight:'bold'});
             })
            .gravity('Floor');
        // 地面
        Crafty.e('Floor, 2D, Canvas, Color')
           .attr({x:0, y:320, w:500, h:40}).color('#830');
        // スコア
        let score = 0;
        Crafty.e("Score, DOM, 2D, Text")
            .attr({ x:20, y:15, w:280 })
            .textFont({size:'20px', weight:'bold'})
            .textColor('#111')
            .text("SCORE: 0");
        // マウスのクリックを取得 注意:ClickではなくMouseDownを使う
        Crafty.s('Mouse').bind('MouseDown', function(e) {
            Crafty("Player").jump();
        });
    </script>
</body>
</html>

 

シンプルでしたがゲームを完成させました。
何も知らなかったときより「へーこうやって動かすんだ」的な感想はあったと思います。

まだまだ教えたいことが沢山あります。
タイトル画面やリトライさせる方法、敵を複数出現させるやり方などなど。

これからも記事を書いていきます。
いっしょにゲームプログラミングを続けていきましょう。