「4.1 ヒット&ブロー」は数字とロジックだけのゲーム、「4.2 3D迷路ゲーム」は一人称視点での移動が特徴だった。本項では、画面下部のパドルでボールを打ち返し、上部に並んだブロックをすべて破壊する「ブロック崩し」(breakout.html)を作る。
見た目はシンプルだが、内部にはAABBと円の衝突判定、HTML5 Canvas 2D API、レスポンシブCSSとアスペクト比制御、デルタタイム、Pointer Events APIとキーボード入力管理、テスト容易性という6つの要素技術が組み合わさっている。これらを1つずつプログラミング未経験者にも分かるように整理したうえで、Codexに渡すプログラム仕様書としてまとめる。
目次
ブロック崩しゲームの全体像
アタリ「Breakout」
「ブロック崩し」は、1976年(昭和51年)にアタリ社(Atari)がアーケードゲームとして発表した「Breakout」(ブレイクアウト)を起源とするアクション・ビデオゲームである。国内では、エポック社が1979年(昭和54年)に発売した「テレビブロック」が最初の製品で、家庭用テレビに接続してプレイできた。
画面下部に置かれたパドルを左右に動かし、跳ね返るボールを打ち返して、画面上部に敷き詰められたブロックを1つずつ壊していく。プレイヤーが操作できるのはパドルだけであり、ボールは壁やブロックに当たるたびに物理法則に従って向きを変えながら画面内を動き回る。

本項で作る breakout.html はアタリ社のゲームの名前をインスパイアし、ブロックを縦7段・横10個、合計70個並べる。配色は上から下へ向かって虹色のグラデーションにし、ブロックの一部は「耐久ブロック」として、周囲を異なる色の枠で囲む。耐久ブロックは1回当てただけでは壊れず、通常ブロックの見た目に変わったうえでもう1回当てて初めて破壊できる。画面上のブロックをすべて消せばクリア、ボールをパドルで受け止められずに画面下端の「ミスゾーン」に落とすと残機が1つ減り、残機が0になった時点でゲームオーバーとなる。
画面下部に置かれたパドルを左右に動かし、跳ね返るボールを打ち返して、画面上部に敷き詰められたブロックを1つずつ壊していく。プレイヤーが操作できるのはパドルだけであり、ボールは壁やブロックに当たるたびに物理法則に従って向きを変えながら画面内を動き回る。
本項で作る breakout.html はアタリ社のゲームの名前をインスパイアし、ブロックを縦7段・横10個、合計70個並べる。配色は上から下へ向かって虹色のグラデーションにし、ブロックの一部は「耐久ブロック」として、周囲を異なる色の枠で囲む。耐久ブロックは1回当てただけでは壊れず、通常ブロックの見た目に変わったうえでもう1回当てて初めて破壊できる。画面上のブロックをすべて消せばクリア、ボールをパドルで受け止められずに画面下端の「ミスゾーン」に落とすと残機が1つ減り、残機が0になった時点でゲームオーバーとなる。
| 要素 | 役割 |
|---|---|
| パドル(Paddle) | プレイヤーが唯一操作できるバー。ボールを打ち返す |
| ボール | 画面内を跳ね返りながら動き回り、ブロックを破壊する |
| 通常ブロック | 1ヒットで破壊できる |
| 耐久ブロック | 周囲を異なる色の枠で囲む。2回当てないと壊れず、1回当たると通常ブロックの色に変わる |
| 壁 | 左右および上部のバウンダリ。ボールを反射させる |
| ミスゾーン | 画面最下部。ボールが落ちるとミスとなり残機が減る |
ボールの跳ね返る角度は、パドルのどこに当たったかによって変わる。パドルの中心で受け止めればほぼ真上に、端に近い位置で受け止めるほど鋭い角度で左右に飛ぶ。また、制限時間を3分(180秒)に設定し、画面右下に「分:秒」で残り時間を表示、残り15秒を切ると数字を赤色にして時間切れの緊迫感を演出する。時間内にブロックを消しきれなければ、これもゲームオーバーとして扱う。
要素技術1:衝突判定(AABBと円と矩形)
本項から、ブロック崩しゲームで使う「要素技術」を解説するが、これらを理解できなくても、最後に掲げるゲーム仕様書(プロンプト)を Codex に投入すればゲーム・プログラムを作ることができる。のちのち、ゲームの改良や、異なるテイストのゲームを創作するときの参考になるように、要素技術を紹介する。

