In English — I don't write code. What I had was a childhood memory of Famicom tank battles and a detailed plain-language spec of how the game should behave. Claude Code built the whole thing — pure HTML5 Canvas, zero frameworks, zero external assets, even the chiptune soundtrack is synthesized live — and wrote 43 automated checks to grade its own work. Every check passed. Then I played the game for ten minutes and hit a bug none of the checks had caught. That bug turned out to be the best lesson of the project.
The bug that 43 tests missed
有命,卻永遠回不來 | Lives left, but never respawning
上線隔天,我自己開了一局。打到一半被擊中,坦克爆炸——然後就沒有然後了。
畫面上 LIVES 還有 2,敵人繼續進攻,但我的坦克再也沒有出現。遊戲不判定失敗,也不讓我重生,就這樣掛著,直到敵人慢慢磨穿基地的磚牆、打爆基地,才終於跳出 GAME OVER。
這個遊戲有 43 項自動化檢查,全數通過才上線的。其中一項就叫「生命歸零後遊戲結束」,另一項驗證「被敵人打中會扣一條命」。單獨看,每一項都是綠燈。
但我親自玩十分鐘就踩出來的這個 bug,43 項檢查一項都沒抓到。
答案留在後面。先從頭說起:一個不會寫程式的人,為什麼、又是怎麼做出一個遊戲的。
Why a tank game?
紅白機的童年債 | A childhood debt to the Famicom
小時候家裡有台紅白機,我最愛的就是這類坦克攻防遊戲:守住基地、擋下一波波敵人坦克。它的好在於不用動太多腦——規則一看就懂,不複雜,但一局打下來又很有成就感。長大後偶爾還會想起那個畫面。
所以這個專案的動機很單純:復刻那份記憶。不是做一個創新的遊戲,是把小時候玩的那種感覺重新做出來——迷宮地圖、磚牆鋼牆、保護基地、一波比一波難的敵人。
問題是我不會寫程式。以前這個念頭就只能是念頭,現在有了 AI coding 工具,我想試試看:光靠「把遊戲描述清楚」,能不能走到「真的能玩」?
I can't code, but I can describe
我不會寫程式,但我會寫需求 | Spec-writing is the real skill
這個遊戲不是「幫我做一個坦克遊戲」一句話生出來的。我準備了一份 20 節的需求書,全部用白話文寫:遊戲怎麼操作、五種地形各自擋不擋坦克和砲彈、敵人要有哪三種、每一波出幾隻、被打中會發生什麼事——最後附上 28 條驗收條件,一條一條列出「怎樣才算做好了」。
寫這份需求書花了不少時間,但它是整個專案裡槓桿最大的一小時。因為 vibe coding 的品質上限不在 AI 多聰明,而在你能不能把「做好」講清楚。「敵人 AI 要聰明」沒辦法驗收;「敵人卡住的時候要會換方向、跟你在同一直線上會提高開火機率」可以。
這跟寫程式無關——它更像寫一份給裝潢師傅的工程清單。完整需求書全文附在文末,可以直接拿去改造成你自己的專案。
AI 一次寫完,自己修到全綠 | One shot, then self-correction
Claude Code 拿到需求書後一口氣把整個遊戲寫完,然後開始自我檢查、自己修錯,直到 43 項驗收全部通過。我看不懂它寫的程式碼,但我看得懂測試報告上的 43/43 PASSED。
The AI grades its own homework
AI 給自己出考卷 | Writing its own exam
不會寫程式的人做軟體,最大的焦慮只有一句話:
我怎麼知道它真的做對了?
我看不懂程式碼,總不能每改一次就把整個遊戲手動玩一遍。
解法是讓 AI 給自己出考卷:根據那 28 條驗收條件,它寫了一套自動化檢查,用一個機器人瀏覽器實際打開遊戲、操作坦克、然後檢查遊戲內部的數值——生命有沒有正確扣、砲彈有沒有穿牆、按下暫停後敵人是不是真的全部停住。連「草叢有沒有真的遮住坦克」這種視覺效果,都是逐個像素檢查顏色來驗證的。
於是分工變得很清楚:AI 負責寫程式和批改考卷,我負責出題(需求書)和玩。每次加新功能,43 項舊考題全部重考一遍,確保沒有改壞任何東西——這是我在整個過程中最有安全感的部分。

