1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

コードを1行も書かずに26日で5.2万行。Gemini と Claude Code と「情シスのインシデント対応」ゲームを作って Steam に出した話

1
Posted at

この記事で共有すること(これからAIでゲーム・アプリを作る方へ)
AIに「数百行のスクリプト」を書かせるのは簡単ですが、「5万行・100ステージ超のゲーム」を1行もコードを書かずに作らせるとなると、普通にやれば文脈が溢れて100%破綻します。
本記事では、26日間・総計47億トークンを費やしてSteam向けゲームを完成させるまでに構築した 「AIが自走・自己検証できるハーネス設計」 と、「実際に踏んだ7つの地雷と回避策」 をすべて公開します。

1. 実証結果:26日間でAIたちと作ったもの

まずは、今回紹介する設計手法でどこまでの規模が実装できたのか、リポジトリの実数を置いておきます(v1.0時点)。

項目 規模(実数)
C# コード(Unity+端末エンジン) 約 52,200 行(137 ファイル)※人間の手書き 0 行
Python コード(台本生成・検査) 約 10,900 行(18 ファイル)
自動テスト(スモークテスト) 1,646 項目(全104話+隠しステージのクリア検証含む)
実装コマンド・シナリオ Linuxコマンド 80 種類 / シナリオ 本編 104 話+入社前研修+隠しステージ
総トークン数(Claude Code) 入力 約 47.3 億(キャッシュ98.6%) / 出力 約 1,140 万
開発期間・コミット数 26 日間(実稼働22日) / 198 コミット
変更履歴・手動テスト手順(MD) 変更履歴 167 件 / 手動テスト手順 121 節

題材は、私の21年間のSE経験を詰め込んだ、Linuxコマンドのパイプラインでブラック企業のインシデントを鎮圧するシミュレーションゲーム『戦う情報システム部』です。
qiita_88.gif

🛒 完成した成果物(Steam): 『戦う情報システム部』ストアページ(Windows 版 480 円 / 発売から7日間は 15% OFF の 408 円)

※このぐらいの開発規模になると、通常のプロジェクトと同様に、標準化や基準書のような 「仕組み(環境設計)」 が不可欠でした。

2. 役割分担と技術選定:「AIが迷わない・自分が手を動かさない」を最優先する

