【初心者向け】第四回 メモ帳だけでゲーム作ってみた〈ブロック崩し編〉

2020年8月30日

今回もメモ帳だけで、HTMLとJavaScriptを用いてブロック崩しを作っていきたいと思います!

今回でゲームの大半が完成するので、面白くなってくると思います!

今までの3回をまだ読んでいない方はそちらを先に読んでください!


今回作るもの

  1. 準備編
  2. ボールを作ろう!
  3. 動くバーを作ろう! ←前回
  4. ブロックを作ろう! ←今回
  5. 完成させよう!

前回の第三回には、操作ができるバーを作りました!

そして今回は、ボールを当てると壊せるブロックを作っていきたいと思います!

完成イメージは以下の画像の通りです!

ブロックはボールが当たると消えるようにします!

そしてブロックの位置は、後で自分の好きなように設定できるようにしますので、様々なステージを作ってみてもいいですね!


今回必要になる知識

今回もコードを書いていく上であったほうがいい知識があります。

それは、配列繰り返しです!

どちらも別の記事に詳しく解説をまとめたので、下のリンクを参照してください!

【誰でもわかる!】配列とは

皆さんは「配列」という言葉を聞いたことはありますか? プログラミングを学習していくうえで、たまに使う程度かもし…


コードを書いていこう!

変数を作る

まず初めに、ブロックを作っていく際に必要になる変数を作っていきましょう!

変数の中には、多次元配列もあります!

…
let bar_speed = 10;

let block = [
  [30, 50, false],
  [130, 50, false],
  [230, 50, false],
  [330, 50, false],
  [430, 50, false],
  [30, 100, false],
  [130, 100, false],
  [230, 100, false],
  [330, 100, false],
  [430, 100, false],
  [30, 150, false],
  [130, 150, false],
  [230, 150, false],
  [330, 150, false],
  [430, 150, false],
  [30, 200, false],
  [130, 200, false],
  [230, 200, false],
  [330, 200, false],
  [430, 200, false]
];

let block_width = 40;
let block_height = 40;

let left_pressed = false;
…

ブロックの場所を配列にしまいました!
(配列の「,」を最後につけないように気を付けましょう!)
そして、blockの配列についている、「false」というのは、ブロックが壊れたときには「true」に設定します。

なので、「false」はブロックがまだ壊されていない、「true」は既にブロックが壊されているという状態です!

下2つの、block_width, heightは名前の通り、ブロックの横幅と縦幅を決めています。

今回は正方形にしましたが、形を変えたい方はここをいじりましょう!


ブロックを表示させる

まずはブロックを表示させる用の関数を作りましょう!

setInterval(function(){
  eraseCanvas();
  drawBar();
  drawBall();
  drawBlock();
},30);

function eraseCanvas() {
…
}

function drawBar() {
…
}

function drawBall() {
…
}

function drawBlock() {

}

あとは、ブロックを描かせる処理を、関数drawBlockの中に書いていけばいいですね!

なので、前回も使ったfillRect(=四角形を描く)を使ってブロックを表示させましょう!

ブロックの位置は、blockという多次元配列にしまったので、

CONTEXT.fillRect(block[0][0], block[0][1], block_width, block_height);
CONTEXT.fillRect(block[1][0], block[1][1], block_width, block_height);
CONTEXT.fillRect(block[2][0], block[2][1], block_width, block_height);
…

上のようにブロック一つ一つ書いていってもいいのですが、せっかく繰り返しを学んだので、使ってみましょう!

つまりこうなります!

function drawBlock() {
  for (let i = 0; i < block.length; i++) {
      CONTEXT.fillRect(block[i][0], block[i][1], block_width, block_height);
    }
}

forの中の括弧の中の意味を確認しましょう!

for (繰り返しの最初は、i = 0; i が配列「block」の長さ(今回は20になります)未満で繰り返す; iは1増やして繰り返す)

block.lengthといった、配列の長さを使うコードは意外と多いので、少しずつ慣れていきましょう!

あとはブロックが壊れたとき(=「true」になったとき)には表示させないので、最後にif文を使って…

function drawBlock() {
  for (let i = 0; i < block.length; i++) {
    if (block[i][2] == false) {
      CONTEXT.fillRect(block[i][0], block[i][1], block_width, block_height);
    }
  }
}