Zero assets, by design
沒有任何圖片和音效檔 | No image or sound files at all
我在需求書裡下了一條狠限制:不准用任何現成素材。沒有圖片檔、沒有音效檔、不接網路資源,整個遊戲就是幾個純文字的程式檔案,離線也能玩。
所以畫面上每一台坦克都是程式即時「畫」出來的幾何圖形——矩形履帶、圓形砲塔、一根砲管;爆炸是上百顆小色塊組成的粒子噴發。而我最喜歡的部分是背景音樂:那首 8-bit 風格的循環配樂不是任何音樂檔案,是程式即時演奏出來的——它按著譜(兩串音符數字)用瀏覽器內建的音訊功能當場合成。我本來還準備了用 Suno 生成音樂的備案,最後根本沒用上,合成版跟像素畫風更搭。
為什麼要這樣限制?因為素材是版權地雷區,而且我想看看「純描述」能推多遠。事實證明:推得很遠。
Day two: seven power-ups in an afternoon
第二天加寶物,一個下午 | Good foundations make features cheap
隔天我想加寶物系統:打爆敵人有機率掉道具,撿了變強。從三種基礎道具(加一條命、加速、護盾)做到七種(強化砲彈打穿鋼牆、鏟子把基地圍牆升級成鋼牆、星星火力升級、炸彈全場秒殺)——一個下午就完成,包含每種道具的自動化驗證。
快的原因是第一天的地基打得好:所有遊戲數值集中在同一個地方管理,之後想調整「掉落機率」或「加速持續幾秒」只要改一個數字。
中間有個有趣的插曲:我的需求是「增加血量、增加防禦」,但 AI 提醒我這遊戲跟紅白機原作一樣是「一發死、算殘機」的設計,根本沒有血條。所以「加血」變成加一條命、「防禦」變成幾秒鐘的無敵護盾。需求說的是意圖,怎麼落地是可以討論的——這種來回其實就是 vibe coding 最像「合作」的時刻。
![]()
Anatomy of the bug
同一瞬間的兩件事 | Two things at the same instant
回到開頭那個 bug。修好之後回頭看,成因其實可以用一句話講完:
我被打死的那一瞬間,我射出的最後一發砲彈剛好打爆了那一波的最後一隻敵人。
遊戲內部有很多「模式」:進行中、暫停、玩家重生倒數中、換波倒數中……被打死時,遊戲進入「重生倒數」模式,1.2 秒後我應該復活。但「清完一波敵人」會讓遊戲切到「換波倒數」模式——這兩件事在同一瞬間發生時,後者把前者蓋掉了。重生的倒數計時器只在「重生倒數」模式裡才會走,模式被蓋掉,計時器就永遠停住。坦克永遠回不來,遊戲也沒有報錯,只是安靜地把我鎖在局外。
為什麼 43 項檢查都沒抓到 | Why every check missed it
因為每一項檢查驗的都是單一事件:「被打中會扣命」綠燈、「沒命了會結束」綠燈、「清完一波會進下一波」綠燈。每個零件都對,但「死亡」和「清波」恰好同時發生的組合,沒有任何一條考題涵蓋——而這種「兩件事撞在同一瞬間」的組合有無限多種,考卷永遠出不完。
真人玩家不按劇本出牌。我沒有想測什麼,我只是在玩,然後系統設計時沒人想到的時機組合就自己冒出來了。十分鐘的真人遊玩,找到了 43 項自動檢查找不到的問題。
修復本身很小(AI 三行程式碼就修好,並補上了針對這個情境的新考題)。但教訓值得寫下來:**AI 可以把你寫進需求的東西全部驗證到綠燈;需求裡沒寫的意外組合,還是得靠人去玩。**上線不是測試的終點,是另一種測試的開始。

