ブラウザゲームを自動テスト&デプロイ⑥|puppeteerヘッドレス検証と静的配信【Archipelago Saga制作・完結】

アプリの作り方

ブラウザゲームを自動テスト&デプロイ⑥|puppeteerヘッドレス検証と静的配信【Archipelago Saga制作・完結】

約1万行・6地域49ステージのゲームを、毎回手で全クリアして「壊れていない」と確認していられない。だから「動いている」を機械に証明させる。タイトルから戦闘・リザルトまでをロボットに通しプレイさせ、「コンソールエラー0・画像/音声の404ゼロ」を合格条件にする。そして配布は、ビルドが無いから静的ファイルを置くだけ。連載最終回は、自動検証とデプロイを実コードで開く。

▶ 第5回(AIアセット量産)までで部品は揃った。全体像は連載ハブ。完成品はここで遊べる(この公開も、本記事の「置くだけデプロイ」の成果だ)。

目次
  1. 最終回のゴール
  2. Step 1. なぜ自動検証なのか
  3. Step 2. puppeteer で通しプレイする
  4. Step 3. 戦闘オートパイロット:DOM非依存設計が効く
  5. Step 4. 完了条件:「エラー0・404ゼロ」
  6. Step 5. デプロイ:ビルドが無いから「置くだけ」
  7. 運用のコツ:検証を「回し続ける」ために
  8. 連載のまとめ:「小さく完成させ切る」設計

最終回のゴール

(1) puppeteer でゲームをヘッドレス(画面なし)通しプレイし、(2) コンソールエラー0・404ゼロを完了条件に自動検証し、(3) 静的ファイルを置くだけで本番公開する。この3点を実装する。第1回の「無ビルド」と第3回の「DOM非依存」が、ここで一気に回収される。

Step 1. なぜ自動検証なのか

個人開発で一番怖いのは「どこかを直したら、別のどこかが静かに壊れる」回帰だ。手動テストは抜けるし、毎回は続かない。そこでロボットに毎回、同じ通しプレイをさせる。人間は「新しく作った所」に集中し、「前から動いていた所」は機械に見張らせる。これが小規模でも完成まで走り切るコツだ。

図1:ロボットが通しプレイして「壊れていない」を証明する puppeteer起動file:// で開く 自動操作ループシーン監視→クリック 収集console error / 404 0 なら✅合格 title → party → story → worldmap → battle → result まで自動で踏破。 各シーンでスクショも保存し、目視確認も残す。

Step 2. puppeteer で通しプレイする

第1回の「file:// で動く」が、ここで効く。サーバーを立てずに index.html を直接開いて操作できる。鍵は「今どの画面か」をゲーム自身に聞けること。第1回で G.game.current に現在シーン名を持たせておいた。

// scripts/shot_game.js(抜粋)
const url = "file:///" + path.resolve("game/index.html").replace(/\\/g, "/");
const b  = await puppeteer.launch({ headless: "new" });
const pg = await b.newPage();

const errs = [];
pg.on("console",  m => { if (m.type() === "error") errs.push(m.text()); });  // ① コンソールエラーを集める
pg.on("pageerror", e => errs.push("PAGEERR " + e.message));                  //    例外も集める
await pg.goto(url, { waitUntil: "networkidle0" });

// 「今どの画面か」をゲームに聞く(第1回の G.game.current)
const scene = () => pg.evaluate(() => (window.G && G.game && G.game.current) || null);
const waitScene = async (name, ms = 8000) => {
  const t0 = Date.now();
  while (Date.now() - t0 < ms) { if ((await scene()) === name) return true; await sleep(120); }
  return false;
};

await pg.click("#btnNew");          // 「はじめる」
await waitScene("party");           // 編成画面になるまで待つ
const cards = await pg.$$(".hero-card");
await cards[0].click(); await cards[2].click(); await cards[4].click();  // 3人選ぶ
await pg.click("#go");              // 出発

waitScene("party") のように「目的の画面になるまで待つ」のが安定動作の肝。固定の sleep だけに頼ると、遅い環境で取りこぼす。ゲームが状態を公開しているから、ロボットは「画面が変わった」を正確に検知できる。

Step 3. 戦闘オートパイロット:DOM非依存設計が効く