なぜ「Unity(C#)」を選んだのか?

CUIベースのゲームならElectronやGodotも選択肢になりますが、Geminiと壁打ちした結果、「AIが最も正確にコードを書けるか」 を基準にUnityを採用しました。

  1. Claudeの学習量と自己完結力:Unity固有のライフサイクルやuGUIの制御、C#のクラス設計は学習データが豊富で、タイピング演出やログのスクロール制御を自律的に進めてもらいやすいと判断しました。
  2. Steamworks.NETの実績:全9種の実績解除やSteam Cloudによるセーブ同期の実装も、ネット上に事例が多いためClaudeだけで迷わず実装しきれました(ストア審査ではAI利用開示の英語欄の短さとカプセル画像の文字規定で2回差し戻されましたが、ビルド審査含め無事通過しています)。
  3. 演出のシンプルさ:終盤の「警告の赤点滅」や「黒いKVMコンソール」、画面の揺れやサーバールームのファン環境音なども、複雑な機能は使わず、uGUIの色・テーマ切り替えとAudioSourceだけで完結させています。

qiita_image2_themes.jpg

4者のチーム体制:原案のGemini、実装と保守のClaude

Qiita用4人.jpg

  • プランナー 兼 監査役:Google Gemini(3.1 Pro)
    • 「ブラックジョーク」と「現場の正しい教訓」のバランスを取ったシナリオ原案、コマンドパズルのレベルデザイン
    • 完成した台本(MD)の監査、画像生成AIへ渡す英語プロンプトの作成
  • リードエンジニア:Claude Code(Opus 5 → Fable 5.1 → Opus 5.5)
    • Unity(C#)およびLinuxコマンドエミュレーター(端末エンジン)の実装
    • 原案から台本データ(Python生成スクリプト → ステージJSON)への落とし込みと台詞の手直し
    • 整合性の機械チェック、自動テスト、実機(WSL)との突き合わせ、仕様変更ごとのMD更新
  • アートディレクター:NanoBananaPro2
    • ゲーム内アセットからSteamストアのバナー作成(Geminiが作成した英語プロンプトを使用)
  • プロデューサー 兼 テストプレイヤー:私
    • 21年分の現場経験の提供、「これは面白い / これは不快」の判断、そして 「画面を見ること」

実際に開発を行った所感は、Claudeは細かいセリフの修正は指示とおりにできますが、
アイデアを出す、ブラッシュアップは非常に苦手でした。

そのため、ブラッシュアップはGemini 3.1 Proがメイン担当でした。
逆にGeminiは壁打ちする時に、「よいしょ」する傾向にあるので適宜使い分けが必要でした。

3. 【設計の核心】AI駆動開発を破綻させない2つのアーキテクチャ

AIと一緒に5万行のゲームを作り切るうえで、最も効いた設計が以下の2つです。

① ゲームの心臓部をUnityから切り離す(ヘッドレス化)

鉄則:AIはGUI(Unityエディタ)を操作できない
「Unityを起動しないと動作確認できない」設計にすると、人間が毎回テストプレイする羽目になり、開発速度が劇的に落ちます。エディタ無しで検証できる範囲をどれだけ広く取るかが核心でした。

そこで、コマンド解釈・仮想ファイルシステム・クリア判定といった 「端末エンジン」は、UnityEngine に一切触らない素のC#(Pure C#)として分離 してもらいました。
さらに、窓やボタンなどのUIもシーンファイルに手置きせず、起動時にコードで動的に組み立てる方式にし、「シーンを作り直してください」と頼まれる回数を減らしました。

これにより、Claudeはコードを直すたびにUnityを起動せず、普通のC#コンパイラでビルドして1,646個の自動検査をコマンドラインから高速に回すことができます。

② Markdown(MD)を「唯一の情報源(Single Source of Truth)」にする

生成AIとの大規模開発で最も怖いのは、文脈の取りこぼしによる時系列や設定の不整合です。Claude Codeはセッションが長くなると文脈が要約されますが、「会話は消えてもMDは残る」 ため、すべての情報をMDに集約しました。

  1. 事前定義による防波堤:世界観、時系列、登場人物、各話のクリア条件などを全てMDに定義し、実装前に必ず読んでもらう。
  2. 変更履歴の通し番号管理(全167件):仕様変更時は「変更内容と経緯」を通し番号付きでMDの上部に積む。次のセッションのAIが「なぜこうなっているのか」を引き継げます。
  3. 手で書く部分と、データから生成する部分を分ける:各話の一覧表(日時、依頼者、解放コマンド、クリア条件)は、ステージデータから毎回スクリプトで生成してMDに書き戻し、台本と資料のズレを根絶しました。
  4. 手動テスト手順もMDに蓄積(全121節):修正のたびに「何を打って、どうなれば合格か」を1節ずつ追加。人間のテストプレイはこの手順に沿って行いました。
  5. 「約束ごと」の明記:「コミットは私が頼んでから」「フォントに無い文字は使わない」といったルールもMDに残し、セッションを跨いでも守ってもらいます。

【シナリオMDファイル抜粋(仕様変更履歴)】
qiita_image3a_changelog.png

【シナリオMDファイル抜粋(各ステージ設計)】
qiita_image3b_overview.png

実際の共有資料(MDファイル)の抜粋

【登場人物とペルソナの定義例】

鈴木取締役:4システムすべて admin1234、共有フォルダに平文で一覧を置く。深夜3時に予算ファイルを開く。11/16にベンダーと密談(情シスに伝えない、ログ保存30日に短縮、作業は保守用アカウント)。「画面に出すな」「証拠を消せ、業務命令だ」。

【世界観と会社の社風定義例】

絶対的な上下関係とアナログの踏襲:役職が絶対で、デジタル上でも目上への敬意をシステムで表現しようとする。押印の角度規程41条(5〜15度左に傾けて押す=お辞儀ハンコ)は、実在する悪習をシステム化したもの。

【クリア条件の型定義例(件数はデータから自動集計)】

型 意味 使用数
run_command 指定のコマンドを打つ 118
submit_answer チャット / コンソールで答えを送る 23
kill_all_malicious 悪性プロセスを全部止める 3

4. 「破綻なく」は嘘でした。実際に踏んだ7つの地雷と解決策

MDをハブにしても破綻は起きます。大事なのは破綻を機械と人間の両方で見つける仕組みでした。チームとして実際に踏んだ地雷と、その直し方の記録です。

地雷①:検査スクリプトが「0件を読んで合格」していた

台本の矛盾を見つける検査スクリプトが、台本の場所を相対パスで持っていました。

STAGES = os.path.join("Assets", "StreamingAssets", "Stages")   # 実行した場所に依存する

別のディレクトリから実行すると1話も読めず、それでも「台本の表紙と中身は一致しています」と表示して通っていました。実行場所を変えた際に結果が変わったことから、Claude自身が原因を突き止めてくれました。

  • 解決:パスをスクリプトの場所基準で解決し、1件も読めなければ失敗にするよう修正。直した途端、隠れていた食い違いが5件出てきました。
  • 教訓:検査を作ったら、「わざと壊して、落ちること」を一度いっしょに確かめる。合格の表示は何も証明しません。

地雷②:黙って捨てられる設定キー

52話は「台帳に無いサーバーに ping を打って生存確認する」回ですが、ping が 100% loss なのに依頼者が「到達性を確認しました」と返すバグにテストプレイで気づきました。

qiita_image4_ping.png

原因は、台本が hosts というキーで書いていたのに、読み込み側は reachableHosts しか読まないこと。知らないキーが黙って無視されるため、エラーが出ませんでした。

  • 解決:生成スクリプト側で設定キーを読み込み側の一覧と突き合わせ、知らないキーがあれば停止する仕組みを導入(全104話中、この1件だけでした)。
  • 教訓:似た名前の取り違えは人間でもAIでも起きます。「寛容な読み込み」はバグを隠すので、黙って通さない仕組みにする。

地雷③:小さな追加の積み重ねが、TextMeshProの上限(16,383個)を踏み抜いた

33話でゲーム内ブラウザのマニュアルを開くと、前のページの文字が崩れて残り IndexOutOfRangeException が発生しました。

qiita_image5_before.png

原因はTextMeshProの上限(テキスト1つが持てる四角形は16,383個まで)でした。コマンド説明や図解など「1つずつは小さな追加」をお願いし続けた結果、24話で上限を超え、最終話では4〜6万個に達していました。

  • 解決:ClaudeがスタックトレースからTextMeshProのソースまで読み、全話のページサイズを実測したうえで、本文を5,000個分ずつの塊に分けて描く方式を提案・実装してくれました(分割位置の判定はファズテストで検証済み)。
  • 教訓:頼めば快く足してくれるからこそ、量の上限は頼む側も頼まれる側も見ていない。節目で実測してもらう。

地雷④:最初のコミットから壊れていた成績保存(AI同士のクロスレビューで発覚)

「読み込む」関数に「成績を復元する」副作用があり、自動保存のたびに成績がファイルの内容へ巻き戻っていました。落ちないしエラーも出ないので誰も気づきません。

  • 解決:コミット前にClaudeが走らせたAIどうしの複数観点レビューで発覚しました。観点ごとにレビュー役を立て、見つかった指摘は別のAIに「反証できないか」を検証させ、生き残った5件を修正しました。
  • 教訓:人間のチームと同じで、書いた本人とは別の目(別の観点、反証役)を必ず通す。

地雷⑤:「実機と同じですか?」には、知識ではなく実機(WSL)で答えてもらう

教育目的のため「実機と同じ動き」にこだわりました。top を q で抜けたとき画面が消えるか尋ねた際、Claudeは「知識からの判断で、実機では確かめていません」と正直に添えてくれました。そこでPC内のWSL(Ubuntu)で疑似端末ごと出力を記録し、制御文字を数えて検証してもらいました。

コマンド 代替画面に入る(ESC[?1049h) 代替画面から戻る(ESC[?1049l) 抜けるとき
top(procps-ng 3.3.16) 0 回 0 回 画面は消さない。最後の1枚が残る
less 1 回 1 回 元の画面に戻る

同じやり方で、sed のエラー文の文字位置が1つずれている(実機は char 11、ゲームは char 12)ことも見つかりました。

  • 教訓:AIが確かめに行ける実機(WSLで十分)を用意し、「確認した事実」と「知識からの推測」を分けて報告してもらう。

地雷⑥:提案の前提が間違っていた、と自分から報告してもらう

端末履歴の上限を「15,000字にしましょう。ふつうの出力はずっと少ないので」とClaudeが提案し了承しましたが、実装直前にClaudeが全104話の出力量を測り直し、「本編のログ28本が15,000字を超えます。先ほどの説明は誤りでした」と報告してくれました。

  • 教訓:数字を伴う提案は実装前に実測してもらう。間違いの報告を歓迎する言い出しやすい関係のほうが、結果として品質が上がります。

地雷⑦:画面はAIに見えない

「ページ番号が紙の真ん中に出ている」「文字が重なっている」「シーンに保存された値がコードの既定値より優先されている」といった不具合は、画面が見えないAIには自力で観測できません。私がスクリーンショットを撮って渡すのが最速でした。
qiita_image6_before.png

  • 教訓:人間は「目」と「判断」、AIは「ログと原因と修正」。テストプレイ(2周しました)は省略できません。

5. 品質を支えた仕組み:直すたびに回す6つの自動検証

修正のたびに、Unityを起動せず以下の検査をすべて自動で通してもらいます。

  1. 台本の生成(Python → ステージJSON)と、台本どうしの突き合わせ
  2. スモークテスト(検査 1,646 個):端末エンジンをUnity無しでコンパイルし、全話の正解手順を実際に打ってクリアできるか検証
  3. Unity向けのコンパイル確認
  4. フォント検査:使用フォントに無い全角の「!」「?」などが混ざると豆腐(文字化け)になるため、全ファイルを走査
  5. 保存データの消し漏れ検査
  6. 変更履歴とテスト手順のMDを更新

qiita_image7_checks.png

6. 実際にかかったもの:モデル、プラン、トークン、期間

Claude Codeのセッション記録(JSONL)から、コーディング開始からv1.0ビルドまでの全セッション分を重複除外して集計した実数です(Geminiと画像生成AIの分は含みません)。

開発期間(26日間 / 実稼働22日)

項目 日付
コーディングの開始(最初のコミット) 2026-09-05
全 100 話に増補 2026-09-07
全 104 話・隠しステージの作り直し(台本の第6版) 2026-09-14
2 周目のテストプレイの直し 2026-09-18
Steam に繋ぐ(実績、ビルドと配信の仕組み) 2026-09-25
v1.0 のビルド(凍結) 2026-09-30

使用モデルとトークン内訳

モデル 使った期間 主に一緒にやったこと 応答の数 出力トークン
Claude Opus 5 9/5〜9/14 端末エンジンと画面の土台、全100話の骨組み、KVMコンソール 約 4,100 回 約 462 万
Claude Fable 5.1 9/8〜9/25 研修と設定、全104話への作り直し、実機との総点検、2周目の直し 約 2,800 回 約 497 万
Claude Opus 5.5 9/25〜9/30 Steam対応(実績・クラウドセーブ・配信)、リリース前の監査 約 3,200 回 約 175 万

(※このほか、9/10〜9/12に Claude Opus 4.8 の応答が13回あります)

項目 トークン量
出力(AIが書いたコード、台本、説明、報告) 約 1,140 万
入力(毎回送り直される会話の文脈を含む) 約 47 億 3,000 万
うちキャッシュからの読み直し 約 46 億 7,000 万(98.6%)
うち新しく読み込んだもの 約 6,500 万
応答の総数 約 1 万回

はじめにClaudeProから開発をスタート(Opus5.0使用)しましたが、結局トークン量不足と品質の悪さから、Claude Max 5x に変更(Fable5.1使用)しました。それでもトークンが足りず、Claude Max 20xプラン(Opus5.5使用)までいきました。

特にOpus5.0ではデグレードが多く、Fable5.1にアップグレードしましたが、品質とのトレードオフで、トークンの使用量がすさまじかったです。Opus5.5がローンチされてトークンの使用量が落ち着いて、助かりました。

基本はOpus5.5でエフォートを超高にし、UltracodeをONにすることでトークンと品質が一気に安定しました。

APIの従量課金ではなく定額プランだったからこそ、毎回のスモークテスト出力の読み取りや長大なMDの読み込みをためらわずに1万回回すことができました。

おわりに:エンジニアの皆様へ

「AIと作った」の実態は、 「AIに作ってもらい、AI に検査してもらい、私が遊んで判断した」 です。
人間がプロデューサーとしてMDのハブと検証環境を用意し、頼みっぱなしにせず画面を見て、遊んで、決める(たとえば、テストプレイで少しでも不快に感じたBGMや煽り演出は外し、裏エンディングでファンの音だけを残す静かな演出を選びました)。それが人間側の持ち場でした。

ゲーム本編には、こんな「現場のリアル」と「Linux哲学の快感」を詰め込んでいます。

  • ps aux | grep enc-worker | awk '{print $2}' | xargs sudo kill -9 の1行で、12個の暴走プロセスをまとめて止める
  • 2万行の syslog から、grep で怪しい8行だけを抜き出す
  • 最後の手段は、警備員さんに走ってもらい、LANケーブルを物理的に引き抜くこと

『戦う情報システム部』は、理不尽な社会とシステムに向き合うすべてのエンジニアへのラブレターです。

21年分の現場のリアルを詰め込んだ「Linux哲学のカタルシス」を、ぜひ体験してみてください。
(IT業界未経験の方は、ぜひCUI環境の練習場としていかがでしょうか。)

🎮 Steam ストアページはこちら: 『戦う情報システム部』

価格は 480 円です(発売から7日間は15%引きの 408 円、約コーヒー1杯分)。Windows(64bit)専用です。
※ゲーム内のコマンドはすべて仮想環境の上で動き、ご自身の PC のファイルには一切触れないので、安心して打ってください(ちなみに rm -rf / は、ゲームの中でもちゃんと止められます)。

まだ遊ぶ時間が取れない方も、ウィッシュリストに入れていただけると励みになります!

プロンプトの工夫や、AI同士の連携フローについて気になることがあれば、ぜひコメントでご質問ください!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?