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

2020年10月30日

今回もメモ帳だけで、HTMLとJavascriptを用いてゲームを作っていきたいと思います!

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


今回から作っていくもの

これから実際に作っていくゲームを発表したいと思います。

今回から作っていくゲームは…

ブロック崩しの例

ブロック崩しです!

見たこと聞いたことぐらいはあるかと思いますが、ボールを下にあるバーで動かし、ブロックをすべて壊せたらクリアのゲームです。

このゲームを選んだ理由は、このゲームを作ることが意外と簡単なためです。

このゲームを全五回に分けて作っていきますが、一回目は既に終わりましたね。

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

そして第二回は、上にも書いてある通り、ボールを作っていきたいと思います!


下準備

前回は、HTMLやJavascriptを使うための準備をしたのですが、もう少しだけ準備をしたいことがあるので先にそれをやっていきたいと思います。

前回作ったもののままでは、パソコンが正しくHTMLを認識しなかったり文字化けが起こってしまったりする可能性があるため、それを無くすためのコードを書きます。

<!DOCTYPE html>
<html>
  <head>
        <meta charset="utf-8">
        <title>Game</title>
  </head>
  <body>
    <canvas style="border:1px solid black"></canvas>
    <script>
    </script>
  </body>
</html>

赤色の文字の部分ですね!

<!DOCTYPE html>は、ブラウザにHTMLであることを認識させることができます
そして、<meta charset="utf-8″>で、文字コードを確定し、文字化けを起こさないようにしています。

(難しい単語ばかりなので理解しなくても大丈夫ですよ!)

そしてもう一つ!

<canvas width="500" height="800" id="canvas" style="border:1px solid black"></canvas>

と、canvasタグを少し変えましょう!一つ一つ説明していきますね。

まず、

widthとは日本語で「幅」なので、キャンバス(=ゲーム画面)の横の長さを指し、

それに対しheightは、「高さ」なのでキャンバスの縦の長さを指します。

今回は、500(px):800(px)にしているので、縦長の画面になるということですね!

今回はブロック崩しを作っていくため、縦長の画面にしましたが、自分の作るゲームに合わせた大きさにするとよいでしょう!

そして、idというのは、その名の通り、キャンバス(=ゲーム画面)にIDを振りました。

これは後でも説明しますが、ゲーム画面に何かを表示する際に、IDを使って指定するので、その時に必要になってきます。


今回必要になる知識

今回、実際にコードを書いていくうえで必要になってくる知識、プログラミング用語が2つほどあります。

まず一つ目に、変数です!
変数については別の記事で詳しく説明しましたので、そちらを参考にしてください!

【誰でもわかる!】変数とは

プログラミングの勉強を始めたときに最初に学ぶのが、「変数」と呼ばれるものです。 変数を知ることはプログラミングを知ることと同じといっても過言ではありません! この記事では、主にJavaScriptの変数について解説します […]

そして二つ目に、条件分岐です!
こちらについても別の記事で詳しく説明しましたので、こちらを参考にしてください!

【誰でもわかる!】条件分岐とは

プログラミングを勉強していく中でとても大事になってくるのが条件分岐です。ゲームでの当たり判定など条件分岐はとてもよく使われるものです! 今回は主にJavascriptの条件分岐について詳しく書いていきますが、ほかの有名な […]


コードを書いていこう!

先ほども書いた通り、第二回の今回は、ボールを作っていきます!

第一回や先ほどの下準備では、第一回でも説明した、HTMLというものを主にメモ帳に書いていました。

ですがこれからは、JavaScriptという、HTMLを動かすためのものを書いていきます。
全く別のものを作っていくことになるため、少し書き方がHTMLと変わってきますが、慣れていきましょう!


ゲーム画面の設定

まずは手始めに、JavaScriptがキャンバス(=ゲーム画面)がどこにあるかわかるように、先ほど指定したIDで教えてあげましょう。

<script>
  const CANVAS = document.getElementById("canvas");
  const CONTEXT = CANVAS.getContext("2d");
</script>

この二行を書き写しましょう!
(constの前のスペースは見やすくするために入れているもので、入れなくても大丈夫です!)

一行ずつ説明しますと…

const CANVAS = document.getElementById("canvas");

constは、変えることのできない変数ですね。

documentは「メモ帳」、getElementById(~)は「~とIDが付いたものを探す」といったものなので、
(「.」は日本語の「の」と訳すのが自然です。)

「メモ帳の中の"canvas"とIDが付いたもの」を「CANVAS」とする

といったところです。(あまりわからなくても大丈夫です。)

つまりこの行では、「CANVAS」をゲーム画面とする、といった解釈でOKです。

const CONTEXT = CANVAS.getContext("2d");

この行は、2Dともあるように、CANVAS(=ゲーム画面)を2Dの設定としたものを、CONTEXTとするといったところです。

おそらくこの2行が一番わかりずらいと思いますので、理解しようとしなくて大丈夫です(笑)


ボールを表示してみよう

ここでやっと本題に入れます!
まずは下の通りに入力してみましょう!

