ものがたり
序章:器は整い、しかし魂がなかった
第4章でブラウザへの扉が開かれた。pygbagが動き、UIが英語で輝いた。
しかし冒険者たちが気づいたのは ── 「このゲーム、クリアできない」 という事実だった。
- 戦闘でダメージが常に5固定(プレイヤーの強さが意味をなさない)
- 敵を倒しても経験値が入らない
- 封印に失敗すると未定義変数でクラッシュする
- マップは12枚あるが、どこをどう進めばゴールかわからない
- UIやデータに日本語が混在し、ブラウザで文字化けする
- 総大将「ぬらりひょん」は存在するが、辿り着く手段がない
ゲームとしての「魂」── シナリオと完結性 ── を吹き込む時が来た。
今回のクエスト:「ぬらりひょんを倒せるゲームを完成させ、その瞬間を記録する」
第一の試練:バグの魔王三兄弟
最初に立ちはだかったのは、P0(致命的)バグの魔王三兄弟だった。
長男:固定ダメージの呪い
どんなに強くなっても攻撃力が「5」固定。勇者の成長は完全に無意味だった。
次男:経験値ゼロの罠
敵を何体倒しても add_exp() が呼ばれず、永遠にLv.1のまま。
三男:msg 未定義クラッシュ
封印に失敗した瞬間、ゲームが例外で落ちる。
秘宝:ATKベースのダメージ計算式
damage = max(1, player.attack + random.randint(-2, 2))
たったこの1行で、三兄弟は全滅した。ついでに勝利時に add_exp(exp_reward) を呼び出し、レベルアップをUIに通知するシステムも整備した。
第二の試練:散らばった世界と文字化けの霧
バグを倒した次の試練は 「世界の混乱」 だった。
12マップという迷宮: 東京から鳥取まで12枚のマップがあったが、どこがゴールなのか不明。プレイヤーがどう進めばぬらりひょんに辿り着けるのか、道筋がなかった。
日本語データの霧: マップ名「東京都・浅草」、妖怪名「カッパ」、NPC台詞「こんにちは」── JSONデータが日本語のまま残り、ブラウザでは文字化けの霧に覆われていた。
AI NPCの重さ: Gemini APIを呼び出すAI NPCが実装されていたが、ブラウザ(Wasm)環境では動作しない。複雑さだけが残り、ゲームを重くしていた。
秘宝:3マップ集中と英語統一
世界を3つに絞った:
Tokyo - Asakusa → Tochigi - Nikko → Kyoto - Gion
カッパを倒し、大天狗ボスを倒し、ぬらりひょんを倒す。シンプルで明確な一本道が生まれた。
全テキストを英語化: yokai_list.json・items.json・全マップJSONの名前・台詞・説明をすべて英語に統一。文字化けの霧が晴れた。
AI NPCを削除: ai_service.py を削除し、NPCの台詞はJSONの静的メッセージに一本化。シンプルイズベスト。
第三の試練:新たな妖怪たちの降臨
ゲームのシナリオが固まった。だが、主役の妖怪たちのスプライトが貧相だった。
OpenCV依存のasset_generatorスクリプトは機能せず、画像生成APIもこのセッションでは利用不可。
しかし、道はあった。
秘宝:Pillowによるピクセルアート手描き
# 32x32ピクセルを1ドットずつ描く
from PIL import Image
img = Image.new("RGBA", (32, 32), (0,0,0,0))
rect(img, 11, 7, 10, 8, skin_color) # 頭
rect(img, 10, 5, 12, 4, dish_color) # 皿
Pillowで1ピクセルずつ描画することで、カッパ・天狗・ぬらりひょん・プレイヤーの4体を新規生成。特にぬらりひょんは長く伸びた頭部と紫のローブを持つ神秘的な老人として表現された。
第四の試練:記録せよ、その瞬間を
全ての試練を乗り越え、ゲームが完成した。
残るは 「ぬらりひょんを倒す瞬間を記録する」 という最後のクエスト。
ブラウザのキー操作は不安定。OpenCVは未インストール。しかし Pillow があった。
秘宝:ヘッドレスpygame + GIF自動生成
os.environ["SDL_VIDEODRIVER"] = "dummy" # ウィンドウを開かず描画
# pygame.image.tobytes() でフレームをキャプチャ
# PIL.Image で各フレームを結合してGIF生成
SDL_VIDEODRIVER=dummyでheadlessモード起動し、pygameイベントをコードから直接注入。タイトル画面→東京フィールド→カッパ戦→日光→大天狗ボス戦→京都→ぬらりひょん最終決戦→エンディング画面まで、77フレームのGIFが誕生した。
エンディング画面には「The Great Yokai Lord Nurarihyon has been defeated. Peace has returned to Japan.」の文字が刻まれた。
【ステータス画面】Developer Status: Lv.5
試練を乗り越え、私のステータスは以下のように更新された。
| 項目 | ステータス | 備考 |
|---|---|---|
| 称号 | シナリオ完成者 (Lv.5) | ゲームを「遊べる状態」から「クリアできる状態」へ引き上げた者 |
| メイン武器 | JSON + Python | データドリブンの設計で世界を自在に操る力 |
| 習得スキル | Scenario Engineering | ストーリーフラグ管理でゲームの物語を制御する力 |
| 習得スキル | Headless GIF Capture | pygameをheadlessモードで動かし、プレイを自動録画する力 |
| 習得スキル | Pixel Art Coding | Pillowで1ドットずつキャラクタを描く職人技 |
| 現在の任務 | ゲームの磨き上げ | クリアできる骨格は完成。次は体験の質を高める |
成果物
技術知見
1. AIエージェント開発の全体像
今回のプロジェクトは「AIにゲームを作らせる実験」として始まった。使用したのは Antigravityと、Claude Code 環境。
プロジェクト構成の核心:
-
CLAUDE.md(コンテキストファイル):セッションをまたいでもAIがプロジェクトを即座に把握できるよう、ディレクトリ構成・実行方法・コード規約・シナリオ概要をルートに配置。これがなければ毎回ゼロから説明し直しになる。 -
projectrules.md:ゲーム固有のルール(ワープゾーンは通行可能タイル上に置く等)をAIに記憶させる設計書。AIの「迷い」を防ぐ。 -
スキル(
.claude/skills/):繰り返す作業(アセット生成・E2Eテスト・ブログ投稿)をスキルとして定義。AIが手順を忘れない。
2. データ駆動設計の重要性
「ハードコードしない」原則を徹底した。
data/
yokai/yokai_list.json ← 妖怪データ(名前・HP・ATK・スプライトパス)
maps/kanto/tokyo.json ← マップ(タイル・シンボル・ワープゾーン)
items.json ← アイテム定義
maps/tile_properties.json ← タイルの通行可否
AIはJSON追加だけで妖怪・マップ・アイテムを増やせる。これにより「AIがコードに触れなくてもコンテンツを追加できる」状態になった。
3. AIエージェントの「品質保証」設計
最大の教訓:「AIが完了と言っても信じるな」
AIは「実装した」と報告しても実際には動いていないことが多い。この問題を解決するために以下の仕組みを構築した。
① ヘッドレスE2Eテスト(scripts/e2e_scenario_test.py)
os.environ["SDL_VIDEODRIVER"] = "dummy" # ウィンドウなしでpygameを起動
# pygame.event.post()でキー操作をコードから注入
# 各シーンで状態を検証し、PASSかFAILを記録
② GIF自動録画(scripts/capture_gif.py)
# headlessモードでゲームを動かしながら各フレームをPillowでキャプチャ
frames[0].save("recordings/playthrough.gif", save_all=True, append_images=frames[1:])
③ 開発ログの義務化(docs/logs/develop_summary_YYYYMMDD.md)
毎セッション終了時に改善ポイント・実装詳細・既知課題を記録。AIが次のセッションでコンテキストを引き継げる唯一の手段。
4. AIへの指示設計(プロンプトエンジニアリング)
AIと長期間・複数セッションにわたって開発する際に有効だったアプローチ:
「何を作るか」より「なぜ作るか」を先に伝える
❌ 悪い例:「battle_state.pyを修正して」
✅ 良い例:「バトルでEXPが入らないP0バグがある。原因はadd_exp()が
呼ばれていないこと。ATKベースのダメージ計算も同時に修正して」
スキルによるワークフロー標準化
繰り返すタスク(スプライト生成・テスト実行・ブログ投稿)はスキルファイルとして定義し、/skill_nameで呼び出すだけにする。手順が標準化されると品質が安定する。
まとめ
AI駆動開発の勘所
今回の取り組みが厳密にAI駆動開発に当てはまるのかはわかりませんがAIを活用した開発を行うにあたり、私が感じた重要な使いどころのポイントは、抽象的な表現が多く恐縮なのですが大きく以下の3つがありました。
1. AIの成果物の品質を担保すること
AIに指示をすれば とにかく動くもの は簡単に作ってくれます。
ただ、機能を拡張したり、設計通りの動きとなっているかはまた別で、意外と適当な部分が多いと感じました。
そのあたりは、やはりテストを実行してチェックしたり、品質を担保するためのチェック観点を明確にすることが重要と感じました。
やり方は、テスト自体を自動化したり、チェックの仕組みをSkillとしてナレッジ化したりと、AIを活用した効率化の方法は色々ありました。
2. どういうシステムにしたいかという設計思想
何となくの指示でもそれなりのものができる様に見えるが故に意識しなくなっていたのですが、そもそもどういうアーキテクチャでシステム(本記事はゲーム)を組むべきか、最終的にどういう仕様にすべきか、それらを確認するためにはどういうドキュメントで整理するのが適切か、という作り手の意思が重要に感じました。
これがないと、何となく作っているがゴールが分からない、AIの成果物の善し悪しが判断できない、という状態に陥りやすい様に感じました。
3. 型をつくる
ログの残し方にしても、残すべきドキュメントにしても、ブログ記事のたたき台の作成にしても、
ルールや残すべき情報を型として定義できることがAIを活用した開発では必要だと感じました。
自分がこんな感じに作りたい、アウトプットが欲しい、と思っていることをなるべく詳細に言語化し、使いまわせるSkillやフォルダ構成に落とし込むことができてから、やっと納得のいく開発を進めていく感覚が出てきていた気がします。
感想
AI駆動開発というものを体験してみたくて全部で5回に渡りRPG開発を題材にAIエージェント(AntigravityとClaude)を使ってきました。
最初は何となく作りたいものを打ち込んで、出てきたものを動かすだけだったのですが、最終的にはテストやブログ記事のたたき台を作成させるところまで使うことができました。
最初の記事を作成してから3か月の間にツールやモデルのアップデートもめまぐるしく、できることがどんどん増えていくのは純粋に驚きがありました。
ただ、あまり考えずに使っていると、ただ成果物は出るもののそれで終わり。自分で開発した感覚もなく、楽しさがない状態にも陥りやすいと感じました。
月並みではありますが、これは今後のエンジニアとしての楽しさが、コードを書くところから、システム全体のアーキテクチャや開発のマネジメントなどの上流側に比重が増えていくということなのかなと感じました。(そもそもコードを書くことがエンジニアの楽しさだというのも人には寄ると思いますが、、)
これまでの記事