戦闘は、コマンドメニューが出たら「こうげき → 倒せる敵をクリック」を繰り返すだけ。第3回で戦闘ロジックを画面から切り離したおかげで、挙動が安定し、こうした機械操作が決定的に楽になる。

// 戦闘が終わるまで自動で殴り続ける
let guard = 0;
while ((await scene()) === "battle" && guard++ < 120) {
  const ready = await pg.evaluate(() => {            // 自分の手番(コマンド表示)か?
    const c = document.querySelector("#cmd");
    return c && !c.classList.contains("hidden") && !!c.querySelector('.cbtn[data-c="attack"]');
  });
  if (ready) {
    await pg.evaluate(() => document.querySelector('.cbtn[data-c="attack"]').click());  // こうげき
    await pg.evaluate(() => { const t = document.querySelector(".unit.enemy.targetable"); if (t) t.click(); }); // 標的
  }
  await sleep(300);
}
const after = await scene();   // "result"(勝利)に遷移していれば成功

guard++ < 120無限ループの保険。万一どこかで詰まっても、120手番で打ち切ってレポートする(CIがハングしない)。「ちゃんと result に着いたか」で勝敗まで自動判定できる。

Archipelago Saga のバトルリザルト画面(VICTORY)
puppeteer の通しプレイが到達するリザルト画面。DOM非依存の戦闘コアだから、タイトル→戦闘→リザルトを自動で走らせ、「コンソールエラー0・画像/音声の404ゼロ」を機械的に確認できる。

Step 4. 完了条件:「エラー0・404ゼロ」

通しプレイが終わったら、集めたエラーを数える。1件でもあれば不合格。これを CI(あるいは手元のワンコマンド)の合格条件にする。

// 画像・音声の読み込み失敗(404)も拾う
const failed = [];
pg.on("requestfailed", r => failed.push(r.url()));
pg.on("response", r => { if (r.status() === 404) failed.push("404 " + r.url()); });

// …通しプレイ後…
console.log("console errors:", errs.length, errs);
console.log("404 / failed   :", failed.length, failed);
if (errs.length || failed.length) process.exit(1);   // ← 1件でもあれば失敗で終了
console.log("✅ 通しプレイOK:エラー0・404ゼロ");

なぜ404を重視するか。第5回で作った立ち絵や背景のファイル名が、データの art パスと1文字でも食い違うと404になる。それをロボットが通しプレイの中で必ず踏んで検出してくれる。「エラー0・404ゼロで最後まで遊べた」を緑信号にすれば、リリース前の不安がほぼ消える。

🔎 設計が検証を可能にしている:これが効くのは偶然ではない。(1) 無ビルド(第1回)だから file:// で即起動できる。(2) シーン名を公開(第1回)しているからロボットが画面を追える。(3) 戦闘がDOM非依存(第3回)だから挙動が安定する。テストしやすい設計を最初に選んだ報酬が、ここで返ってくる。

Step 5. デプロイ:ビルドが無いから「置くだけ」

そして公開。第1回で webpacknpm run build も使わないと決めた。その恩恵が最後に効く。配布物は「静的ファイル一式」そのもの。ビルド成果物の生成も、依存解決の事故も無い。サーバーに js/ css/ assets/ index.html を置けば、それで公開完了だ。

図2:無ビルド=静的ファイルを置くだけ 静的ファイルjs / css / assets 最適化(任意)png→webpで軽量化 アップロードzip→SFTP→展開 公開URLで遊べる ビルド成果物なし=置くだけ。配布版(Tauri)も同じ静的ファイルを同梱するだけ。

実運用では、転送量と表示速度(LCP)のために本番だけ画像を webp 化している。大きな .png 参照を .webp に書き換えた最小サブセットを作り、zip で固めてアップ、サーバー側で展開する、という1コマンドにまとめてある。

# デプロイの流れ(要点)
# 1) 本番用サブセットを作る(js/css の .png 参照を .webp に書換え、画像をwebp化)
# 2) zip に固める  →  3) SFTP で /tmp へ送る  →  4) サーバーで unzip して上書き配置
$ python scripts/deploy_archipelago.py        # 上記を一括実行(dry-run も可)

# 配置先はただの静的ディレクトリ:
#   /game/archipelago/{index.html, js/, css/, assets_ai/, audio/}

