【中級者向け】第四回 メモ帳だけでゲーム作ってみた〈ぷよぷよ編・続〉

今回も前回までと同様に、メモ帳だけを使ってぷよぷよを作っていきたいと思います!

前回の記事をまだ読んでいない方は、是非そちらを先に読んでください!


今回作るもの

前回は、設置する前にぷよを動かせるようにしましたね!

  1. 落ちる場所を表示しよう!
  2. 壁にぶつかっている状態でも回転できるようにしよう!
  3. 設置する前にすこし動かせるようにしよう! ←前回
  4. スコアを表示しよう! ←今回
  5. コードをまとめてきれいにしよう!

そして今回は、ぷよぷよのスコアを計算して、上に表示できるようにしていきたいと思います!

完成イメージは以下の通りです。

ぷよぷよの本家通りの計算で得たスコアを上に表示するようにしています!

是非最後まで読んでみて下さい!


コードを書いていこう!

ではさっそくコードを書いていきましょう!

今回は、スコアを計算していくので、例えば消えてるぷよの個数などを今までのコードの様々な場所に追加していくので、間違えないようにしましょう!


ぷよぷよの得点計算について

ぷよぷよの得点計算方法については、ぷよぷよ用語辞典というサイトを参考にして進めていきたいと思います。

得点計算 – ぷよぷよ用語辞典

こちらによりますと、

消したぷよの個数×(連鎖ボーナス+連結ボーナス+色数ボーナス)×10

で求められるようです。

詳しい解説は省略いたしますので、ご自身でどのような計算方法なのか確認しておきましょう。


変数を作る

ではまず初めに、今回必要な変数を作りましょう。

計算途中に必要な変数や、計算する際に必要な変数などが様々ありますので、気を付けましょう!

let rensa_finish = true;
let total_score = 0;
let score = 0;

let rensa_bonus = [0, 8, 16, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 480, 512];
let renketsu_bonus = [0, 2, 3, 4, 5, 6, 7, 10];
let irokazu_bonus = [0, 3, 6, 12, 24];

let erased_number = 0;
let rensa = 0;
let max_renketsu = 0;
let irokazu_array = [0, 0, 0, 0];

let renketsu = 0;

いろいろとあってややこしいですが、一番上の「score」がついているものは得点を、真ん中の「bonus」がついているものには計算に必要な数字を、そして下にある4つの変数は計算する際に必要な変数となっています。

名前などは適時自分の分かりやすいものに変更しておいてもいいですね。


スコアを表示させる場所を作る

では次にスコアが表示される場所を作っていきましょう。

これは第一回で作って以降全く触ってこなかった、「HTML」の部分を少し変更していきます!

<center>
  <div id="score">0</div>
  <canvas width="400" height="600" id="canvas" style="border:1px solid black"></canvas>
</center>

最初は得点は0点なので「0」と入力しておきましょう。

また、「score」というIDを振ったので、あとでこの中の数字を変えたければこのIDを使って場所を指定することが出来るようになります。


ぷよが置かれ新しいぷよが出現するときに変数を初期化する

ではまず、ぷよが置かれて次のぷよが出現するときに、「rensa」という変数を元に戻すコードを追記します。

function nextPuyo() {
  color = next_puyo;
  next_puyo = next_next_puyo;
  next_next_puyo = [Math.floor(Math.random() * 4 + 1), Math.floor(Math.random() * 4 + 1)];

  position = [2, 1];
  child = [0, -1];
  direction = 90;
  counter = 0;

  rensa = 0;
}

ぷよが消える処理の時にぷよの個数や色の数を調べる

では次に、ぷよが消える処理の時(=連鎖中)に何個の連結でぷよが消えているのか、何色のぷよが消えたのかを調べるコードを書いていきます。

消えるぷよを調べるのは「erasePuyo」という関数にあるので、そこの中にいくつかコードを足していきます。

function erasePuyo() {
  rensa_finish = true;

  for (let i = 0; i < 12; i++) {
    for (let j = 0; j < 6; j++) {
      flag_field[i][j] = 0;
    }
  }

  for (let i = 0; i < 12; i++) {
    for (let j = 0; j < 6; j++) {
      if (flag_field[i][j] == 0) {
        if (field[i][j] == 0) {
          flag_field[i][j] = 1;
        } else {
          renketsu = 1;
          flag_field[i][j] = 3;
          let check_color = field[i][j];

          checkUp(j, i - 1, check_color);
          checkDown(j, i + 1, check_color);
          checkLeft(j - 1, i, check_color);
          checkRight(j + 1, i, check_color);

          if (renketsu >= 4) {
            for (let i = 0; i < 12; i++) {
              for (let j = 0; j < 6; j++) {
                if (flag_field[i][j] == 3) {
                  flag_field[i][j] = 2;
                }
              }
            }
            rensa_finish = false;
            if (max_renketsu < renketsu) {
              max_renketsu = renketsu;
            }
            irokazu_array[check_color - 1] = 1;
          } else {
            for (let i = 0; i < 12; i++) {
              for (let j = 0; j < 6; j++) {
                if (flag_field[i][j] == 3) {
                  flag_field[i][j] = 1;
                }
              }
            }
          }
        }
      }
    }
  }

 …checkUp系は省略…

  let rensa_checker = false;
  for (let i = 0; i < 12; i++) {
    for (let j = 0; j < 6; j++) {
      if (flag_field[i][j] == 2) {
        field[i][j] = 0;
        erased_number++;
        if (rensa_checker == false) {
          rensa++;
          rensa_checker = true;
        }
      }
    }
  }
}

