ブロック表示と当たり判定

ブロックを表示する

ボールとパドルができたので、次はブロックです。
とりあえず1列だけ表示してみます。
次のプログラムをボール処理の下に追加します。

<script>
    // ブロック
    function initBlock() {
        for( let i=0; i<8; i++ ){
            Crafty.e("Block, 2D, Canvas, Color")
                .color('#00ff00')
                .attr({x:1+i*50, y:50, w:48, h:30});
        }
    }
    initBlock();
</script>

 

実行すると次のようになります。

ブロックを1列表示する

ところで何気なく関数initBlockを作りました。
関数にしなくても良かったのですが、ブロックの処理をまとめたかったのでこうしました。

 

さて次は、ブロックに色を付けて4列にしてみます。

<script>
    // ブロック
    function initBlock() {
        const col = ["red","orange","green","blue"];
        for( let j=0; j<4; j++){
            for( let i=0; i<8; i++ ){
                Crafty.e("Block, 2D, Canvas, Color")
                    .color(col[j])
                    .attr({x:1+i*50, y:50+j*30, w:48, h:25});
            }
        }
    }
    initBlock();
</script>

 

実行してみましょう。

ブロックを1列表示する

もうすっかりブロック崩しになりましたね。

.attr({x:1+i50, y:50+j30, w:48, h:25});

座標y も計算するようになりました。
計算の意味が分からないときは、数値を変えてテストするといいです。
例えばy:50+j*40で実行すれば30が何の数なのか分かります。

ブロックの高さをh:30からh:25にしています。
これで見た目のバランスが良くなりました。

 

.color(col[j])