のようにすればいいですね!

これで、ブロックが壊れていないとき(=「false」のとき)だけブロックを表示させるコードができました!


当たり判定を作る

さて、最後にボールとブロックの当たり判定を考えてみましょう!

たくさんのブロックがありますが、まずは、配列の一つ目に入っているブロックの当たり判定だけ考えましょう!

まずは左の壁に当たった時を考えましょう!

前回と同じ通り、x座標をまず考えると…

「ball_x + ball_r >= ブロックの左側」かつ「ball_x <= ブロックの左側」

になりますね!

今度はy座標について考えて行くと…

「ball_y >= ブロックの上側」かつ「ball_y <= ブロックの下側」

になりますね!

これらを組み合わせると…

if (ball_x + ball_r >= block[0][0] && ball_x <= block[0][0] ) {
  if (ball_y >= block[0][1] && ball_y <= block[0][1] + block_height) {

   }
}

となります!

後は壁に当たったときに跳ね返らさせるために、

ball_speed_x = - ball_speed_x;

とします!

そして当たったことで、「false」から「true」に変えないといけないですね!

block[0][2] = true;

を入れればOKですね!

最後に、ブロック壊れている(=「true」の時)には当たり判定はチェックしなくていいので…

すべて合わせて…

  if (block[0][2] == false) {
    if (ball_x + ball_r >= block[0][0] && ball_x <= block[0][0] ) {
      if (ball_y >= block[0][1] && ball_y <= block[0][1] + block_height) {
        block[0][2] = true;
        ball_speed_x = - ball_speed_x;
      }
   }
}

後はこれをforループですべてのブロックで当たっているか確認させましょう!

for (let i = 0; i < block.length; i++) {
    if (block[i][2] == false) {

      if (ball_x + ball_r >= block[i][0] && ball_x <= block[i][0] ) {
        if (ball_y >= block[i][1] && ball_y <= block[i][1] + block_height) {
          block[i][2] = true;
          ball_speed_x = - ball_speed_x;
        }
      }
    }
  }

これをdrawBallの中の壁の跳ね返りのコードの後に書きましょう!

さてこれで左の壁の当たり判定ができたので、あとは右の壁下の壁上の壁の判定を作りましょう!

答えは下のコードですが、少し考えてから下を見ましょう!

…
 if ( 0 + ball_r > ball_y + ball_speed_y){
    …
  }

  for (let i = 0; i < block.length; i++) {
    if (block[i][2] == false) {

      if (ball_x + ball_r >= block[i][0] && ball_x <= block[i][0] ) {
        if (ball_y >= block[i][1] && ball_y <= block[i][1] + block_height) {
          block[i][2] = true;
          ball_speed_x = - ball_speed_x;
        }
      }

      if (ball_x >= block[i][0] + block_width && ball_x - ball_r <= block[i][0] + block_width) {
        if (ball_y >= block[i][1] && ball_y <= block[i][1] + block_height) {
          block[i][2] = true;
          ball_speed_x = - ball_speed_x;
        }
      }

      if (ball_y + ball_r >= block[i][1] && ball_y <= block[i][1] ) {
        if (ball_x >= block[i][0] && ball_x <= block[i][0] + block_width) {
          block[i][2] = true;
          ball_speed_y = - ball_speed_y;
        }
      }

      if (ball_y >= block[i][1] + block_height && ball_y - ball_r <= block[i][1] + block_height) {
        if (ball_x >= block[i][0] && ball_x <= block[i][0] + block_width) {
          block[i][2] = true;
          ball_speed_y = - ball_speed_y;
        }
      }

    }
  }

  ball_x = ball_x + ball_speed_x;
…

これでボールが当たると表示されなくなるブロックのコードが完成しました!


ということで第四回はここまでにしたいと思います!

もしうまくいかなければ、自分が書いたコードを見直しましょう!
それでもうまくいかなければ、コメントやTwitterにご連絡ください!

今回でゲームの基本はほとんど完成しましたので、次回が最終回です!

次回は、今のブロック崩しにもう少しゲーム性を与えていきたいと思います!

それでは、最後まで読んでいただきありがとうございます!

第五回はこちらからどうぞ!