ブロック崩しの核心は、ボールが壁・パドル・ブロックのどれに当たったかを判定する処理にある。もっとも基本的な方法が AABB(Axis-Aligned Bounding Box、軸平行境界ボックス)である。これは、回転していない2つの長方形について、それぞれの左端・右端・上端・下端の座標を比較し、4辺のどこにも隙間がなければ「重なっている=衝突している」と判定する方法である。計算が単純で高速なため、壁やブロックのように向きの変わらない四角形どうしの当たり判定に向いている。

ただし、ボールは実際には円である。円をそのまま四角形として扱うと、ブロックの角に当たったときに不自然な跳ね返りになりやすい。そこで本項のプログラムでは、ボールの半径ぶん広げた仮想の四角形(バウンディングボックス)を使って AABBの判定を行ったうえで、ボールがブロックのどちら向きから食い込んでいるか(上下方向の食い込み量と左右方向の食い込み量のどちらが小さいか)を比較し、小さいほうの向きの速度を反転させる。円と矩形の正確な最近接点計算を省きながらも、見た目には自然な反射を実現する、実務的な折衷案である。
ブロック崩しの核心は、ボールが壁・パドル・ブロックのどれに当たったかを判定する処理にある。もっとも基本的な方法が AABB(Axis-Aligned Bounding Box、軸平行境界ボックス)である。これは、回転していない2つの長方形について、それぞれの左端・右端・上端・下端の座標を比較し、4辺のどこにも隙間がなければ「重なっている=衝突している」と判定する方法である。計算が単純で高速なため、壁やブロックのように向きの変わらない四角形どうしの当たり判定に向いている。
ただし、ボールは実際には円である。円をそのまま四角形として扱うと、ブロックの角に当たったときに不自然な跳ね返りになりやすい。そこで本項のプログラムでは、ボールの半径ぶん広げた仮想の四角形(バウンディングボックス)を使って AABBの判定を行ったうえで、ボールがブロックのどちら向きから食い込んでいるか(上下方向の食い込み量と左右方向の食い込み量のどちらが小さいか)を比較し、小さいほうの向きの速度を反転させる。円と矩形の正確な最近接点計算を省きながらも、見た目には自然な反射を実現する、実務的な折衷案である。
| 組み合わせ | 判定方法 |
|---|---|
| ボール × 壁 | 画面の左右・上端の座標とボールの座標を比較する単純なAABB判定 |
| ボール × パドル | AABB判定に加え、当たった位置から跳ね返る角度を計算する |
| ボール × ブロック | AABBで重なりを検出したうえで、食い込み量の小さい向きに反射させる |
要素技術2:HTML5 Canvas 2D API と requestAnimationFrame
画面の描画には HTML5 Canvas を使う。<canvas>タグをHTMLに配置し、JavaScriptからCanvas 2D APIと呼ばれる描画命令を呼び出すことで、点や線、長方形、円、グラデーションといった図形を自由に描ける。画像ファイルを読み込む必要はなく、パドルは塗りつぶした長方形として、ボールは円弧を描く命令(arc)として、ブロックの色は行ごとに用意した色の配列を割り当てるだけで表現できる。

