都市をブラウザのタブに押し込むと、デモ日のスローガンはすぐに具体的な工学問題に変わります。入力デバイスは一つではない、資源は一括ダウンロードできない、黒画面と「キーが効かない」は別クラスの障害です。本稿では 臺北 GTA(Taipei GTA) の公開ページと確認できるフロント資源を手がかりに、WebGL 系の開放世界で再利用しやすい層分けを整理します。
先に断り: 臺北 GTA は独立したウェブゲームであり、Rockstar Games および Grand Theft Auto シリーズとは公式の関係がありません。以下は検証可能な事実のみを述べ、コードはすべてサンプルコードです。
「案内サイト」と「ゲーム」は二層
taipeigta.com のページ構成を見ると、操作表・攻略を担う案内サイトと、実際のプレイ領域(「開始遊戲/Start」後に iframe で読み込まれるプレイ先)が分かれています。構造化データ上もブラウザには JavaScript と WebGL が必要と書かれています。
プレイ側の入口HTMLには、パッケージ名として three-*.js、BufferGeometryUtils-*.js、engine-*.js、controllers-*.js、world-*.js などが現れます。つまり遊べる本体は three.js/WebGL ベースのブラウザ3D(詳細な業務ロジックはオンライン版に従う)であり、従来型のインストールパッケージではありません。
この二層は次の副作用を生みます。
-
キーボードフォーカスが外層に残る。 下の攻略を読んでいるとき、
Space/WASDはページスクロールに吸われ、canvas に届かないことがある - 読み込み進捗が二段。 案内ページはすぐ開く。都市メッシュ・テクスチャ・スクリプトは iframe 内で続く。「ページが出た=街に入れた」と誤ると、黒画面障害と誤診しやすい
入力マップ:同じ意図、三種類の物理キー
開放世界では、移動・乗車・地図・任務といった 意味(Intent) が、キーボード、タッチ、ゲームパッドをまたぎます。案内サイトのキー表は、そのまま「意味表」として読めます。
| 意味 | キーボード/マウス(案内より) | タッチ(案内より) |
|---|---|---|
| 徒歩移動/視点 | WASD + マウス | 左スティック + 右スワイプ |
| 乗降 | F |
「乗降」ボタン |
| 地図/スマホ/一時停止 |
M / T / Esc
|
対応する画面ボタン |
| 運転のアクセル/ブレーキ/操舵 |
W / S / A``D
|
ペダル + スティック |
| 徒歩ジャンプ/運転ハンドブレーキ | どちらも Space(状態で切替) |
「跳」と「手煞」は別ボタン |
1. 物理キー名ではなく「キャラ状態」に意味を結ぶ
徒歩の Space はジャンプ、運転中はハンドブレーキ。地図表示中の E はズーム寄り、任務開始地点の近くではインタラクト、といった具合です。コントローラ層が keydown === 'Space' -> jump() だと、乗車直後に必ず壊れます。整理すると(サンプル):
type Mode = 'onFoot' | 'driving' | 'mapOpen' | 'phoneOpen';
type Intent =
| 'move'
| 'jump'
| 'handbrake'
| 'enterExitVehicle'
| 'toggleMap'
| 'interact'
| 'zoom';
function resolveIntent(mode: Mode, key: string): Intent | null {
if (key === 'Space') {
return mode === 'driving' ? 'handbrake' : mode === 'onFoot' ? 'jump' : null;
}
if (key === 'KeyE') {
return mode === 'mapOpen' ? 'zoom' : 'interact';
}
if (key === 'KeyF') return 'enterExitVehicle';
if (key === 'KeyM') return 'toggleMap';
return null;
}
タッチ側は「乗車」でHUDを切り替え、ジャンプを隠し、アクセル/ブレーキ/ハンドブレーキを出します。案内にもある通り——ステアだけ効いて前進できないときは、すでに乗車していないか、前進がスティックではなくアクセルペダル依存かを先に疑います。
2. ゲームパッドは印刷キーに依存しない
iframe の allow に gamepad が含まれており、サイト側はパッド入力を通す意図があります。ボタン番号は機種ごとに違うので、キーボードショートカットをパッドへ直訳しない方が安全です。実装では navigator.getGamepads() をポーリングし、軸とボタンを同じ Intent に落としてから、共通の状態機械へ渡します。
読み込み:先に遊べて、あとから綺麗に
都市資源を「最初のHTML」で止める必要も、止めてはいけません。挙動から心象モデルを分けると:
- 外殻が触れる: 案内、開始ボタン、シアターモード/全画面
- エンジンとコア: three.js ランタイム、コントローラ、セッション
- ワールドのストリーム: 街区・車両・任務関連を必要に応じて継続取得
ユーザ向け文言でも「ホームが開いた」と「都市資源のロード」は分けられています。進捗が動いているなら待つ。完全停止ならネットワークを見て再読み込み。開発者視点では、進捗イベントは ゲーム内の資源パイプライン から出すべきで、外層 iframe の load ではありません。load は骨格HTMLの到着しか意味しません。
黒画面・カクつき・無反応:分類してから触る
モバイル/性能ガイドの分類は、WebGLページ一般にも使えます。
| 現象 | まず疑うもの | 低コストな行動 |
|---|---|---|
| 進捗未完了だが変化している | 回線と資源サイズ | 前面で待つ。連打リロードしない |
| 進捗が完全停止 | 回線断/資源失敗 | 他サイトが開くか確認し、再読み込み1回 |
| メニューは出るが街が黒/崩れる | GPU能力/画質 | 画質を「低」へ。別ブラウザで比較 |
| 街は見えるが移動が一瞬止まる | 端末負荷 | 重いタブを閉じ、同地点でFPS比較 |
| 画は正常だが入力無効 | フォーカス/UIスタック | プレイ領域をクリック。地図/スマホを閉じる |
画質段は「自動・低・中・高・極致」などが公開されており、カクつくときは下げるよう案内されています。回線が速くても黒、は矛盾しません——WebGLの滑らかさはブラウザ実装とGPU/メモリにも依存します。
もう一つ: サイトデータの消去を最初の一手にしない。 ローカルストレージに進行が載ることが多く、別ブラウザやプライベート窓はそもそも別ストレージです。消すとセーブを失い、描画原因の切り分けにもなりません。
ミニマップと任務:「押したのに効かない」
地図を開くと WASD が地図パンに変わる。任務の光輪に近づいてから E(またはタッチの「互動」)で開始。ナビ到着=任務完了ではない、という罠もあります。
状態機械としては uiStack(map/phone)を持ち、入っているあいだは移動Intentを止めるか弱める。多くの「キーが壊れた」報告は、UIスタックとキャラ制御のフォーカス争いです。
モバイル:向き・シアター・全画面は別物
- 横向き: デバイスの向き。スティックと道路の幅を稼ぐ
- 全画面: ブラウザ/OSが許すか次第
- シアターモード: 案内サイトがプレイ領域を拡大する。画質低下でもFPS保証でもない
PWAや全画面は「表示領域」の問題で、「GPU予算」の問題ではありません。落とすべきは影・解像度スケール・ポストプロセス側です。
まとめ
ブラウザ開放世界の技術選定は WebGL/three.js 系に寄りがちですが、体験を決めるのは次の地味な層分けです。
- 入力は Intent に落とし、キャラ/UI状態で解釈する
- 進捗はゲーム内パイプラインを公開し、外層
loadと混同しない - 黒画面・カクつき・フォーカス問題を分けて洗う
- セーブとキャッシュはブラウザストレージ境界を尊重する
実機確認は 臺北 GTA を開き、「開始」でプレイ領域へ入り、操作説明・地図任務・モバイル性能ガイドと突き合わせると早いです。独立ウェブゲームの面白さは、街歩きをタブ一枚に圧縮できる点にあります——その代わり、層分けを誤ると「ダウンロード不要」が「手間だらけ」に変わります。

