
純粋なJavascriptでのブロック崩しの作り方②
やりたいこと
フレームワークやライブラリを使わず、純粋な javascript のみでブロック崩しを作る。
今回は第 2 回目となり、ボールを実際に動かすところまでやってみます!
前回は初期設定から図形の描画までを行いました ↓
Canvas で図形を動かす処理の基本は、画面を連続的に更新して図形の位置を変えることで実現出来ます。
さっそく動かしてみましょう!
環境
- Google Chrome : Version: 130.0.6723.92
- VSCode : Version : 1.90.2 (Universal)
繰り返し呼ばれる関数を定義する
Cnvas を毎フレーム、定期的に更新するには何度も実行される関すを定義する必要があります。
Javascript のタイミング関数の setInterval()や requestAnimationFrame()を用いれば、同じ関数を何度も実行できます。
今回は requestAnimationFrame()を使っていきます。
まず、前回コードにかいた javascript のコードを最初の 2 行意外は削除してあげます。
こちらのコードだけになったかと思います ↓
// canvas を要素取得
const canvas = document.getElementById("canvas");
// 2D で描画できるようにする
const ctx = canvas.getContext("2d");
次にこのコードの下に、このようなコードを追加して見てください。
// draw 関数を定義
function draw() {
// 描画コード
console.log("Hellow World!"); // コンソールログ
requestAnimationFrame(draw); //1秒間に約 60 回呼ぶ
}
// アニメーションを開始
draw();
右クリックから検証を押し、コンソールログを開いてみてください。
1 秒間に約 60 回ログが呼び出されてるのが分かります。
ではコードの解説をしていきます。
function draw() {}で関数を定義できます。draw の部分はお好きな名前でも構いませんが、分かりやすい名前にしておくと良いでしょう。
console.log(“Hellow World!”);は’("")の中にお好きな文字列を指定すると、それがコンソール画面に表示されます。
requestAnimationFrame(draw);は 1 秒間に約 60 回、()の中に指定した関数を実行してくれます。
今回の場合は draw 関数の中で自分自身を呼び出してあげることで、私たちが止めるまでこの関数は実行されることになります。
requestAnimationFrame();の良いところはブラウザ側で最適なタイミングで呼び出されることです。
これにより、カクつきや負荷の高い処理が軽減され、スムーズなアニメーションが実現できます!
最後に関数は定義しただけでは実行されないので、一度呼び出してあげる必要があるので、draw();で関数を実行してあげます。
ボールを動かす
まず、ボールを動かすには当たり前ですが、ボールを描画してあげる必要があります。
円の描画は前回使用したコードで描画できますね!
ctx.beginPath();
ctx.arc(50, 50, 10, 0, Math.PI \* 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
これをそのまま draw 関数の中に追加していきましょう、と言いたいところですが、ボールの X 座標や Y 座標には変数を使うことで、汎用性や可読性が高まり、より良いコードになるでしょう!
次のようにします ↓
//ボールの座標
let x = canvas.width / 2;
let y = canvas.height - 30;
// draw 関数を定義
function draw() {
ctx.beginPath(); // 新しいパスを開始
ctx.arc(x, y, 10, 0, Math.PI \* 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath(); // パスを終了
requestAnimationFrame(draw); //1秒間に約 60 回呼ぶ
}
canvas.width / 2 というのは指定していた canvas のの半分、今回は 300px の正方形で作成してるので、ボールの X 座標は原点から 150px の地点、つまり真ん中を指定しています。
同様の考え方でいくと、Y 座標は 300px から 30px を引いてるので、canvas の一番下から 30px、上に指定してあげてます。
下記のように表示されたかと思います。
この時点でボールは最描画され続けてますが、動きがないので分かりませんね。
次はボールに動きを加えてきましょう!
draw 関数の中身を次のように書き換え、新たに移動量の変数を定義して見てください。
//ボールの座標
let x = canvas.width / 2;
let y = canvas.height - 30;
// 移動量
let dx = 2;
let dy = -2;
// draw 関数を定義
function draw() {
ctx.beginPath(); // 新しいパスを開始
ctx.arc(x, y, 10, 0, Math.PI \* 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath(); // パスを終了
//決めていた値を足す
x += dx;
y += dy;
requestAnimationFrame(draw); //1秒間に約 60 回呼ぶ
}
下記の画像のように動いたかと思います ↓
dx と dy は delta(変化量)の略です。
x += dx;は draw 関数が呼ばれるたびに、x 座標に dx の値を足すという処理です。
y 座標も同様です。
しかし、現在のコードのままでは前回描画されたボールの軌跡が残ってしまってます。
これを改善するには、draw 関数が呼ばれるたびにボールの描画を消す処理を追加する必要があります。
draw 関数の最初に以下のように clearRect メソッドを追加して見てください!
// draw 関数を定義
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // パスを削除
ctx.beginPath(); // 新しいパスを開始
ctx.arc(x, y, 10, 0, Math.PI \* 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath(); // パスを終了
//決めていた値を足す
x += dx;
y += dy;
requestAnimationFrame(draw); //1秒間に約 60 回呼ぶ
}
無事前回の描画の軌跡が消え、ボールが動いてるかのように見えるようになったかと思います ↓
追加した clearRect メソッドは 4 つの引数を取ります。
四角形の左上端の X、Y 座標と、四角形の右下端の X、Y 座標です。
この四角形で囲われた領域にある内容全てが消去されます。
つまり、ctx.clearRect(0, 0, canvas.width, canvas.height)は Canvas 内の全ての内容が消去されるということですね!
コードを整える
機能自体は完成しましたが、これから draw 関数の中には様々なコードを追加していくので、コードを整える作業をしていきます。
先程のボールを描く処理を別の場所で関数として定義しておいて、それを draw 関数で呼ぶようにします。
次にのようになります。
// ボールを描く関数
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI \* 2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
// draw 関数を定義
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height); // パスを削除
drawBall();
//決めていた値を足す
x += dx;
y += dy;
requestAnimationFrame(draw); //1秒間に約 60 回呼ぶ
}
どうでしょうか? draw 関数内では drawBall();の 1 行で済み、スッキリしたかと思います!
今回は以上です。お疲れ様でした! 次回は実際にボールを壁で弾ませる処理を書いていきたいと思います。
参考
出典: Mozilla Contributors. “純粋な JavaScript を使ったブロック崩しゲーム”. MDN Web Docs.

この内容は、Creative Commons Attribution-ShareAlike (CC-BY-SA) 2.5(またはそれ以上)のライセンスのもとで公開されています。