本項では、コンピューターが自動生成した迷路を一人称視点で3D表示し、プレイヤーが制限時間内に出口を目指すブラウザゲーム「3D迷路ゲーム」(maze3D.html)を作る。前項のヒット&ブローが数字とロジックだけのゲームだったのに対し、本項では画面の中を実際に歩き回る感覚を作り込む点が大きな違いになる。
15×15マスの迷路を毎回自動生成し、開始地点から最も遠い場所を出口に定める。3D表示にはHTML5 Canvasとレイキャスティングという2つの要素技術を使い、外部の3D描画ライブラリを使わずに壁や床、空を描く。さらに、壁との衝突判定、プレイヤーが通った場所だけを記録する探索マップ、制限時間の管理なども必要になる。これらを1つずつ整理したうえで、Codexに渡すプログラム仕様書としてまとめる。
3D迷路ゲームの全体像
「迷路ゲーム」と聞くと、上から見下ろした2Dの迷路を思い浮かべる人が多いだろう。本項で作るのは、迷路の中を実際に歩いているように見える一人称視点の3D迷路である。プレイヤーは画面中央に表示された迷路を見ながら、前進・後退・左右への旋回だけで出口を目指す。上から見た迷路全体は最初から表示されず、実際に歩いた場所だけが画面左下の探索マップに少しずつ描き加えられていく仕組みにする。

ゲームとして成立させるには、制限時間という制約が要る。本項では制限時間を3分(180秒)とし、その間に出口へ到達できなければゲームオーバーとする。逆に、時間内に出口へ着けばゲームクリアとなり、かかった時間を秒単位で表示する。クリア・オーバーいずれの結果も、直近30回分の成績として画面に記録する。下表に、本項で扱う主な機能をまとめる。
ゲームとして成立させるには、制限時間という制約が要る。本項では制限時間を3分(180秒)とし、その間に出口へ到達できなければゲームオーバーとする。逆に、時間内に出口へ着けばゲームクリアとなり、かかった時間を秒単位で表示する。クリア・オーバーいずれの結果も、直近30回分の成績として画面に記録する。下表に、本項で扱う主な機能をまとめる。
| 機能 | 内容 |
|---|---|
| 迷路の自動生成 | 15×15マスの迷路を、開始のたびにコンピューターが作る |
| 一人称視点の3D表示 | HTML5 Canvasとレイキャスティングで壁・床・空を描く |
| 移動・旋回 | キーボードまたは画面上のボタン・タッチ操作で操作する |
| 壁との衝突判定 | 壁がある方向には進めず、画面の反転・点滅で知らせる |
| 探索マップ | 実際に通った床と、それに接する壁だけを画面左下に描く |
| 制限時間 | 3分以内に出口へ到達できなければゲームオーバー |
| 成績記録 | クリア・オーバーの結果を直近30回分表示する |
迷路の自動生成アルゴリズム
迷路を自動生成するとき、最も避けなければならないのは「たどり着けない部屋」ができてしまうことである。壁をランダムに配置するだけでは、行き止まりに囲まれた到達不能な区画が生まれかねない。そこで本項では、すべての通路が到達可能になる方式で迷路を作る。具体的には、15×15マスの区画を単位とし、開始マスから未訪問のマスへ壁を壊しながら進んでいく方式を使う。この方式では、通路をつなぎながら迷路を掘り進めるため、結果としてどのマスからも必ず開始マスへ戻れる、すなわち到達可能な迷路が保証される。

出口の位置も工夫が必要である。出口を固定の位置(例えば右下の角)に置くと、迷路の形によっては開始地点からすぐ近くになってしまい、ゲームとして単調になる。そこで、迷路が完成した後に、開始地点からの距離を全マスについて計算し、最も遠い到達可能なマスを出口にする。これにより、迷路の形が毎回変わっても、常に相応の探索が必要な出口が設定される。