まず初めに追加されている部分は、34行目の部分ですね。

ぷよが連結している数の中で一番最大の数を数えないといけないので、max_renketsu(今まで調べてきた中での最大の個数)と比べて大きければ、その数を最大にするといった形にしています。

そして次に「irokazu_array」についてですが、ここでは、例えばチェックした色が赤だった場合は、赤は「1」番をあてていたので、配列の0番目に「1」が入りますね。

そして例えば、その連鎖中に消えた色が赤と黄色と緑だった場合には、その配列は「1, 1, 0, 1」というように消えた色の数だけ「1」が入るようになっています。

あとは消えた色の数を調べたければ、この配列の中に入っている「1」の個数を調べればOKですね。

そして次に、54行目からの部分が大きく変わっていますね。

消えたぷよの数を「erased_number」で数えながら、連鎖が起きているかを同時に調べていますね。

そして連鎖があるときには「rensa」という変数を1増やしています。

ここのコードは他のコードが出来上がってからでないと分かりづらい部分だと思うので、またあとで見返しましょう。


得点計算用の新しい関数を作る

次に、得点計算用の新しい関数を作り、ぷよが置かれたり連鎖した時に計算されるようにしましょう。

function checkField() {
  setTimeout(fallPuyo, 500);
  setTimeout(function(){
    erasePuyo();
    calculateScore();
    if (rensa_finish == true) {
      nextPuyo();
      stop = false;
    }else {
      setTimeout(checkField, 500);
    }
  }, 1000);
}
function calculateScore() {

}

得点計算のコードをこの「calculateScore」に書いていきます!


得点を計算する

では本題の得点を計算していきましょう。

連鎖数は「rensa」に、連結数は「max_renketsu」に、色数は「irokazu_array」に入っている「1」の数に、とすでにそれぞれは計算していますので、あとはこれに基づいて得点を計算すればいいですね。

function calculateScore() {
  if (max_renketsu > 0) {
    let irokazu = 0;
    for (let i = 0; i < 4; i++) {
      if (irokazu_array[i] == 1) {
        irokazu++;
      }
    }

    let a = rensa_bonus[rensa - 1];
    let b;
    if (max_renketsu >= 11) {
      b = renketsu_bonus[7];
    }else {
      b = renketsu_bonus[max_renketsu - 4];
    }
    let c = irokazu_bonus[irokazu - 1];

    if (a + b + c == 0) {
      a = 1;
    }
    score = erased_number * (a + b + c) * 10;

    total_score += score;
    score = 0;
    erased_number = 0;
    max_renketsu = 0;
    irokazu_array = [0, 0, 0, 0];
    document.getElementById("score").innerHTML = total_score;
  }
}

まず、連結が「0」(=連鎖してない)だと得点計算する意味がないので、if文で分けています。

そしてその次の「irokazu」に「irokazu_array」の中にある「1」の個数を数えて入れています。

あとは、「rensa_bonus」や「renketsu_bonus」、「irokazu_bonus」に得点計算用の数字を入れていたので、それをうまく取り出すようにして、

また、得点計算するときにボーナスが0点になった場合はボーナスを1点にするという決まりもあるので、それをif文で分けていますね。

得点の計算が終われば、必要な変数はもとの「0」にもどします。

最後の

document.getElementById("score").innerHTML = total_score;

このようなコードを書くのは、canvasの設定をして以来ですね。

「ドキュメント内の、「score」というIDがついたものの、中に、total_scoreを入れる」といった意味となっています。

もし、数字だけでなく「~点」と表示したければ、

document.getElementById("score").innerHTML = total_score + "点";

と「+」と「""」を使ってすることもできます。

これで完成です!


うまくいかなかった方向け

うまくいかなかった方は、まずエラーが出ていないか確認しましょう!

エラーの確認方法については、別の記事で詳しくまとめたので、ぜひそちらを参考にしてください!

それでもうまくいかなければ、下のサンプルコードをダウンロードして、自分のコードを比較してみましょう!


今回はここまで!

というわけで続編の第四回はここまでとしたいと思います!

次回は、最終回として、今まで書いてきたコードをまとめたり、ぷよぷよとして少し完成度を上げたりしたいと思います!

というわけで長くなってしまいましたが、

最後まで読んでいただきありがとうございました!

ご感想などあればコメントやTwitterにどしどしお寄せください!

第五回はこちらから!

第五回は製作中です。
もう少しお待ちください。