<script>
  const CANVAS = document.getElementById("canvas");
  const CONTEXT = canvas.getContext("2d");

  CONTEXT.beginPath();
  CONTEXT.arc(20, 20, 5, 0, 2 * Math.PI);
  CONTEXT.fill();
</script>

一行ずつ解説しますと…

CONTEXT.beginPath();

これは、ここからCONTEXT(≒ゲーム画面)に絵を描いていきますよ、といった指示です。

CONTEXT.arc(~);

これは、(~)のなかの情報をもとに円(や円弧)を書く指示です。

CONTEXT.fill();

書いた線を埋める(今回は初期設定の黒色で)といった指示です。

これでブラウザで確認してみましょう!
どうなりましたか?

下の画像のようになっているはず!

ではここで先ほど書いた3つの行の真ん中の値だけ変えてみましょう!

例えば…

CONTEXT.arc(100, 60, 30, 0, 2 * Math.PI);

のようにしてみましょう!
(数字以外は変えないでください!)

するとどうなりましたか?

上の例のようにしたのなら下の画像のようになっているはずです。

括弧の中の数字を変えるとどのようになるか試してみるとよくわかると思いますが、数字はこのような意味を持っています。

arc(x座標, y座標, 半径r, 0, 2 * Math.PI);

そしてx座標とy座標、半径r
(半径は英語でradiusなので頭文字のrとします!)
はこのようになっています!


つまりx座標を大きくすればするほど右に行き
y座標を大きくすればするほど下に行き
半径rを大きくすればするほど円が大きくなります

中学校で座標について習いますが、y軸が逆だったり少し違った点もありますが慣れましょう!

いろいろ数字を変えてまた試してみましょう!


ボールを動かすための準備

今のままでももちろんいいのですが、ボールを動かすときに便利にするために少しコードを、変数を使ってすこし変えてみましょう!

下のように変えてみましょう

const CANVAS = document.getElementById("canvas");
const CONTEXT = CANVAS.getContext("2d");

canvas_width = 500;
canvas_height = 800;

ball_speed_x = 1;
ball_speed_y  = 1;

let ball_x = 100;
let ball_y = 60;
let ball_r = 30;

CONTEXT.beginPath();
CONTEXT.arc(ball_x, ball_y, ball_r, 0, 2*Math.PI);
CONTEXT.fill();

canvas_widthとcanvas_heightは自分が設定した値を入れましょう!

ball_speed_x,yは、名前の通り、ボールを動かす際のボールのスピードです!

変数を使っただけで、やっていることは先ほどと変わりませんね。

変数をここで設定しておくことで、あとから「座標ってどこを変えたらいいっけ」となったときや、「canvas(=ゲーム画面)の高さっていくつだっけ?」となったときなどに分かりやすくなります!


ボールを動かしてみよう!

先ほどはゲーム画面にボールを表示しただけですが、これからは実際にボールを動かしてみましょう!

ボールを動かすには、皆さんが今までで一度はやったことがある方式を使います。

それはパラパラ漫画です。

一枚一枚絵をかきそれをつなげることによって動いているかのように見せる方法ですね!

これを今回は一個のゲーム画面上で行います!

つまり、

画面を消して、画面に移動後のボールを表示する

ということをひたすら繰り返します!

繰り返すためには、setIntervalというものを使います!

これは何秒に一回仕事を行うといったもので、これを使い上の仕事を繰り返してもらいます!

下のコードを真似して書いて見ましょう

…
ball_r = 30;

setInterval(function(){
  CONTEXT.clearRect(0, 0, canvas_width, canvas_height);

  CONTEXT.beginPath();
  CONTEXT.arc(ball_x, ball_y, ball_r, 0, 2 * Math.PI);
  CONTEXT.fill();
},30);

一番大きい括弧で囲っている、setIntervalは先ほども説明した通り、繰り返し処理をしてもらうためにあり、つまりパラパラ漫画にするためのものだと思ってもらってOKです!

CONTEXT.clearRect(0, 0, canvas_width, canvas_height);

は、端から端まで消す処理です。
つまり、書いてあるボールを消して真っ白に戻すということですね。

これで実行してみると、どうなりましたか?

結論からいうと先ほどとあまり何も変わりません!

まだ動かすという処理を入れていないため、同じ場所にずっとボールが表示されています!

つまり、「画面を真っ白に戻して、同じ位置にボールを表示する」ということを連続して行っているので、まるで同じ場所にずっとボールがあるようにみえます

では次にボールが動くように、先ほど作ったball_speed_x,yを使いましょう!

CONTEXT.clearRect(0, 0, canvas_width, canvas_height);

ball_x = ball_x + ball_speed_x;
ball_y = ball_y + ball_speed_y;

CONTEXT.beginPath();
CONTEXT.arc(ball_x, ball_y, ball_r, 0, 2 * Math.PI);
CONTEXT.fill();

こうすることで、ボールを表示する前に、ball_speed_x,yの分だけ移動します!
これでブラウザで確認してみましょう!

ボールが動いたはずです!

ですが壁をすり抜けてしまいますね。
つまりあとは壁にぶつかったら、跳ね返るようにすればいいだけですね!

