/
純粋な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(またはそれ以上)のライセンスのもとで公開されています。