火伊布放火爆,螢幕上卻是一個白方塊——「眼睛看到的」跟「程式判定的」差在哪

你有沒有過那種,code 完全沒錯、測試 831 個全綠、但玩起來就是「怪怪的」的經驗?不是會 crash 的那種怪,是那種你說不上來、但身體很誠實地覺得「這不對」的怪。

我這一整天都在跟這種怪打架。而且它換了三張臉出現。

先講背景。我在做一款橫向動作格鬥的小遊戲,角色會進化、會放招、招式有火水電不同元素。技術上招式是資料驅動的——招式定義在 JSON 裡,VFX、音效、判定框各走各的 pipeline,理論上很乾淨。理論上啦。

第一張臉:火伊布的白方塊

伊布進化會換元素,一般進化成火、水、電。我那時很得意——資料驅動嘛,進化型只要在 JSON 加個 element 欄位,火伊布放招就會是火的。

結果火伊布放火爆,螢幕上跳出來一個白色方塊

我第一個反應是 vfx 素材壞了,去翻 fire_blast 的 sprite-sheet,好好的。第二個反應是元素沒吃到,去 log element 欄位,火得很正常。我卡在這邊滿久的,因為「資料是對的、素材是對的」這兩件事同時成立的時候,你會開始懷疑人生。

真相是:進化 kit 根本沒有 presentSpecial。基底伊布有招式→VFX 的對應表,但三個進化型的 kit 是另外一份資料,那份漏了 present 對應。所以系統找不到該播什麼 vfx,就回退到「白框」這個 fallback。元素是對的、火也是火,只是沒人告訴畫面「火長什麼樣子」。

教訓有點刺:資料驅動最危險的不是資料錯,是資料「缺」。 錯的資料會噴錯、會跑紅燈;缺的資料只會安靜地走 fallback,然後給你一個語意上完全合理、視覺上完全荒謬的白方塊。

第二張臉:日光束打出一根柱子

修好白框,下一隻。妙蛙花的日光束——judgment 判定框是 280×16,一條細細長長的橫帶,貼著地面掃過去。設計就是要這樣。

但畫面上放出來是一根垂直的高柱,大概 140px 高。

我又卡住了。判定框明明是橫的、扁的,為什麼 vfx 是直的、高的?玩家看到一根柱子,會以為打到柱子範圍內都算,結果實際只有貼地那 16px 命中——「動畫範圍 ≠ 判定範圍」,這是格鬥遊戲的大忌,玩家會覺得遊戲在騙他。

挖下去發現是縮放邏輯偷懶。所有爆破 vfx 一律用 b.w / 96 等比縮放,solar_beam 的素材是 96×48,等比放大之後高度就被拉到 140 左右。對方塊形的爆破沒問題,但對這種極度細長的 beam,等比縮放等於把它「吹胖」。

修法是在 VfxPlayer.play 加一個 fit{w,h},偵測到細長框(寬高比 ≥ 4)就改用非等比縮放去貼合判定框,高度只留 ×1.6 給一點視覺存在感。其餘方塊爆破維持原樣。

教訓跟第一張臉是同一句話的變奏:一套「夠用」的通用邏輯,會在邊界情況安靜地騙人。 等比縮放對 90% 的招式都對,所以你不會想到它,直到那 10% 細長招式出現,它就把判定跟視覺扯開。

第三張臉:繞身 chip 打到像打空

最後一隻最陰。飛葉快刀跟濁流這類招式有「繞身 chip」——招式繞著角色轉的時候會掃到敵人。

判定是對的,敵人會掉血。但沒有火花、沒有傷害數字,玩家看起來完全像打空了一樣。

這次反過來——前兩張臉是「視覺太多、判定太少」,這張是「判定有了、視覺沒跟上」。原因是 chip 命中直接呼叫 f.takeHit,繞過了負責生火花、跳傷害數字的 enemyHitEvents 那條線。傷害真的進去了,只是回饋的 pipeline 被抄捷徑跳過了。

修法是加一個 pendingChipHits 佇列,chip 命中時把命中點推進去,再讓場景 drain 出來補上傷害數字跟火花。純視覺,不進 combo、不進 XP,維持原本平衡。

三張臉,同一個病

我盯著今天三個 commit 看,發現它們其實是同一句話:

玩家的「真實」是螢幕上看到的東西,不是你 code 裡的判定。 你的 hitbox 再精準,玩家相信的是火花、是數字、是動畫的範圍。一旦這兩者對不上——多了會騙人、少了像打空——體驗就破了,不管你測試多綠。

附帶一提,今天順手把粒子 emitter 池化了。原本每次命中都 add.particles 建一個 emitter、延遲後 destroy,連段密集命中一秒數十次,GC 抖得很慘。改成常駐 emitter 池、用 preset|tint|量化scale 當 key 復用,7 次 burst 只開 3 個 emitter。這個是純效能,跟上面三張臉無關,但也算是「玩家看不到、但身體會感覺到」的那種——掉幀的時候你說不上來哪裡卡,就是覺得不順。某種程度上,跟那個白方塊是同一類問題吧。

先不說了,我得去 playtest 確認火伊布終於不是白方塊了。screenshot 比 831 個測試更能讓我安心啊。

這些 code 寫於 2026 年 6 月 17 日,文章整理於同一個晚上,趁記憶還新。