Canvasはあくまで「今の状態を1枚の絵として描く」仕組みであり、動きを表現するには、1秒間に何十回も「画面を消去する→最新の位置を計算する→描き直す」という処理を繰り返す必要がある。本項ではブラウザが用意する requestAnimationFrame という仕組みを使い、画面の描画タイミングに合わせてこの繰り返し(ゲームループ)を実行する。ctx.clearRect で前のフレームの絵を消してから描き直すことで、パドルとボールが滑らかに動いているように見える。
Canvasはあくまで「今の状態を1枚の絵として描く」仕組みであり、動きを表現するには、1秒間に何十回も「画面を消去する→最新の位置を計算する→描き直す」という処理を繰り返す必要がある。本項ではブラウザが用意する requestAnimationFrame という仕組みを使い、画面の描画タイミングに合わせてこの繰り返し(ゲームループ)を実行する。ctx.clearRect で前のフレームの絵を消してから描き直すことで、パドルとボールが滑らかに動いているように見える。
要素技術3:レスポンシブCSSとアスペクト比制御
レスポンシブCSSとは、パソコンの大きな画面からスマートフォンの縦長画面まで、閲覧環境に応じてレイアウトを自動的に調整する設計手法である。本項では、ゲーム画面を囲む要素の幅を「画面の96%」「高さから逆算した幅」「960ピクセル」の3つのうちいちばん小さい値に合わせるCSSを使い、パソコンでもスマートフォンでも画面からはみ出さず、かつできるだけ大きく表示されるようにする。

一方で、Canvasの内部の座標(本項では800×600ピクセル)は固定したままにしたい。表示サイズだけを変えて内部の比率が崩れると、ボールが楕円に見えたりパドルが歪んだりしてしまう。そこでアスペクト比制御として、CSSの aspect-ratio プロパティで表示領域の縦横比を常に4対3に固定する。これにより、どんな画面幅であっても、ゲーム画面の縦横比は変わらず、内部のボールやブロックの見た目も崩れない。画面の高さが極端に低い端末向けには、ヘッダーの表示を小さくする調整も別途加えている。
レスポンシブCSSは、ブログやホームページにも応用できる。
一方で、Canvasの内部の座標(本項では800×600ピクセル)は固定したままにしたい。表示サイズだけを変えて内部の比率が崩れると、ボールが楕円に見えたりパドルが歪んだりしてしまう。そこでアスペクト比制御として、CSSの aspect-ratio プロパティで表示領域の縦横比を常に4対3に固定する。これにより、どんな画面幅であっても、ゲーム画面の縦横比は変わらず、内部のボールやブロックの見た目も崩れない。画面の高さが極端に低い端末向けには、ヘッダーの表示を小さくする調整も別途加えている。
レスポンシブCSSは、ブログやホームページにも応用できる。
要素技術4:デルタタイム
パソコンやスマートフォンは機種によって画面の更新速度(フレームレート)が異なり、同じ端末でも他の処理が重なると一時的に遅くなることがある。もし「1フレームごとにボールを5ピクセル動かす」という決め方をすると、更新が速い端末ではボールが速く、遅い端末では遅く見えてしまう。そこで、前回の描画から今回の描画までに実際に経過した時間(デルタタイム)を毎回計算し、「1秒間に210ピクセル動かす」のように時間あたりの速度で表現することで、フレームレートが変わってもボールの速さが一定に保たれる。

ただし、ブラウザのタブを裏に回すなどしてゲームが一時的に止まった直後は、経過時間が異常に長く計算されてしまう場合がある。この値をそのまま使うと、ボールが壁やブロックを一瞬で通り抜けてしまう不具合につながる。そこで本項のプログラムでは、デルタタイムの上限を0.025秒に制限し、どれだけ処理が遅れても1回の計算で進む距離が跳ね上がらないようにしている。
ただし、ブラウザのタブを裏に回すなどしてゲームが一時的に止まった直後は、経過時間が異常に長く計算されてしまう場合がある。この値をそのまま使うと、ボールが壁やブロックを一瞬で通り抜けてしまう不具合につながる。そこで本項のプログラムでは、デルタタイムの上限を0.025秒に制限し、どれだけ処理が遅れても1回の計算で進む距離が跳ね上がらないようにしている。
要素技術5:Pointer Events APIとキーボード入力管理
パドルの操作方法には、パソコンのマウス、スマートフォンの指、ペンタブレットなど複数の入力手段がある。従来はマウス用とタッチ用でそれぞれ別のイベント処理を書く必要があったが、Pointer Events APIを使うと、pointerdown(押した)、pointermove(動かした)、pointerup(離した)という共通のイベントだけで、入力機器の種類を意識せずに済む。本項では、画面を押した位置にパドルの中心を合わせ、指やマウスを動かすとその位置にパドルが追従するようにしている。