ポイントは、ローカル開発(生の .pngfile://)と本番(.webp・サーバー配信)を切り替えても、ゲームのコードは一切変わらないこと。最適化は配信時の置き換えに閉じている。デスクトップ配布版(Tauri)も、この同じ静的ファイルを実行ファイルに同梱するだけだ。

運用のコツ:検証を「回し続ける」ために

自動検証は、回し続けた月日が価値になる。運用で効いた工夫を3つ残しておく。

  • 不安定な待ちを作らない … 固定 sleep は環境の速さで結果が揺れる(フレークの温床)。waitScene() のように「状態が変わるまで待つ+上限時間」の形に統一すると、遅いPCでも安定して同じ結果になる。
  • 落ちたときの証拠を残す … 各シーンでスクショを保存しているのは、鑑賞用ではない。失敗した実行の「最後の画面」が残っていれば、エラー文だけでは分からない「どこまで進んだか」が一目で分かる。
  • 実行の入口を1コマンドにする … node scripts/shot_game.js の一発で最後まで走るから、修正のたびに気軽に叩ける。手順が2つ以上あるテストは、忙しい日に必ずスキップされる。検証は、実行の摩擦が小さいほど文化として根づく。

通しプレイの守備範囲も正直に書いておく。この検証がカバーするのは「本編の一本道」(タイトル→編成→マップ→戦闘→リザルト)で、ショップ・図鑑・ステータスのようなサブ画面は素通りする。サブ画面の壊れ方は「開いた瞬間にエラーが出る」型が大半なので、対策も軽くていい。全シーンを G.game.show() で順に開いてエラー0を確かめるだけの「全画面スモーク」を1本足せば、通しプレイの死角はほぼ埋まる。深いテストを1本と、浅いテストを全面に。この組み合わせが、労力あたりの検出力で一番効率がいい。全部を深くテストしようとすると書く方が先に力尽きるし、全部を浅くすると肝心の戦闘の壊れを見逃す。守るべき中心がどこかを決めてから、テストの深さを配る。

この構成は GitHub Actions などのCIにもそのまま載る。push のたびに通しプレイが走り、緑のチェックが付く形だ。個人開発でそこまでやるかは規模次第だが、「載せられる形になっている」こと自体が、検証設計の健全さの証明になる。手元で1コマンドで走る物は、どこでも走る。逆に、手元で儀式が要る物は、自動化しようとした瞬間に儀式が全部露呈する。

ツール選びの補足も1つ。ここでは puppeteer を使ったが、同種の Playwright でも同じ構成が組める。効いているのは、「シーン名を公開する・状態変化を待つ・エラーと404を数える」というゲーム側の作りの方だ。そこさえ守れば、自動化ツールは好みで選んでいい。

連載のまとめ:「小さく完成させ切る」設計

全6回で、ブラウザで通しクリアできる JRPG を最初から組み上げた。貫いているのは一つの思想、「派手な技術より、完成させ切れる構成」だ。

  • ① 無ビルドfile:// で動く。読込順が設計図。window.G に集約。
  • ② データ駆動:中身を純データに。コンテンツ追加は「データ追記だけ」。
  • ③ DOM非依存の戦闘コア:ロジックは画面を知らず、イベント配列を返すだけ。
  • ④ 状態を1つに:マップ・進行・セーブを S 1オブジェクトに集約。
  • ⑤ AI量産フロー:生成→透過→正規化→配置を型に。絵が描けなくても揃う。
  • ⑥ 自動検証+静的デプロイ:ロボットが通しプレイで証明。公開は置くだけ。

これらの工夫は互いに支え合っている。無ビルドだから検証が即起動でき、DOM非依存だから検証が安定し、データ駆動だから量産が回る。最初に「テストしやすく・増やしやすい」骨格を選べば、絵が描けなくても、1人でも、ゲームは最後まで完成する。

あとは、あなたの番だ。第1回の「最小で動く土台」を写経するところから、始めてみてほしい。4ファイルの土台が動いた瞬間が、あなたのゲームの起工式になる。

AI生成コンテンツの開示:本作の BGM・効果音・キャラクター画像・ボイスは、すべて生成AIの出力物です(BGM=ACE-Step 1.5〈MIT・出力の商用利用可を配布元モデルカードで確認済み〉 / ボイス=Irodori-TTS 系の合成設計音声・実在人物の複製ではありません / 効果音=数値合成 / 画像=画像生成AI〈各サービスの利用条件で出力の商用利用可を確認のうえ使用。透過処理は BiRefNet〈MIT〉を rembg 経由で使用〉)。第三者の著作物は同梱していません。© 2026 Cooliris(本作のコード・構成・データの権利は作者に帰属します)。


👉 ← 第5回:AIアセット量産第1回から読み直す連載ハブ▶ 完成版を遊ぶ

AIでゲーム素材を量産する⑤|生成→透過切り出し(BiRefNet)→配置のパイプライン【Archipelago Saga制作】AIでゲーム素材を量産する⑤|生成→透過切り出し(BiRefNet)→配置のパイプライン【Archipelago Saga制作】前のページ

ブラウザで動く都市開発シミュを作る①|React+TypeScript+Canvasの土台と3レイヤ設計【Aurum City制作】次のページブラウザで動く都市開発シミュを作る①|React+TypeScript+Canvasの土台と3レイヤ設計【Aurum City制作】

ピックアップ記事

  1. New Eden Intelligence Hub の作り方 — EVE Onl…

  2. 高精度OCRデスクトップアプリの作り方 — PaddleOCR-VLとPyIns…

  3. Claude Mission Control の作り方 — Tauri+Pyth…

  4. 競艇予想AIの作り方 — LightGBMで「当たる順位」を学習させる実装ガイド…

関連記事

  1. JavaScriptでRPGを作る③|CTB戦闘システムをDOM非依存で実装する【Archipelago Saga制作】

    アプリの作り方

    JavaScriptでRPGを作る③|CTB戦闘システムをDOM非依存で実装する【Archipela…

    FFX風のCTB(チャージタイム制)戦闘を、画面(DOM)から完全に切…

  2. large-v3-turbo は large-v3 の代わりになるか。日本語で測って、速度の測り方を2回間違えた記録
  3. JavaScriptでRPGを作る④|ワールドマップ・シーン遷移・セーブ(localStorage)【Archipelago Saga制作】

    アプリの作り方

    JavaScriptでRPGを作る④|ワールドマップ・シーン遷移・セーブ(localStorage)…

    ステージデータから蛇行するワールドマップを描き、クリアでロックを解放し…

  4. New Eden Intelligence Hub の作り方 — EVE Online の SSO×ESI API で市場・資産・戦闘を一画面に集約する自分専用ダッシュボード

    アプリの作り方

    New Eden Intelligence Hub の作り方 — EVE Online の SSO×…

    自作の EVE Online 統合ダッシュボード「New Eden I…

注目

AIで、ここまで作れる

AIで作った2D RPGを、ブラウザでそのまま遊べます。その「作り方=最後まで完成させる進め方」も実例つきで公開中。

▶ ゲームを遊ぶやり方を読む

PR

ロリポップ!レンタルサーバー(PR)

レンタルサーバ:ロリポップ!(本サイトの稼働環境・PR)

  1. 都市開発シミュを作る⑤|「面白くない」を目標・施設・イベント・音の4軸で解消【Aurum City制作】

    アプリの作り方

    都市開発シミュを作る⑤|「面白くない」を目標・施設・イベント・音の4軸で解消【A…
  2. アプリの作り方

    MiniMax H3のライセンスを条文まで読んだ — 地域制限と、H3の規約には…
  3. ゲーム感覚でIT・AI用語500選を覚える学習アプリの作り方 — XP・13ランク・実績で「続く」を設計する

    アプリの作り方

    ゲーム感覚でIT・AI用語500選を覚える学習アプリの作り方 — XP・13ラン…
  4. 都市開発シミュを作る⑥|静的ビルドをWordPressへ公開+連載総括【Aurum City制作・完結】

    アプリの作り方

    都市開発シミュを作る⑥|静的ビルドをWordPressへ公開+連載総括【Auru…
  5. AnimeGen のライセンスを条文まで読んだ — SDXL の挿絵を動かす前に確認したこと

    AI・テック動向

    AnimeGen のライセンスを条文まで読んだ — SDXL の挿絵を動かす前に…
PAGE TOP

TAG CLOUD

ドラッグで回転・クリックでそのタグの記事一覧へ