配列を使って色を指定しています。
(配列の説明はあとで)
これまではcolor(’#00ff00’)のように色コードを使っていましたが
color(“orange”)という感じで英語でもOKです。
ただ対応しているのはメジャーな色だけです。

 

 

配列とconst

配列とは簡単にいうと、複数の変数を1つの名前で管理できるものです。
ただ、変数にはない機能があります。
詳しく知りたい人はjavascript 配列などで検索してみましょう。

 

次のように console.log を3行追加して実行してみます。

<script>
    function initBlock() {
        const col = ["red","orange","green","blue"];
        console.log(col);
        console.log("col[0]="+col[0]);
        console.log("col[2]="+col[2]);
        for( let j=0; j<4; j++){
            for( let i=0; i<8; i++ ){
                Crafty.e("Block, 2D, Canvas, Color")
                    .color(col[j])
                    .attr({x:1+i*50, y:50+j*30, w:48, h:25});
            }
        }
    }
</script>

 

コンソールを見てみると次のように表示されます。

配列とは何か

配列 col の中に4つの色が入っていることが分かります。
配列 col は次の行で作られました。
const col = [“red”,“orange”,“green”,“blue”];

配列の内容を参照するには角かっこに数値を入れます。
col[0]とすれば先頭(red)を参照できます。
col[2]とすれば3番目(green)の参照です。
角かっこの中の数は0から始まることに注意してください。

ざっくりと説明しましたが、これは基礎の基礎です。
また別のときに説明したいと思います。

 

const についてちょっと説明します。

const col = [“red”,“orange”,“green”,“blue”];

これは配列の宣言でしたね。
実は次のように宣言することも可能です。

let col = [“red”,“orange”,“green”,“blue”];

let はこれまでも使ってきました。
この2つの違いは const の場合は変更不可。
let の場合は変更可能ということです。

 

const は配列専用という訳ではありません。
let で変数を作っていたように const でも作れます。
例えば const ENEMY_MAX = 50; というように宣言をして
プログラム中で ENEMY_MAX を使えば処理内容が分かり易くなります。

 

 

ブロックとの当たり判定

作業の前に、先ほど追加した console.log を消しましょう。

ボールとブロックの当たり判定を入れます。
判定はボールで行います。

<script>
    // ボール
    Crafty.e("Ball, 2D, Canvas, Color, Collision")
        .color('#eeeeee')
        .attr({x:100, y:200, w:10, h:10, 
               dX:Crafty.math.randomInt(2,5), dY:5 })
        .onHit('Paddle', function () {  // パドルに当たったらy軸の方向転換
            this.dY *= -1;
        })
        .onHit('Block', function (hitDatas) {  // ブロックに当たったら
            this.dY *= -1;
            console.log("block len="+hitDatas.length);
            // 複数のブロックに当たったときを考慮して全部調べる
            for( let i=0,l=hitDatas.length; i<l; i++ ){
                hitDatas[i].obj.destroy();
            }
        })
        .bind('EnterFrame', function () {
            if (this.x <= 0 || this.x >= 390){   // 画面の左右に当たれば跳ね返る
                this.dX *= -1;
            }
            if (this.y < 10) {  // 上の壁
                this.dY *= -1;
            }
            if (this.y > 380) { // 下の壁
                this.dY *= -1;
            }
            this.x += this.dX;
            this.y += this.dY;
        });
</script>

 

追加したところを見てみましょう。

ボールとブロックの当たり判定を入れる

当たり判定とボールの処理は Paddle のときと同じです。
this.dY *= -1;でボールの向きを変えています。

注目ポイントは hitDatas.length で複数のブロックと同時に当たったかを調べている点です。
そして、当たったブロックは次の行で消しています。

hitDatas[i].obj.destroy();

 

実行してみましょう。

ボールとブロックの当たり判定を入れる

うーん、ブロック崩しっぽい(笑)
ちゃんとブロックを消しています。

 

console.log(“block len="+hitDatas.length);

これで当たったブロックの数を表示しています。
コンソールで確認してみましょう。

ボールとブロックの当たり判定を入れる

ほとんど1つずつ当たっていますね。
ときどき2つ同時に当たることもあるようです。

 

 

ブロックの再配置

すべてのブロックを消したとき、再びブロックを表示します。

ブロックの数をカウントするための変数blockcntを作りました。
これが0のとき再配置します。

<script>
    let blockcnt = 0;
    // ボール
    Crafty.e("Ball, 2D, Canvas, Color, Collision")
        .color('#eeeeee')
        .attr({x:100, y:200, w:10, h:10, 
               dX:Crafty.math.randomInt(2,5), dY:5 })
        .onHit('Paddle', function () {  // パドルに当たったらy軸の方向転換
            this.dY *= -1;
            if( blockcnt == 0 ){
                initBlock();    // ブロックの再配置
            }
        })
        .onHit('Block', function (hitDatas) {  // ブロックに当たったら
            this.dY *= -1;
            console.log("block len="+hitDatas.length);
            // 複数のブロックに当たったときを考慮して全部調べる
            for( let i=0,l=hitDatas.length; i<l; i++ ){
                hitDatas[i].obj.destroy();
                blockcnt--;
            }
        })
        .bind('EnterFrame', function () {
            if (this.x <= 0 || this.x >= 390){   // 画面の左右に当たれば跳ね返る
                this.dX *= -1;
            }
            if (this.y < 10) {  // 上の壁
                this.dY *= -1;
            }
            if (this.y > 380) { // 下の壁
                this.dY *= -1;
            }
            this.x += this.dX;
            this.y += this.dY;
        });
    // ブロック
    function initBlock() {
        const col = ["red","orange","green","blue"];
        for( let j=0; j<4; j++){
            for( let i=0; i<8; i++ ){
                Crafty.e("Block, 2D, Canvas, Color")
                    .color(col[j])
                    .attr({x:1+i*50, y:50+j*30, w:48, h:25});
                blockcnt++;
            }
        }
    }
</script>

 

変更点を見てみましょう。4つあります。

ブロックが全てなくなったら再配置する

処理は単純です。
変数blockcntでブロックの存在を確認します。
ブロックを表示するとき数を加え、消すときに引いていきます。

ボールがパドルに当たったときブロックが無ければ再配置します。
なぜこのタイミングかというと、ボールとブロックが一番離れた状態だからです。
ブロックがすべて消えたタイミングで再配置すると、連続してブロックを消す可能性があります。

 

 

『平凡ブロック崩し』

ゲームを作ってみよう

  1. 平凡ブロック崩しに挑戦
  2. パドル操作とボール移動
  3. 表示と当たり判定
  4. スコアとゲームオーバー