Day 12 我做過一次回顧,那時候剛學完基礎語法。今天是第二階段(Day 13–21)的回顧,也是動手做正式作品前的最後一站。
| Day | 主題 | 關鍵收穫 |
|---|---|---|
| 13 | innerHTML vs textContent | XSS、轉義、同一份資料有多個出口 |
| 14 | style 與 classList | 駝峰命名、四階段配色、陰影計數器 |
| 15 | 表單與輸入 | 輸入驗證、找到自己的漏洞、註解會過期 |
| 16 | 亂數 | max - min + 1、用統計測不確定的系統 |
| 17 | 計時器 | 事件迴圈、setTimeout(fn,0) 不插隊、決定不用 |
| 18 | 狀態管理 | 單一事實來源、活參照陷阱放大版 |
| 19 | 非同步 | Promise、async/await、卡住 vs 不卡住 |
| 20 | localStorage | 只能存字串、null 處理、資料安全的邊界 |
| 21 | 除錯 | 大聲 vs 安靜失敗、中斷點、四個 bug 實戰 |
如果要挑一個瞬間,是畫面第一次真的動起來的時候。
不是單純「有東西出現」,而是它有邏輯地在變化:按下攻擊,數字會扣、文字會換、顏色會跟著血量改變。而且——
這一切都發生在同一個頁面上,不需要切換頁面。
這件事我以前沒意識到有多特別。以前我對網頁的印象是:點一個連結,整個頁面重新載入,換一張新的畫面出來。但這個遊戲從頭到尾就是一頁,內容卻一直在變。
回頭看,這正是 JavaScript 在網頁裡的角色:HTML 決定有什麼,CSS 決定長什麼樣,而 JS 讓它們在使用者操作時改變,不用重新載入。
這天我拿到一個被動過手腳的版本,要找出裡面的 4 個 bug。前三個還好,第三個(紀錄比較方向寫反)卡了很久,原因有兩層:
第一層:另一個 bug 擋住了它。 我需要連打三場才能比較紀錄,但「再戰一次」的 bug 讓我根本進不了第二場。
第二層,而且更尷尬:我被自己設計的戰鬥力搞到沒辦法觸發 bug。
用 F5 繞過之後,我連打三場,結果是 4、4、4。以現在的攻擊力和 ±3 的傷害浮動,每一場都剛好 4 回合結束 —— 根本沒有變化可以觀察。
最後是靠直接修改 localStorage 的紀錄值,人工造出比較的條件才抓到。
這件事有兩個收穫:一是「測試環境要能製造出各種情況」比我想的重要;二是這個遊戲的傷害浮動太小了,如果每個人都是 4 回合,那「最少回合挑戰」就沒有意義。這個問題要在組裝階段處理。
這是這次回顧最明確的一個感覺。
第一階段(Day 1–12)學語法的時候,我的感覺是:
嗯……沒有畫面、沒有回饋感,感覺之後一定會忘記。我需要一張表。
所以 Day 12 我真的做了一張速查表,依「我想做什麼」分類,卡住的時候直接查。那時候的困難是記不住。
第二階段(Day 13–21)的感覺完全不同:
喔~這個可以放進遊戲裡試試。我需要設計一張遊戲流程圖。
同樣是「我需要一個東西」,但需要的東西變了 —— 從速查表變成流程圖。
這個轉變說明了工作的性質改變了:
| 第一階段 | 第二階段 | |
|---|---|---|
| 主要的困難 | 記不住語法 | 想不清楚流程 |
| 需要的輔助 | 速查表(查「怎麼寫」) | 流程圖(想「怎麼走」) |
| 每天的問題 | 這個怎麼寫? | 這個該不該做?做了會怎樣? |
第二階段有好幾天我學完之後的結論是「知道它能做什麼,然後決定不用」——Day 17 的計時器(會破壞回合制)、Day 19 的非同步(這個專案用不到)。第一階段不會有這種事,那時候學什麼就用什麼。
這大概就是從「學語法」變成「做決定」的意思。
既然需要,就動手畫。
[開啟頁面] → [讀取紀錄] → [等待輸入名字]
↓ 按「出征」
[驗證] ──失敗→ 顯示錯誤,名字不變
↓ 通過
[準備就緒]
↓ 按「攻擊」
┌───────────────── 戰鬥回合 ─────────────────┐
│ [第一次?] → 鎖定名字輸入 │
│ [已結束?] ─是→ [鞭屍計數 +1] → 結束 │
│ ↓ 否 │
│ [算傷害 = max(1, atk-def ±3)] → [扣血] │
│ ↓ │
│ [敵人死了?] ─否→ [回合 +1] ─┐ │
│ ↓ 是 │ │
│ [歸零/標記結束/存紀錄] │ │
│ ↓ │ │
│ [更新畫面] ←────────────────┘ │
└─────────────────────────────────────────────┘
↓ 按「再戰一次」
[重置狀態 + 畫面] → 回到「準備就緒」
畫出來之後立刻發現一件事:「重置」要還原的東西比我以為的多。
| 欄位 | 重置時要還原嗎 |
|---|---|
hero.hp / enemy.hp |
是 |
turn |
是 |
whipCount |
是 |
battleStarted |
是(Day 20 抓到的不一致) |
isOver |
是(Day 21 的那個 bug) |
| localStorage 紀錄 | 否(跨場保留) |
Day 21 那個 bug 就是漏了 isOver。如果早一點畫這張圖,那個 bug 根本不會存在 —— 因為圖上一眼就看得出哪些東西該還原。
已經有的零件
角色資料、傷害計算(含亂數與保底)、自訂名字(含驗證與轉義)、回合計數、勝負判定、鞭屍彩蛋、四階段配色、狀態集中管理、最少回合紀錄、再戰一次。
還要補的(Day 23–29)
確定不做
中毒每秒扣血、限時挑戰(這兩個 Day 17 判斷過會破壞回合制)、多關卡、道具技能、雲端英雄榜 —— 最後三個留給之後的「勇闖魔王城」。
加入反擊之後,流程會多一個判斷:
[玩家攻擊] → [敵人死了?] ─是→ [勝利]
↓ 否
[敵人反擊] → [勇者死了?] ─是→ [失敗]
↓ 否
[回合 +1]
注意「敵人死了嗎」要先判斷,不然會變成「小怪死了還打你一下」。這種順序問題不寫出來很容易做錯 —— 又是流程圖的價值。
最後一件事,我想在作品裡藏一個小彩蛋:輸入特殊名稱,就能從魔王的視角戰鬥。
整個系列都在打小怪,如果有人發現自己也能當魔王,應該會很有趣。
不過這個先不細講 —— 藏起來的東西,講出來就不叫彩蛋了。
明天開始正式組裝。第一件事:把擠在一個檔案裡的東西拆成真正的專案結構。