ボールを動かす
これはゲーム開発Canvasチュートリアル (en-US)の10ステップのうち2番目のステップです。このレッスンを終えたあとの完成予想のソースコードはGamedev-Canvas-workshop/lesson2.htmlで入手できます。
前回のレッスンを一通りこなしてみてボールの描き方が分かりました。では今回はそれを動かしましょう。技術的には、ボールを描画し、またそれを消してからほんの少し違う位置に描画し直すという処理を毎フレームずつ行うことで動いているような印象を生み出します。ちょうど映画がどのように動くのかと同じです。
描画ループを定義する
Canvasの映像を毎フレーム、定期的に更新し続けるためには、何度も実行されるような関数を定義する必要があります。この関数には画像の位置を変えたりするために毎回違う値が与えらます。setInterval()
やrequestAnimationFrame()
といったJavaScriptのタイミング関数を用いれば同じ関数を何度も実行できます。
HTMLファイル内に既に書かれているJavaScriptを最初の2行を除いて全て削除し、次のコードを追記してください。draw()
関数がsetInterval
の中で10ミリ秒おきに実行されます。
function draw() {
// 描画コード
}
setInterval(draw, 10);
無限に続く setInterval
の性質のため、draw()
は10ミリ秒おきにずっと、あるいは私達が止めるまで呼ばれ続けます。では、ボールを描画してみましょう。draw()
関数の中に下記のコードを追記してください。
ctx.beginPath();
ctx.arc(50, 50, 10, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
では、書き換えたコードを試してみましょう。ボールが毎フレーム再描画されるはずです。
ボール動かす
動きがないのでボールが再描画され続けていることに気づかないはずです。動きを加えてみましょう。まず、直書きされた位置 (50,50) のかわりに x
、y
という名の変数に開始位置を中央下端として定義し、それらを用いて円が描画される位置を定義します。
まず、x
とy
を定義するために自分の draw()
関数の上に次の2行を追加しましょう。
var x = canvas.width/2;
var y = canvas.height-30;
次に、arc()
メソッド内で変数xと変数yを使うようにdraw()
関数を書き換えましょう。次のハイライトされている行のとおりです。
function draw() {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
ここからが大事な部分です。x
とy
に毎フレーム描画した後に小さな値を加え、ボールが動いているように見せるのです。その小さな値をdx
、dy
として2、-2をそれぞれ設定しましょう。変数x、yの定義のあとに次のコードを追記してください。
var dx = 2;
var dy = -2;
最後に残っていることがあります。フレームごとにx
とy
を変数dx
、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;
}
コードを保存してください。問題なく動作しますが、ボールの軌跡が残ります。
フレームの後にCanvasを消去する
前のフレームを削除せずに毎フレーム描画しているために軌跡が残ってしまいます。でも心配する必要はありません。Canvasの内容を消去するメソッド、clearRect()
があります。このメソッドは4つのパラメータをとります。四角形の左上端のx、y座標と四角形の右下端のx、y座標です。この四角形で囲われた領域にある内容全てが消去されます。
次のハイライトされている新しい行を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;
}
コードを保存してもう一度試してみてください。今度は軌跡のないボールがみえるはずです。10ミリ秒おきにキャンバスは消去され、青い円 (ボール) が指定された位置に描画され、 x
とy
の値は次のフレームに備えて更新されます。
コードを整える
次のいくつかの記事ではdraw()
関数にもっと命令を追加します。ですからdraw()
関数をできるだけ簡潔にしておくのは大事なことです。ボールを描画するコードを別の関数に移しましょう。
既にあるdraw()関数を次の2つの関数で置き換えてください。
function drawBall() {
ctx.beginPath();
ctx.arc(x, y, 10, 0, Math.PI*2);
ctx.fillStyle = "#0095DD";
ctx.fill();
ctx.closePath();
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
drawBall();
x += dx;
y += dy;
}
自分のコードと比べる
この記事で組み上げた自分のコードを下のライブデモで確認したり、書き換えたりしてどのように動いているかしっかり理解しましょう。
練習: 動くボールの速さや向きを変えてみましょう。
次のステップ
ボールを描画して動くようにしましたが、そのままCanvasの縁から消えていってしまいます。第3章ではどのようにボールを壁で弾ませるか探っていきます。