また、迷路生成の途中で「進める未訪問マスがない」状態に陥ることがある。通常は1つ前のマスへ戻って別の方向を試す(バックトラック)ことで解決するが、実装のミスなどで想定外の状態に入ると、処理が終わらなくなる恐れがある。これを防ぐため、生成処理には繰り返し回数の安全上限を設け、上限に達したら生成をやり直すか、エラーとして扱うようにする。

もっとも、これらのアルゴリズムは、Codex がいい案配に用意してくれるので、皆さんはとくに学ぶ必要はない。
出口の位置も工夫が必要である。出口を固定の位置(例えば右下の角)に置くと、迷路の形によっては開始地点からすぐ近くになってしまい、ゲームとして単調になる。そこで、迷路が完成した後に、開始地点からの距離を全マスについて計算し、最も遠い到達可能なマスを出口にする。これにより、迷路の形が毎回変わっても、常に相応の探索が必要な出口が設定される。
また、迷路生成の途中で「進める未訪問マスがない」状態に陥ることがある。通常は1つ前のマスへ戻って別の方向を試す(バックトラック)ことで解決するが、実装のミスなどで想定外の状態に入ると、処理が終わらなくなる恐れがある。これを防ぐため、生成処理には繰り返し回数の安全上限を設け、上限に達したら生成をやり直すか、エラーとして扱うようにする。
もっとも、これらのアルゴリズムは、Codex がいい案配に用意してくれるので、皆さんはとくに学ぶ必要はない。
要素技術1:HTML5 Canvas
3D迷路を画面に表示するために使った JavaScript の要素技術を2つ紹介しておこう。

まず HTML5 Canvasであるが、これは、HTMLの<canvas>タグと、JavaScriptから呼び出す描画命令(Canvas API)を使って、Webページの中に図形や画像を自由に描く仕組みである。あらかじめ用意された画像を貼り付けるのではなく、点・線・長方形・グラデーションといった基本図形を1つずつ組み合わせて描画するため、プログラムの中でリアルタイムに絵を作り出せる。本項の3D迷路ゲームでは、この特徴を利用して、赤レンガの壁や石畳の地面のテクスチャそのものをHTML内で自動生成し、外部の画像ファイルを一切読み込まずに済ませる。

Canvasにはもう1つ重要な特徴がある。1本のCanvas要素の中に、色の異なる無数の縦線や長方形を高速に描き重ねられる点である。3D迷路の描画は、実際には立体の物体を計算しているわけではなく、縦に細長い帯(縦線)を、壁までの距離に応じた高さと明るさで並べて描くという2D描画の積み重ねで実現する。この考え方の中心になるのが、次に説明するレイキャスティングである。
まず HTML5 Canvasであるが、これは、HTMLの<canvas>タグと、JavaScriptから呼び出す描画命令(Canvas API)を使って、Webページの中に図形や画像を自由に描く仕組みである。あらかじめ用意された画像を貼り付けるのではなく、点・線・長方形・グラデーションといった基本図形を1つずつ組み合わせて描画するため、プログラムの中でリアルタイムに絵を作り出せる。本項の3D迷路ゲームでは、この特徴を利用して、赤レンガの壁や石畳の地面のテクスチャそのものをHTML内で自動生成し、外部の画像ファイルを一切読み込まずに済ませる。
Canvasにはもう1つ重要な特徴がある。1本のCanvas要素の中に、色の異なる無数の縦線や長方形を高速に描き重ねられる点である。3D迷路の描画は、実際には立体の物体を計算しているわけではなく、縦に細長い帯(縦線)を、壁までの距離に応じた高さと明るさで並べて描くという2D描画の積み重ねで実現する。この考え方の中心になるのが、次に説明するレイキャスティングである。
要素技術2:レイキャスティング
レイキャスティング(Ray Casting)は、プレイヤーの視点から画面の横方向1列ごとに1本の光線(レイ)を伸ばし、その光線が迷路の壁にぶつかるまでの距離を計算する手法である。画面の幅が例えば640ピクセルであれば、640本の光線を少しずつ角度を変えて放ち、それぞれの光線が壁に当たった距離を求める。距離が分かれば、近い壁ほど縦に長く、遠い壁ほど縦に短く描けばよいことになり、その1本分の結果が画面上の縦1列の帯として描かれる。これを画面の左端から右端まで繰り返すことで、壁が立体的に見える3D映像が完成する。

