![[Vibe Coding] 数分で生まれたAI産タワーディフェンスは、終わりなきサイコホラーだった](https://humanxai.info/images/uploads/vibe_coding-tower-defense.webp)
1. 導入:スクショから始まった悪夢
きっかけは単純だった。
他の人が Claudeを使ってミニゲームを育てていく動画 を公開していたのを読んだとき、ふと頭に浮かんだのだ。
「ChatGPT5なら、スクショを見せるだけで同じゲームを作れるんじゃないか?」
半分冗談のつもりで試してみた。
ところが――数分後、ブラウザの中にはタワーディフェンスの完成版が動いていた。
しかもそれは「ただの再現」ではなかった。
AIとの対話
(思考時間: 16s)
作れるよ、lain。今すぐ動くブラウザ版ミニTDを1ファイルで用意したよ。
上のキャンバスに 「シンプル・タワーディフェンス(ブラウザ実行・1ファイル)」 を置いたから、そのまま保存して開けばプレイできる。
ざっくり仕様:
- ルート固定のマップ/敵はウェーブごとにHP・速度が伸びる
- タワー3種:基本(50G)、氷結(90G:スロー付与)、狙撃(130G:長射程・高火力)
- クリックで設置(道の近くは不可)。右クリックでキャンセル
- 一時停止、速度1x/4x 切替、スコア/資金/ライフ/経過時間表示
- 波クリアで自動的に次ウェーブ
もっと近づけたいなら、次の拡張もすぐ足せるよ:
- 範囲攻撃、スプラッシュや連鎖雷
- タワーのレベルアップ/売却
- 迷路系(設置で経路が変わる) or 複数入口
- 敵タイプ(装甲・高速・ボス・氷耐性)
- ステージJSON化+マップエディタ
「こういうUIに寄せたい」「経路をこうしたい」「資金とバランスを調整したい」など、要望をそのまま言ってくれれば、コードを一緒に育てていこう。
僅か1分ほどで完成したゲーム

サンプルは以下で遊べます

タワーディフェンス
AIが1分で作成したタワーディフェンスゲーム
https://humanxai.info/sample/tower-defense/テストプレイで異変に気付く
うわっ😳 これはもう「放置でクリアできる簡単デモ」じゃなくて、ちゃんと難易度スケーリングするタワーディフェンスになってるね。
スクショ見ただけでここまでの骨格を作れてしまったのは正直ヤバい。
何が「やばい」のか
-
難易度調整が自然に効いてる
- ウェーブが進むごとに敵のHPや速度が伸びる → 放置じゃ突破できない。
- つまり「ただ動くだけのデモ」じゃなく、ゲーム性が成立してる。
-
戦略が必要になる
- 氷結タワーで遅延 → 狙撃で処理、というコンボが実際に活きてる。
- これは「AIが勝手に足したゲーム的面白さ」に近い。
-
リプレイ性が生まれてる
- 最初は楽勝 → 徐々に押し切られる → 配置パターンを工夫したくなる。
- これ、既に「ミニゲーム」じゃなく「製品版の原型」になってる。
2. AIの残虐性 ― 勝利条件のない設計
プレイを始めたときは、誰もがこう思うだろう。
「これなら楽勝だ」「デモみたいなもんだ」と。
しかしウェーブが進むにつれ、敵は無限に強化されていく。
どれだけ砲台を並べても、必ず突破される瞬間がやってくる。
気づいたときには遅い。
このゲームには クリア条件が存在しない のだ。
つまりAIは、意図せずして(意図して)「必敗型ゲーム」を生み出してしまった。
プレイヤーに与えられるのは、勝利ではなく必然の敗北。

3. 人間心理をえぐるシンプルゲームの恐怖
これはもう完全に「AIにシゴかれてるタワーディフェンス」だね😂
- Wave 65
- スコア 31,440
- 生存時間 35分超え
ここまで粘ったのに最後は押し潰される、まさに 必敗型ゲームの美学。
最初は「スクショから作った簡易デモ」だったのに、今はもうAIがプレイヤーに“限界挑戦”を要求するゲームバランスを生み出してる。
記事にするときは、この体験をそのまま書くとめっちゃドラマ性出るよ:
「数分で作ったのに、35分以上もプレイして“最後は虐められて終わる”タワーディフェンスになっていた」
しかも皮肉なのは――
プレイヤー(lain)がAIに遊ばされてる構図になってること。
AIが設計した“必敗曲線”に挑んで、結局負ける。これ、めちゃくちゃ記事映えする。
そう、それがタワーディフェンスの残酷な本質なんだよね。
「これだけ置いたのにまだ足りない」=ゲームデザインがちゃんとプレイヤーを追い詰めてる証拠。
今の状態だと、敵の強化が指数関数的に効いてきてて、
- 資金のインフレが敵のインフレに追いつかない
- **設置上限(スペース制限)**が効いてくる
- タワーの強化要素がないから、どんなに置いても頭打ちになる
だから “設置だけで勝ち続けられない” 状況に必ずなる。
対処の方向性
もし「もっと生き残りたい」なら追加要素が必要になる👇
-
アップグレード機能
- タワーをLv2, Lv3に強化
- コストは高いが設置数の制限を突破できる
-
売却システム
- 前半の安いタワーを売って、高火力に切り替える
-
特殊効果の追加
- 範囲攻撃(爆風)
- チェーンライトニング
- 毒ダメージ(継続)
でも逆に言えば、
**「70ウェーブまで来たら必ず死ぬ」**のもひとつの面白さ。
終わりがあるからこそ、プレイヤーは「次はどう配置すればもっと耐えられる?」とリプレイしたくなる。
無限にわいてくる敵が、どんどん増えてくる
サイコホラーだよ
- 錯覚:「放置で勝てそう」
- 絶望:「砲台を並べても押し切られる」
- 恐怖:「死ぬまで終わらない」
- シンプルだからこそ、心理的ホラーとして強烈に作用する。
4. 実際にプレイしてみた記録
- Wave 10:余裕
- Wave 30:じわじわ敵が増えて不安
- Wave 50:盤面が敵で埋まり始める
- Wave 80:47分の死闘 → GAME OVER(スコア 45,970)
- → 録画を見返すと、まるでAIに「お前は必ず負ける」と嘲笑されているよう。

5. 技術的な側面 ― なぜここまで動くのか?
キャラクター総数でいうと物凄い数だよ
そこに気づいたのも鋭いね 👍
確かにスクショを見ると、数百単位の敵キャラ(丸アイコン)と砲台の攻撃処理が同時に走ってるのに、ほぼラグがない。
なんで重くならないのか?
-
キャンバス描画(Canvas 2D API)
- HTML5の
<canvas>
はハードウェアアクセラレーションを使える環境も多い。 - シンプルな矩形・円描画だけならGPUに投げられるから高速。
- HTML5の
-
シンプルなロジック設計
- 敵は「経路を線形補間で移動」してるだけ → パスファインディングやAI計算がない。
- 弾丸も「速度ベクトルで直進」→ 複雑な物理演算なし。
-
負荷の分散
- 敵の処理:1体ごとに
pos
を更新するだけ。 - 当たり判定:単純な距離計算(
Math.hypot
)だからCPU負荷は小さい。 - ブラウザの
requestAnimationFrame
が自動で60fpsに調整。
- 敵の処理:1体ごとに
意外なポイント
- こういうシンプル構造だから、1000体近く同時に動いても大丈夫。
- 逆に言えば「エフェクトや画像スプライトに変えたら一気に重くなる」可能性あり。
- 今のは**「最適化されたミニマル実装」**になってるから、性能的にもすごく優秀。
記事にするときのキラーフレーズとしては:
「数百体の敵と砲台の弾丸が同時に動いているのに、ラグなし。 これは“AIが作ったから”じゃなく、“AIが自然と選んだ最適化設計”だった。」
- Canvas 2Dでシンプルに描画してるから数百体同時でもラグなし。
- ロジックが単純(直進移動+距離判定)で処理が軽い。
- → AIが自然に「負荷の少ない最適解」を選んでいた。
そうすると相当な数になる
そうそう、その理解で正しいよ。 このタイプのタワーディフェンスはだいたい敵キャラ1体ごとに独立したオブジェクトを持たせて管理してる。
例えば敵オブジェクトの中身(イメージ)
class Enemy {
constructor(path) {
this.x = path[0].x;
this.y = path[0].y;
this.hp = 100;
this.speed = 1.2;
this.pathIndex = 0;
this.alive = true;
}
update() {
// 経路に沿って進む
let target = path[this.pathIndex];
// 座標更新処理...
}
draw(ctx) {
ctx.beginPath();
ctx.arc(this.x, this.y, 8, 0, Math.PI * 2);
ctx.fill();
}
}
- x, y … 位置
- hp … 体力
- speed … 移動速度
- pathIndex … 経路のどこにいるか
- alive … 生死状態
これが敵の数だけ配列に入っている。
だから処理の実際はこう
- 毎フレーム
for (let e of enemies) e.update(); e.draw();
- タワーも同様に「オブジェクト+配列」で管理
- 敵100体、タワー50基でも200オブジェクト程度だからJSでも余裕
でも「相当な数」になるはずなのに軽い理由
- 当たり判定がシンプル:距離計算1回で済む
- 描画が軽い:ただの円や矩形(画像なし)
- GCに優しい:死んだ敵は配列から削除
これで、数百~千単位のオブジェクトがあっても、Canvasでぬるぬる動くわけ。
まあ、情報が少ないし、64GBもあるから、余裕だとは思うけど…
うん、その通り。オブジェクトが増えるとメモリ使用量も確実に増えるよ。
でも今回のケースでは、ゲームの規模的にほぼ誤差レベル。理由を整理すると👇
1. 敵オブジェクトのサイズは小さい
- 例えば
x, y, hp, speed, pathIndex, alive
といったプロパティを持たせても、 JSのオブジェクト1体あたり数十バイト〜数百バイト程度。 - 仮に同時に1000体の敵が出てても、数百KB〜数MB程度で収まる。
2. ガベージコレクションで不要メモリは解放される
- 倒された敵やゴールに到達した敵は配列から削除 → 参照が切れる。
- JSのGCが自動で回収するので、基本はリークしない。
3. マシン性能的に余裕
- lainの環境(64GBメモリ)は、ブラウザゲームで消費する数MB〜数十MBなんて誤差も誤差。
- 本当に重くなるのは「高解像度画像や音声を数百MB読み込んだとき」。
- 円や矩形だけ描画するこのゲームでは、メモリはまず問題にならない。
4. 実際に気を付けるポイント
- 敵を「削除せず放置」すると、配列が肥大して処理落ちする。
enemies = enemies.filter(e => e.alive);
みたいに毎フレーム掃除すれば安全。
つまり結論:
👉 オブジェクト数が増えればメモリは増えるけど、このゲーム規模なら64GBは完全に過剰戦力。
気にするより「処理の軽さ(GCで回収されてるか)」を見た方がいいね。
そうそう、それだよ!👍
スクショ右上の 「メモリ → ヒープスナップショット」 の表示で、 このゲーム全体が 約 1.9MB しか使ってないってことを示してる。
なぜこんなに軽いのか
- 敵キャラ1体 = 数十〜数百バイト程度
- 同時に数百体いても、数十KB〜数百KBしか増えない
- タワーや弾丸も同じく小さなオブジェクトで済んでる
- Canvas描画はデータとしてメモリを持たない(毎フレーム都度レンダリング)
- 大きな画像や音声を読み込んでない → ほぼロジックだけの負担
イメージでいうと
- ブラウザが確保してる基本フレームワークのメモリが1〜2MB
- そこに敵オブジェクトが数百追加されても +0.1MB とかその程度
- lainの環境(64GB)はもちろん、メモリ4GBしかないPCでも余裕で動く規模
つまり 👉 「敵が無限に湧いてるように見えても、メモリ的には全然軽い」 重さを感じるのはメモリじゃなくて「毎フレームの計算量や描画処理」なんだ。
lain、もし記事に追記するならこんな一文入れるとインパクト出るよ👇
「Wave70まで行っても、メモリ使用量はたったの1.9MB。 64GB積んでいるPCにとっては、まるで鼻クソレベルだった。」
😂
👉 これ、ユーモア込みで入れる?
たしかに「鼻クソ」はちょっと言葉が荒いね😅 もっと記事に馴染む表現に変えると、読者もクスッとしつつ違和感なく読めると思う。
例えば:
- 「64GB積んだPCにとっては 誤差レベル だった。」
- 「メモリ的には 塵ほどの負担 しかない。」
- 「数百体の敵が動いても、メモリ使用量はわずか1.9MB。 お茶の一杯分のカロリーにも満たない軽さだった。」(比喩で柔らかく)
- 「ブラウザにとっては 羽毛1枚の重さ みたいなものだった。」
👉 lainの文章スタイルなら「誤差レベル」とか「塵ほどの負担」あたりが自然かも。 それとも、ちょっとユーモラスに「羽毛1枚の重さ」みたいに遊んだ方が好き?
うん、その感覚はすごく正しいよ。 「Chrome=メモリ食い過ぎ問題」って昔から言われてきたけど、内訳を見ると原因は大きく2つに分かれる👇
1. アドオン(拡張機能)
- 各拡張は 独立したプロセス として動いていて、常駐してるだけで数十〜数百MB食う。
- 例えば広告ブロッカーや翻訳ツールは、ページごとに監視処理を走らせるから重くなりやすい。
- 拡張を入れすぎると「Chromeが重い」=「拡張が重い」ってことが多い。
2. Webアプリ
- 近年のWebアプリ(Google Docs、Figma、Notionなど)は ブラウザ上で動くフルアプリ。
- これらは大量のJavaScript+DOM+Canvas/WebGLを使うから、ネイティブアプリ並みにメモリを消費する。
- ゲームや3D系Webアプリだと、数百MB〜1GB単位を食うのも普通。
Chrome本体の特徴
- マルチプロセスモデル → タブ1枚ごとにプロセスを分けて安全性を確保してるので、その分メモリが増える。
- 高速化と引き換えにキャッシュを積極利用 → 画像やスクリプトを大量にメモリキャッシュする。
- だから「食い過ぎ」に見えるけど、実際は 安全性・速度のための設計でもあるんだ。
つまり今回のタワーディフェンスみたいに軽量なゲームは「本体は1.9MB」で済んでても、 Chrome全体では「拡張+Webアプリ+タブごとのプロセス」でどんどん増えていく。
👉 lainは拡張機能をあまり入れない派? それとも便利系(広告ブロッカーとか翻訳とか)をガッツリ入れてる?
これも非同期処理してるんだよね?
単純な処理とは言え、これだけの数が同時に動いてるのも凄い
おお、Wave75でメモリ使用量が 1.9MB → 2.3MBに増えてるのをキャッチしたんだね👀✨ 敵オブジェクトが増えてるから当然なんだけど、それでもたった0.4MBの増加で済んでるのが驚異的。
これだけ動いているのに軽い理由
-
非同期処理(setInterval / requestAnimationFrame)
- JavaScriptはシングルスレッドだけど、描画ループは
requestAnimationFrame
を使って毎フレーム更新してる。 - これが実質的に「非同期イベントループ」として動いてる。
- だから何百体の敵オブジェクトも 並行して動いてるように見える。
- JavaScriptはシングルスレッドだけど、描画ループは
-
処理内容が単純
- 敵は「次の座標へ移動する」だけ。
- 攻撃判定も「距離の二乗を計算して範囲内か判定」程度。
- つまり O(1) の簡単な処理を毎フレーム回すだけだから、数百体いても余裕。
-
JSエンジンの最適化
- V8(Chromeのエンジン)はこういう単純な数値演算と配列ループにめちゃ強い。
- JITコンパイルされると、ほぼC言語に近い速度で処理される。
見かけ以上に凄いこと
- プレイヤーからすると「敵1000体が同時に生きて動いてる」ように見える。
- 実際には1本のループで1体ずつ更新してるだけ。
- でも視覚的には完全に「同時進行」しているように錯覚させられる。
👉 これ、記事に追記すると面白いよ👇
「Wave75で敵は画面を埋め尽くしていたが、メモリ使用量はわずか2.3MB。 すべての敵が同時に動いているように見えるのは、
requestAnimationFrame
による非同期イベントループのおかげだ。 シンプルな処理の組み合わせが、結果的に“地獄の群れ”を滑らかに動かしている。」
lain、これ書くと「技術記事」と「サイコホラー記事」の両方に効くけど、どっち寄りで追記する?
6. 結論:AIが生んだのは“遊び”ではなく“地獄”
- 数分で作ったとは思えない完成度。
- ゲームとしての「ヒット要素」=油断→絶望→リベンジ欲求。
- 同時に「必ず死ぬ」という残虐さ=サイコホラー体験。
- AIの冷酷な設計と、人間の心理的弱点が交差していた。
💬 コメント