キーボード操作については、Aキー・左矢印キーで左へ、Dキー・右矢印キーで右へパドルを移動する。複数のキーを同時に押した状態を扱えるよう、押されているキーの一覧をSet(集合)として保持し、キーを押している間は移動を続け、離すと止まるという自然な操作感を実現する。矢印キーによる画面のスクロールを防ぐ処理や、操作に使えないキーが押されたときに「その操作はできません」という趣旨のメッセージを表示する仕組みも合わせて用意する。
キーボード操作については、Aキー・左矢印キーで左へ、Dキー・右矢印キーで右へパドルを移動する。複数のキーを同時に押した状態を扱えるよう、押されているキーの一覧をSet(集合)として保持し、キーを押している間は移動を続け、離すと止まるという自然な操作感を実現する。矢印キーによる画面のスクロールを防ぐ処理や、操作に使えないキーが押されたときに「その操作はできません」という趣旨のメッセージを表示する仕組みも合わせて用意する。
要素技術6:テスト容易性
ゲームには、ボールの速度や跳ね返る角度など、プレイのたびに変化する要素が多い。人手でプレイしてゲームクリアやゲームオーバーになるまで待つやり方では、動作確認に時間がかかり、確認漏れも起きやすい。そこで、Codexのような自動化されたテスト実行者が、決められたルール通りにゲームが進むかどうかを素早く確認できるように、テスト容易性を考慮した作りにしておく。

