ゲームの「ゲームループ」とは
遊びを見つける執筆にClaudeを使用しています。

ゲームを作り始めると、チュートリアルや解説記事に必ず「ゲームループ」という言葉が登場します。「ループ」とつくので繰り返し処理だとはわかるものの、何をどう繰り返しているのか、なぜそれが必要なのかは意外と説明されないまま進んでしまいがちです。 ゲームループとは、「入力を受け取る→状態を更新する→画面を描画する」という一連の処理を、ゲームが動いている間ずっと繰り返し続ける仕組みのことです。この繰り返しが止まると、キャラクターは動かなくなり、ボタンを押しても反応がなくなります。ゲームが「生きている」ように見えるのは、このループが毎秒何十回も回っているからです。 プログラミングを学び始めた方にとっては抽象的に聞こえるかもしれませんが、仕組みを一度つかむと「なぜコードをここに書くのか」「なぜキャラクターがカクつくのか」という疑問の多くが一気に解決します。この記事では、ゲームループが何をしているのかを順番に整理し、自分でゲームを作るときにどう意識すればよいかを具体的に説明します。
この記事の目次
ゲームループが解決する問題
ゲームは映画や音楽と違い、プレイヤーの操作によって状態が変わります。映画であれば最初から最後まで再生すれば終わりですが、ゲームは「次に何が起きるか」が毎瞬間異なります。このため、プログラムは「今この瞬間、プレイヤーは何をしているか」を常に確認し続ける必要があります。
この「常に確認し続ける」を実現するのがループです。ループがなければ、プログラムは一度だけ処理を実行して終了してしまいます。たとえばHTMLとJavaScriptで書いた簡単なゲームでも、setIntervalやrequestAnimationFrameを使って処理を繰り返しているはずです。これらはいずれも「一定間隔で関数を呼び続ける」命令であり、それ自体がゲームループの土台になっています。
ループの中で何が起きているか
ゲームループは大きく三つの段階に分かれています。
1. 入力の受け取り(Input)
キーボードのキーが押されているか、マウスがクリックされたか、タッチがあったかを確認します。この段階では「状態を変える」のではなく、「何が起きているかを記録する」ことだけをします。記録した情報は次の段階で使います。
2. 状態の更新(Update)
記録した入力をもとに、ゲームの内部状態を変えます。「右キーが押されているなら、プレイヤーのX座標に速度を加算する」「敵がプレイヤーと重なっていたらライフを減らす」といった計算がここで行われます。物理演算、当たり判定、スコア加算、アニメーションのコマ進めなど、「ゲームとして意味のある処理」はすべてこの段階に集まります。
3. 描画(Render / Draw)
更新された状態をもとに、画面を描き直します。「プレイヤーが座標(120, 80)にいる」という状態が確定したので、その位置に画像を表示します。重要なのは、描画は「現在の状態を画面に映す」だけで、状態を変えてはいけないという点です。描画の中で当たり判定をしたり、スコアを変えたりすると、ループのどこで何が変わったかを追いにくくなり、バグの原因になります。
この三段階が一回のループで実行され、それが毎秒30〜60回繰り返されることで、滑らかに動くゲームが成立します。
フレームレートとループの関係
「フレームレート」とはループが1秒間に何回回るかを表す数値で、単位はfps(frames per second)です。60fpsであれば、1秒間に入力→更新→描画のサイクルが60回実行されます。
ブラウザゲームでよく使われるrequestAnimationFrameは、ディスプレイのリフレッシュレートに合わせてループを呼び出す仕組みです。多くの環境では60fps前後になりますが、高リフレッシュレートのモニターでは120fpsや144fpsになることもあります。
ここで注意が必要なのは、「フレームレートに依存した速度計算」の問題です。毎フレーム「座標に5を加える」と書いた場合、60fpsの環境では1秒で300ピクセル進みますが、120fpsの環境では600ピクセル進んでしまいます。これを防ぐには、前のフレームからの経過時間(デルタタイム)を使って速度を計算します。requestAnimationFrameのコールバック関数には時刻が渡されるので、前回との差を求めて「座標 += 速度 × 経過秒数」と書くと、どの環境でも同じ速さで動くゲームになります。
重い処理がループに入ると何が起きるか
ゲームループは一回の処理が重くなると、その分だけ次のフレームが遅れます。たとえば更新処理の中で大きなデータの読み込みや複雑な計算を毎フレーム行うと、1フレームにかかる時間が長くなり、画面がカクつきます。これを「フレーム落ち」と呼びます。
対処の基本的な考え方は「ループの外で済ませられることはループの外で行う」です。画像や音声のロードはゲーム開始前の「ロード画面」でまとめて行い、ループ内では読み込み済みのデータを参照するだけにします。毎フレーム計算する必要のない値は事前に変数に入れておく、同じ処理を何度も書かず関数にまとめるといった工夫も有効です。
JavaScriptでのゲームループの基本形
ブラウザゲームをHTMLとJavaScriptで作る場合の、最もシンプルなゲームループの構造を示します。
let lastTime = 0;
function gameLoop(timestamp) {
const delta = (timestamp - lastTime) / 1000; // 秒単位の経過時間
lastTime = timestamp;
update(delta); // 状態を更新
draw(); // 画面を描画
requestAnimationFrame(gameLoop); // 次のフレームを予約
}
requestAnimationFrame(gameLoop); // ループ開始update(delta)の中に当たり判定や座標計算を書き、draw()の中にCanvas描画やDOM操作を書きます。この分離を守るだけで、コードの見通しが大きく改善されます。ゲームが複雑になっても「動きがおかしい→updateを見る」「表示がおかしい→drawを見る」という調査の起点が明確になるためです。
ゲームループを意識すると何が変わるか
ゲームループの構造を知る前と後では、ゲームのコードの読み方が変わります。どんなゲームエンジンやフレームワークを使っても、updateやtickやonFrameという名前の関数が見つかれば、それがゲームループの中心です。そこに書かれた処理が毎フレーム実行されると理解するだけで、コードの意図が読み取りやすくなります。
また、「なぜこの変数はグローバルに置かれているのか」「なぜ初期化処理は別の関数に分けられているのか」といった設計の判断も、ゲームループを起点に説明できます。ループをまたいで保持したい値はループの外に、ループごとに計算し直す値はループの中に置く、というルールを守るだけで、多くのバグを防げます。
ゲームループは地味な仕組みですが、ゲームプログラミングのすべての土台になっています。この構造を自分の言葉で説明できるようになると、エラーへの対処も、他人のコードを読むことも、格段に楽になります。
次の行動
ゲームループの動きを実際に確かめるには、requestAnimationFrameを使った最小限のサンプルコードを自分で書き、console.logでフレームごとの経過時間を出力してみるのが早道です。動きを確認したら、入力→更新→描画の三段階を意識しながら簡単なゲームを組み立ててみましょう。完成したゲームはアソバース(https://aso-verse.com)にHTMLファイルのままアップロードして公開できます。
参考資料
- MDN Web Docs「Window: requestAnimationFrame() メソッド」
- MDN Web Docs「Canvas API」