レイキャスティングは、コンピューターグラフィックスで一般的なレイトレーシング(光の反射や屈折まで再現する手法)とは異なり、光線を1回まっすぐ伸ばして最初に当たった壁までの距離だけを求める、単純で計算負荷の軽い手法である。1990年代のパソコン向けゲームで、まだ本格的な3D描画の性能がなかった時代に広く使われた技術であり、現在ではブラウザ上のJavaScriptだけでも十分な速度で計算できる。下表に、レイキャスティングと、地面(石畳)の描画に使う床キャスティングの役割の違いを示す。
レイキャスティングは、コンピューターグラフィックスで一般的なレイトレーシング(光の反射や屈折まで再現する手法)とは異なり、光線を1回まっすぐ伸ばして最初に当たった壁までの距離だけを求める、単純で計算負荷の軽い手法である。1990年代のパソコン向けゲームで、まだ本格的な3D描画の性能がなかった時代に広く使われた技術であり、現在ではブラウザ上のJavaScriptだけでも十分な速度で計算できる。下表に、レイキャスティングと、地面(石畳)の描画に使う床キャスティングの役割の違いを示す。
| 対象 | 手法 | 考え方 |
|---|---|---|
| 壁 | レイキャスティング | 画面の縦1列ごとに光線を伸ばし、壁までの距離で縦の帯の高さと明るさを決める |
| 地面(石畳) | 床キャスティング(フロアキャスティング) | 画面の横1行ごとに、その行が示す実際の距離を逆算し、石畳の模様を遠近に応じて縮小・拡大して描く |
壁は遠いほど暗く描き、距離感を演出する。また、出口が視界内にあり、かつ十分に近づいた場合には、壁の描画に重ねて「EXIT」の文字を表示し、プレイヤーに出口の位置を知らせる。地面については、単純に石畳の画像を平らに貼り付けるだけでは、プレイヤーが歩いても模様が変化せず、奥行き感が生まれない。そこで床キャスティングを使い、画面の各行が「プレイヤーから実際に何メートル先の地面か」を計算し、その距離に応じて石畳の模様を縮小・拡大しながら描く。これにより、移動や旋回に合わせて足元の石畳が滑らかに変化する。
3D迷路ゲームのプログラム仕様書
以上を踏まえて、3D迷路ゲーム「maze3D.html」のプログラム仕様書を示す。これがCodexに渡すプロンプトそのものになる。
プログラム仕様書(プロンプト)
# 目標 コンピューターが自動生成した迷路を一人称視点で3D表示し、プレイヤーが制限時間内に出口を目指すブラウザゲームを作成する。
# プログラム・ファイル名 maze3D.html
# プロジェクト・フォルダ作成 - プログラム・ファイル名の拡張子を除いた主ファイル名と同じ名前のサブフォルダを作成し、以降の作業はサブフォルダで行う。 - すでにサブフォルダがあれば、そのサブフォルダに移動して以降の作業を進める。
# ゲーム仕様
## 迷路 - 迷路の大きさは15×15マスとする - ゲーム開始時と再プレイ時に迷路を自動生成する - すべての通路が到達可能な迷路を生成する - 開始地点から最も遠い到達可能な場所を出口にする - 迷路生成処理には安全上限を設け、無限ループを防止する
## 制限時間 - 制限時間は3分(180秒)とする - 画面右下に残り時間を「分:秒」で表示する - 残り15秒以下では時間表示を赤色にする - 制限時間内に出口へ到着できなければゲームオーバーとする
## クリア条件 - プレイヤーが制限時間内に出口へ到着するとゲームクリア - クリア時には出口までにかかった時間を秒単位で表示する - ゲームクリア画面およびゲームオーバー画面には、それまでの成績(年月日時分、ゲームクリアかオーバーか、クリアまでの時間)を直近30回分を表示する。1画面に表示しきれなければ自動縦スクロール。画面上段には「もう一度遊ぶ」「終了する」ボタンを常に表示する
# 3D画面 - HTML5 Canvasを使用して、一人称視点の迷路を画面中央に表示する - レイキャスティングによって壁を3D描画する - 遠くの壁ほど暗くし、距離感を表現する - 出口が近く、視界内にある場合は「EXIT」と表示する
## 空 - 頭上は青空にする - 空には青色のグラデーションと白い雲を描画する
## 壁 - 壁は赤レンガを積み重ねた外観にする - 512×512ピクセル相当の高解像度テクスチャをHTML内で自動生成する - レンガには目地、陰影、色むら、表面の細かな模様を付ける - 外部画像は読み込まない
## 地面 - 地面は石畳にする - 石畳のテクスチャはHTML内で自動生成する - 単純な平面貼り付けにはせず、床キャスティングを使用する - プレイヤーの視点、向き、距離、画角に応じて遠近投影する - 遠くの石畳は小さく、足元の石畳は大きく表示する - 移動や旋回に合わせて石畳の見え方を変化させる
# 操作方法
## キーボード - Wキーまたは上矢印:前進 - Sキーまたは下矢印:後退 - Aキーまたは左矢印:左を向く - Dキーまたは右矢印:右を向く
## 画面上のボタン - 前進 - 後退 - 左旋回 - 右旋回 - タッチ操作に対応する
# 壁との衝突 - 移動方向に壁がある場合は移動させない - 壁に当たったとき、3D画面の色を短時間反転させる - 色反転には点滅と軽い拡大アニメーションを付ける - 同時に「壁があるため移動できません」と表示する - 連続して壁に当たった場合も、アニメーションを最初から再生する
# 探索マップ - 画面左下に迷路を上から見たマップを表示する - 未踏領域は暗いマスクで隠す - 迷路全体の構造を最初から表示しない - プレイヤーが実際に通過した床だけを表示する - 通過した床に接している壁を表示する - 通過した床は青灰色で表示する - 壁は赤茶色で表示する - プレイヤーが進んできた経路を赤線で表示する - 現在位置と向きを白い矢印で表示する - 出口は緑色で常に表示する - 未踏の通路や、その先にある壁は表示しない - 再プレイ時には探索済み領域と移動経路をリセットする
# 画面構成 - 画面中央:一人称視点の3D迷路 - 画面左下:探索マップ - 画面右下:残り時間 - 画面下部:移動・旋回ボタン - 画面上部:タイトル、バージョン、著作権者、ライセンス - スマートフォンの狭い画面でも操作できるレスポンシブ構成にする
# エラー処理 - 迷路生成処理には無限ループ防止用の上限値を設ける - JavaScript実行中にシステムエラーが発生した場合は、処理を安全に停止する - エラー内容を画面に表示する - 無効な入力は受け付けず、理由をメッセージで表示する
## 記録 - それまでの成績(上述の通り)
# テスト観点・合格条件 - Codexが5回プレイし、ゲームクリア、ゲームオーバーがルール通りに行われること。 - 前提条件、制約条件が守られていること。
# 前提条件 - タイトルは「3D迷路ゲーム」、バージョン番号、著作権者を表示する。 - 仕様で分からないことがあれば、ユーザーに質問すること。 - 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に違反していないこと。
「## 迷路」「## 制限時間」「## クリア条件」に迷路生成と時間制限のルールを、「# 3D画面」以下の「## 空」「## 壁」「## 地面」に外部画像を使わないテクスチャ自動生成の要件を、「# 探索マップ」に通過済みの床と壁だけを描くマップ表示の条件を、それぞれ書き込んである。この仕様書をCodexに渡すと、レイキャスティングによる3D表示と床キャスティングによる石畳表現を備えた迷路ゲームが生成される。
完成した3D迷路ゲームの画面
参考サイト
- Canvas API:MDN Web Docs
(この項おわり)
大きな写真