Ship it
上線 | Deploy
最後一步意外地簡單:AI 把遊戲放上 GitHub Pages(免費),綁了我自己的網域,遊戲就住在 game-tank.tingyudeco.com。純靜態網頁、零伺服器成本。
Takeaways
- 不會寫程式不是門檻,講不清楚需求才是——花一小時把「做好」寫成一條條可以驗收的條件,是整個專案槓桿最大的投資
- 讓 AI 給自己出考卷:你看不懂程式碼沒關係,看得懂 43/43 PASSED 就有安全感;每次改動全部重考,就不怕改壞
- 自動化檢查驗證你想到的,真人遊玩發現你沒想到的——兩者缺一不可
- 童年的遊戲記憶是很好的第一個 vibe coding 題目:規則你滾瓜爛熟,驗收標準就在你的肌肉記憶裡
Links | 所有連結
- 🎮 線上遊玩:game-tank.tingyudeco.com
- 📖 遊戲攻略:操作與寶物完全指南
- 💻 原始碼:github.com/Ttingyu1123/game-tank
- 🛠️ 更多工具:tingyudeco.com/portfolio/tools
Appendix: the full spec | 附錄:完整需求書全文
以下是餵給 Claude Code 的原始需求全文(我唯一「寫」的東西),按右上角按鈕可整份複製,自由取用改造。
你是一位資深 HTML5 遊戲工程師、遊戲設計師與測試工程師。
請直接建立一款可在瀏覽器執行的 2D 俯視角坦克射擊遊戲,玩法靈感來自經典坦克攻防遊戲,但不可直接使用任何受版權保護的名稱、圖像、地圖、音效或素材。
請不要只提供教學、規格或程式片段,而是實際建立完整專案、執行測試、修正錯誤,直到遊戲可以正常遊玩。
一、技術規格
請使用:HTML5、CSS、JavaScript、HTML Canvas API
限制:不使用 React、Vue 或其他前端框架;不使用 Phaser、Unity、Godot 或其他遊戲引擎;不使用外部圖片素材;不使用外部音效檔;不依賴 CDN;遊戲必須可離線執行;所有圖像使用 Canvas 幾何圖形繪製;音效可使用 Web Audio API 即時產生;程式需能直接透過瀏覽器開啟,或使用簡單本機伺服器執行。
請建立清楚的檔案結構(index.html、style.css、js/main.js、js/game.js、js/player.js、js/enemy.js、js/bullet.js、js/map.js、js/audio.js、README.md)。如判斷單一 JavaScript 檔案更適合初版,也可採用較簡單結構,但必須保持程式可讀性與模組化。
二、遊戲核心概念
玩家操控一輛坦克,在俯視角迷宮地圖中保護自己的基地,擊敗持續出現的敵方坦克。遊戲畫面固定在單一競技場中,不使用捲動畫面。建議 Canvas 邏輯解析度 960×720,可隨瀏覽器視窗等比例縮放,保持固定長寬比,不因縮放影響碰撞判定。
三、玩家控制
鍵盤:W/↑ 上、S/↓ 下、A/← 左、D/→ 右、Space 射擊、P 暫停/繼續、R 遊戲結束後重新開始。
控制規則:坦克只能朝上下左右四方向移動;移動時朝向必須更新;不能穿越牆壁、基地、其他坦克或地圖邊界;長按移動鍵持續移動;長按射擊鍵有冷卻;同時存在砲彈數量有限制;被擊中扣一條生命;重生短暫無敵並顯示閃爍或護盾效果。
四、坦克視覺
Canvas 幾何圖形繪製:履帶、車身、砲塔、砲管,朝向清楚可辨識,玩家與敵人不同顏色,不用外部圖片。不同敵人可透過顏色、尺寸、速度或裝甲圖示區分。
五、射擊系統
砲彈從砲管前端生成、沿當前朝向直線飛行、碰障礙物產生對應效果、碰坦克造成傷害、碰基地摧毀基地、碰邊界消失、敵我砲彈可互相抵消、不可穿透實體牆、每顆砲彈只造成一次有效傷害。避免:砲彈在牆內生成、一次碰撞重複扣血、高速穿薄牆、摧毀物體後仍存在、自傷。
六、地圖系統
網格化地圖,至少包含:磚牆(阻坦克阻砲彈、可破壞、建議多段耐久或子區塊破壞)、鋼牆(阻擋、普通攻擊不可摧毀)、水面(坦克不可過、砲彈可過、波紋動畫)、草叢(坦克砲彈可過、顯示在坦克上方遮擋)、空地。先建立一張經過設計的固定地圖(非隨機生成),包含玩家出生區、敵人出生區、基地防禦區、多條可選路線、不會永久卡死的通道、基地周圍可破壞磚牆保護。
七、基地系統
地圖底部中央設玩家基地:清楚圖示、敵人會嘗試接近、被敵方砲彈擊中立即摧毀、摧毀即失敗、周圍有可破壞磚牆、坦克不能穿過基地、摧毀時播放明顯爆炸動畫與音效。
八、敵人 AI
從地圖上方不同出生點生成,至少三種:普通型(中速、一發毀、隨機巡邏向基地前進)、快速型(速度快、裝甲弱、轉向頻繁)、重裝型(慢、需多次命中、外觀厚重)。AI 必須:向基地大致前進、遇障礙改向、偶爾朝玩家移動、同直線無牆阻擋時提高射擊機率、偶爾射牆開路、避免長時間停在同一位置、偵測卡住並重新選方向、敵人彼此不完全重疊、不逐幀改向。用 FSM、方向權重、視線檢測與簡單路徑決策,不用機器學習。
九、敵人生成與波次
波次制至少 5 波:第 1 波少量普通、第 2 波增加普通、第 3 波加入快速、第 4 波加入重裝、第 5 波大量混合。每波數量遞增、同時在場數量有上限、生成時短暫警示動畫、出生點被擋延後生成、清除當前波所有敵人進下一波、波次間顯示 2-3 秒提示、完成第 5 波顯示勝利畫面。
十、計分與 UI
顯示 SCORE、LIVES、WAVE、ENEMIES、基地狀態、暫停提示、開始/勝利/失敗畫面、重新開始提示。計分:普通 100、快速 150、重裝 300、完成波次額外加分。主要遊戲 UI 用 Canvas 繪製,CSS 用於外框、標題與操作說明。
十一、爆炸與粒子效果
砲彈命中火花、坦克爆炸、牆壁碎片、基地爆炸、重生護盾、敵人出生閃爍、畫面輕微震動。不用圖片素材、粒子數量有上限、不可明顯降效能、震動不可改變實際碰撞座標。
十二、音效
Web Audio API 產生:玩家射擊、敵人射擊、砲彈碰牆、牆壁破壞、坦克爆炸、基地爆炸、波次開始、勝利、失敗。注意:瀏覽器需使用者互動後才允許播放;首次按鍵或點擊後才初始化 AudioContext;加入音效開關;音效初始化失敗不可導致遊戲停止。
十三、遊戲狀態
START、PLAYING、PAUSED、WAVE_TRANSITION、PLAYER_RESPAWNING、GAME_OVER、VICTORY。不同狀態限制不適當輸入:暫停時所有物件停止更新、結束後不可射擊、波次提示期間敵人不能攻擊、重生過程不可重複扣生命。
十四、碰撞與效能
穩定 AABB 碰撞,至少處理:玩家/敵人與牆、玩家與敵人、敵人與敵人、坦克與基地、砲彈與牆/坦克/砲彈/基地、所有物件與邊界。使用 requestAnimationFrame、delta time(含上限,避免切分頁後瞬移)、安全的陣列刪除、必要時簡單空間分區。目標一般桌面瀏覽器穩定接近 60 FPS。
十五、畫面風格
現代化復古街機風:深色背景、高辨識度幾何造型、清楚配色、像素感與現代 Canvas 動畫融合、UI 清楚易讀、不模仿特定遊戲原始美術、不使用受版權保護的標誌或角色。
十六、程式品質
class 或清楚模組結構、避免大量全域變數、常數集中管理、函式命名清楚、重要邏輯註解、移除未使用程式碼、輸入監聽器只註冊一次、重新開始不重複建立 animation loop、重開後不殘留上一局的砲彈/敵人/粒子/計時器。
十七、驗收條件(28 項)
- 頁面正常開啟 2. Canvas 正常顯示 3. 四方向移動 4. 無法穿牆 5. 正常射擊 6. 砲彈方向正確 7. 磚牆可摧毀 8. 鋼牆不可被普通砲彈摧毀 9. 水面阻坦克不阻砲彈 10. 草叢遮擋坦克 11. 敵人生成 12. 敵人不全卡出生點 13. 敵人射擊 14. 敵人傷害玩家 15. 玩家摧毀敵人 16. 重裝需多次命中 17. 基地可被摧毀 18. 基地毀遊戲結束 19. 生命歸零遊戲結束 20. 暫停正常 21. 波次切換正常 22. 第 5 波完成顯示勝利 23. R 重新開始 24. 重開不產生雙重迴圈 25. Console 無持續錯誤 26. 縮放不影響碰撞 27. 音效關閉遊戲仍正常 28. 長時間遊玩無明顯記憶體累積
十八、工作流程
檢查目錄 → 建檔 → 最小可玩版 → 執行 → 查 Console → 測移動射擊碰撞 → 加敵人 AI → 加地圖物件 → 加基地與波次 → 加 UI 音效特效 → 完整測試 → 主動修錯 → 更新 README。不要每個小步驟停下詢問,自行做合理決策並持續完成。
十九、README
遊戲簡介、操作方式、啟動方式、專案結構、遊戲規則、敵人類型、已完成功能、已知限制、後續可擴充功能。
二十、最終回報
建立了哪些檔案、啟動方式、完成哪些功能、實際執行哪些測試、修正哪些錯誤、是否仍有已知問題、最重要的程式架構說明。除非遇到真正無法自行解決的權限或環境問題,否則不要只停留在分析或建議階段。