少し詳しく…

少し詳しく説明すると…

CONTEXT.clearRect(~);
画面を消す

ballt_x,y = ball_x,y + ball_speed_x,y;
ここでボールの位置を、例えばもともと(100,100)にあったら、1ずつ足すので、(101, 101)にする。

CONTEXT.arc(~);
ボールを表示する

ということをすごく高速で行っています。

実際にはボールは、消されて、1だけ動いて、また表示される、ということを繰り返しているだけなのですが、人の目から見ると、パラパラ漫画のように動いているように見えますね!


ボールを跳ね返らさせる

ここからはボールを跳ね返すコードを組んでいくのですが、その前に、ボールが跳ね返る時に、ボールがどこにあればいいかを考えてみましょう!

ボールの座標は、黄色い点で示した通り、ボールの真ん中にあるため、一番右よりrだけ左にありますね。

つまり、ボールのx座標が、「ゲーム画面の横の幅 – 半径」より右に行こうとしている時に左に跳ね返らせる処理をすればよいのです。

これを条件分岐、if文で書いてみると…

if (canvas_width – ball_r < ball_x + ball_speed_x) {
  跳ね返る処理;
}

といった形になります!

跳ね返る処理は、進むスピードが今、1なので、-1にすればうまくいきそうですね。
なので、if文を使い下の通りに変えてみましょう

…
CONTEXT.clearRect(0, 0, canvas_width, canvas_height);

if ( canvas_width - ball_r < ball_x + ball_speed_x) {
  ball_speed_x = - ball_speed_x;
}

ball_x = ball_x + ball_speed_x;
…

これで動かしてみましょう!

(ボールが遅いと思ったら、ball_speed_x,yを5とかに変えましょう!つまり最初の、let ball_speed_x = 1; を let ball_speed_x = 5; にすればよいですね!)

これでおそらく右の壁には反射するようになったでしょう!

だけど跳ね返っても下の壁をすり抜けてしまいますね。

では次は下の壁に反射するようにしましょう!

…
CONTEXT.clearRect(0, 0, canvas_width, canvas_height);

if ( canvas_width - ball_r < ball_x + ball_speed_x) {
  ball_speed_x = - ball_speed_x;
}

if ( canvas_height - ball_r < ball_y + ball_speed_y) {
  ball_speed_y = - ball_speed_y;
}

ball_x = ball_x + ball_speed_x;
ball_y = ball_y + ball_speed_y;
…

先ほどのものを、y座標にしたり、width(=横幅)をheight(=高さ)に変えたりするだけですね!

これで動かしてみましょう!

これで下の壁にも反射するようになりました!

では次の左の壁の反射は自分で考えてみましょう!

ヒントは下の画像です!

ボールが左の壁に当たったときにボールの真ん中(黄色い点)の位置はどこになるでしょうか?

答えは下の通りです

…
CONTEXT.clearRect(0, 0, canvas_width, canvas_height);

if ( canvas_width - ball_r < ball_x + ball_speed_x) {
  ball_speed_x = - ball_speed_x;
}

if ( canvas_height - ball_r < ball_y + ball_speed_y) {
  ball_speed_y = - ball_speed_y;
}

if ( 0 + ball_r > ball_x + ball_speed_x){
  ball_speed_x = - ball_speed_x;
}

ball_x = ball_x + ball_speed_x;
ball_y = ball_y + ball_speed_y;
…

先ほどと違って左側になると+と-が逆になる部分がありますが、基本的にはあまり変わらないですね!

さて最後は上の壁ですが、こちらは簡単ですね!

…
CONTEXT.clearRect(0, 0, canvas_width, canvas_height);

if ( canvas_width - ball_r < ball_x + ball_speed_x) {
  ball_speed_x = - ball_speed_x;
}

if ( canvas_height - ball_r < ball_y + ball_speed_y) {
  ball_speed_y = - ball_speed_y;
}

if ( 0 + ball_r > ball_x + ball_speed_x){
  ball_speed_x = - ball_speed_x;
}

if ( 0 + ball_r > ball_y + ball_speed_y){
  ball_speed_y = - ball_speed_y;
}

ball_x = ball_x + ball_speed_x;
ball_y = ball_y + ball_speed_y;
…

これですべての壁に反射して、永遠にボールが動き続けるゲームが完成しました!

思っている通りに動くと嬉しいですよね!

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

次回は、自分が操作できるバーを作ってボールを打ち返すコードを組んでいきたいと思います!

またまた長くなってしまいましたが、

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

第三回はこちらから!


もしうまくいかなかったら自分が書いたものを見返してみましょう!
もしかしたら打ち間違いがあるかもしれません!

それでもうまくいかなければ…
「この下にあるコメントを残す」からコメントをしていただくか、ただの大学生のTwitterにご連絡ください!

Twitter開設しました!

ただの大学生のブログが更新されたときや、様々な情報を載せるためのTwitterを開設しました!ブログの裏側を載せたり、読者の方の質問に応えたりします! TwitterのIDはこちらです。@Daigakusei_blog […]