具体的には、URLの末尾に特定の文字列(例えば #codex-test)が付いているときだけ、現在の残機やブロック数を取得する関数、強制的にクリアさせる関数、残機を1にしてミスを再現する関数、時間切れを再現する関数などをまとめて公開する。この仕組みにより、実際に何十回もパドルでボールを打ち返す操作を繰り返さなくても、ゲームクリア・ゲームオーバー・時間切れという3つの結末それぞれが仕様通りに動くかを短時間で検証できる。通常のプレイヤーがこの文字列を知らなければ、この機能に触れることはない。

よく「デバッグ・モード」と呼ばれる機能であり、配布プログラムでは機能を使えないようにしておくのが定石だが、本プログラムではあえて残してある。興味がある方は使ってみてほしい。
具体的には、URLの末尾に特定の文字列(例えば #codex-test)が付いているときだけ、現在の残機やブロック数を取得する関数、強制的にクリアさせる関数、残機を1にしてミスを再現する関数、時間切れを再現する関数などをまとめて公開する。この仕組みにより、実際に何十回もパドルでボールを打ち返す操作を繰り返さなくても、ゲームクリア・ゲームオーバー・時間切れという3つの結末それぞれが仕様通りに動くかを短時間で検証できる。通常のプレイヤーがこの文字列を知らなければ、この機能に触れることはない。
よく「デバッグ・モード」と呼ばれる機能であり、配布プログラムでは機能を使えないようにしておくのが定石だが、本プログラムではあえて残してある。興味がある方は使ってみてほしい。
ブロック崩しゲームのプログラム仕様書
以上を踏まえて、ブロック崩しゲーム「breakout.html」のプログラム仕様書を示す。これがCodexに渡すプロンプトそのものになる。
プログラム仕様書(プロンプト)
# 目標 プレイヤーは画面下部にあるパドルを左右に操作し、跳ね返るボールを打ち返して、画面上部に配置されたブロックをすべて破壊することを目指す。
# プログラム・ファイル名 breakout.html
# プロジェクト・フォルダ作成 - プログラム・ファイル名の拡張子を除いた主ファイル名と同じ名前のサブフォルダを作成し、以降の作業はサブフォルダで行う。 - すでにサブフォルダがあれば、そのサブフォルダに移動して以降の作業を進める。
# ゲーム仕様
## 勝敗条件 - 勝利(クリア):画面上の破壊可能なブロックをすべて消去する。 - 敗北(ゲームオーバー):ボールをパドルで打ち返せず、画面下端(ミスゾーン)に落とすと残機(ライフ)が1つ減る。残機が0になるとゲームオーバーになる。
## 基本的な挙動・メカニクス - 反射運動:ボールは壁やブロック、パドルに当たると物理法則に従って跳ね返る。 - 打角のコントロール:パドルの「当たる位置」によってボールの跳ね返る角度が変わる。端で打つほど鋭い角度で飛ぶ。
## 画面構成要素 ### パドル(Paddle) プレイヤーが唯一操作できるバー。ボールを打ち返す。
### ボール 画面内を動き回り、ブロックを破壊する。
### ブロック 破壊対象。色や耐久度によって性質が異なる。 縦7段、横10個が並ぶ。 配色は、上から下に向かって虹色のグラデーション。 - 通常ブロック:1ヒットで破壊できる。 - 耐久ブロック:ブロックの周囲が異なる色の枠に囲われている。2回以上当てないと壊れない(1回当たると色が通常ブロックに変化する)。
### 壁 左右および上部のバウンダリ。ボールを反射させる。
### ミスゾーン 画面最下部。ここにボールが落ちるとミス。
## 制限時間 - 制限時間は3分(180秒)とする。 - 画面右下に残り時間を「分:秒」で表示する。 - 残り15秒以下では時間表示を赤色にする。 - 制限時間内にクリアできなければゲームオーバーとする。
# 操作方法
## キーボード - Aキーまたは左矢印:パドルを左へ移動 - Dキーまたは右矢印:パドルを右へ移動
## 画面タッチ - パドルを左右へスライドさせると、それに沿ってパドルが動く。
# 画面構成 - 画面中央:ブロック崩し - 画面右下:残り時間 - 画面上部:タイトル、バージョン、著作権者、ライセンス - スマートフォンの狭い画面でも操作できるレスポンシブ構成にする - ゲームクリア画面およびゲームオーバー画面には、それまでの成績(年月日時分、ゲームクリアかオーバーか、クリアまでの時間)を直近30回分表示する。1画面に表示しきれなければ自動縦スクロール。画面上段には「もう一度遊ぶ」「終了する」ボタンを常に表示する。
# エラー処理 - JavaScript実行中にシステムエラーが発生した場合は、処理を安全に停止する。 - エラー内容を画面に表示する。 - 無効な入力は受け付けず、理由をメッセージで表示する。
## 記録 - それまでの成績(上述の通り)
# テスト観点・合格条件 - Codexが5回プレイし、ゲームクリア、ゲームオーバーがルール通りに行われること。 - 前提条件、制約条件が守られていること。
# 前提条件 - タイトルは「ブロック崩しゲーム」、バージョン番号、著作権者を表示する。 - 仕様で分からないことがあれば、ユーザーに質問すること。 - JavaScriptを使った1本のプログラム・ファイルにすること。 - クライアントPCのブラウザ(OSやブラウザの種類は問わない)で動作すること。 - スマホでも利用できること。 - httpサーバなどやNode.jsなどサーバ技術は使わず、ブラウザの機能で完結すること。 - コーディングは「Airbnb JavaScript Style Guide」にのっとること。 - プログラムファイルにコメントとして次の情報を記載すること。 - プログラムの名称 - バージョン - 目的 - 動作環境 - 著作権表示および使用条件 - インストール方法 - お問い合わせ
# 制約条件 - インターネットとのデータ送受信は行わないこと。 - 外部ライブラリを使用する場合は、下記のサイトに限定すること https://cdn.jsdelivr.net/ https://cdnjs.cloudflare.com/ https://ajax.googleapis.com/ https://code.jquery.com/ https://ajax.aspnetcdn.com/ - プログラムがMIT Licenseに違反していないこと。
「## 画面構成要素」にパドル・ボール・ブロック・壁・ミスゾーンそれぞれの性質を、「## 制限時間」「## 基本的な挙動・メカニクス」に時間管理と打角制御のルールを、「# 操作方法」にキーボードとタッチそれぞれの操作方法を書き込んである。この仕様書をCodexに渡すと、AABBに基づく衝突判定とデルタタイムによる速度管理を備えたブロック崩しゲームが生成される。
完成したブロック崩しゲームの画面
参考サイト
- Canvas API:MDN Web Docs
- Pointer events:MDN Web Docs
- 2D collision detection:MDN Web Docs
(この項おわり)
大きな写真