iT邦幫忙

2026 iThome 鐵人賽

DAY 23
0
Vibe Coding

從 Vibe Coding 到系統架構:Gemini x Claude Code 雙 AI 協同開發 Godot 2D Roguelike 卡牌遊戲實戰系列 第 23 篇

Day 23:【數值平衡】先量化再動手:用模擬取代「我覺得這張卡有點強」

  • 分享至 

  • xImage
  •  

Day 22 抓的是程式邏輯的錯誤,答案比較明確:結果對不對,修正之後就能重新驗證。
Day 23 遇到的是另一種問題。
數值平衡沒有一個絕對的「正確答案」。一張卡到底強不強、削弱多少才合理,都需要先定義問題,再用數據確認。
這次實際試玩時,有人提出一個很直接的問題:

「賣血狂暴是有點強,要怎麼調?」

我沒有直接把卡片的 +3 改成 +2。

先請 Claude Code 回頭分析:
這張卡到底強在哪裡?

往下查之後,發現問題不只是單純調整數字那麼簡單。


一、「有點強」不是一個可以直接修改的參數

先介紹主角。《賣血狂暴》是狂暴疊攻流的卡:
0 能量花費,失去 3 點生命,永久 +3 攻擊力。
不花能量,設計上是拿生命換輸出的那一張。

「賣血狂暴是有點強」是一個試玩感受,但還不能直接轉成程式碼修改。
最直接的做法,可能就是把:

+3 攻擊力

改成:

+2 攻擊力

然後再玩幾場看看。這次沒有直接這樣做。
我先請 Claude Code 檢查這張卡目前的實際效果,以及它在戰鬥裡會被使用幾次。
結果查到兩層原因。


二、先查「強在哪裡」,結果不是單純的數值問題

第一層:生命值有下限保護

目前的程式有:

Global.player_hp = max(1, Global.player_hp - value)

下限保護這行原本是為了避免玩家把自己扣到 0 HP。
但放到「賣血狂暴」上,就產生了一個額外效果。
當玩家只剩 1 點生命時,再使用這張卡:

原本 HP:1
消耗生命:3

經過 max(1, ...) 之後:

最後 HP:1

實際上沒有再扣血。
也就是說,在這個邊界情況下,原本應該支付的生命代價消失了,但增加攻擊力的效果仍然存在。


第二層:這張卡會回到牌組

打出的卡會進入棄牌堆。
當抽牌堆抽完之後,棄牌堆會重新洗回抽牌堆。
目前牌組是 13 張,每回合抽 5 張,因此一張牌平均大約每 2.6 回合會重新進入手牌一次。

「賣血狂暴」的效果又是永久增加攻擊力。
所以這張卡不是只使用一次:

使用一次
↓
+3 攻擊力
↓
之後重新抽到
↓
再 +3
↓
再重新抽到
↓
繼續 +3

這樣看起來,問題就不只是「+3 太高」。

生命代價在特定情況下可以歸零,加上永久效果可以隨牌組循環持續疊加,兩個條件疊在一起,才形成這張卡的主要問題。

如果只把 +3 改成 +2,這兩個條件都沒有改變。
卡片會變弱,但原本的機制仍然存在。


三、先量化,再決定怎麼改

確認問題之後,我沒有馬上請 Claude Code 修改卡片。
先列出兩個需要回答的問題。

問題一:加入消耗機制後,會不會常常抽不到攻擊牌?

如果之後讓這張卡使用一次就進入消耗堆,它就不會再回到牌組。
這時候新的問題是:

如果玩家抽到賣血狂暴,卻沒有可以吃攻擊力的卡,會不會變成一張卡手的牌?

我請 Claude Code 把這個情況算出來。
結果是:

起始 4 張牌組,抽 5 張沒有攻擊卡的機率:0.0%(只有 4 張,全部抽光)

13 張牌組,抽 5 張沒有攻擊卡的機率:6.5%
13 張牌組,手上有增益卡卻沒攻擊卡:5.6%

目前卡池 8 張裡,有 3 張會吃攻擊力:

  • 斬擊
  • 重擊
  • 破甲打擊

因此,完全沒有攻擊卡可以搭配的情況,機率是 5.6%。
這個數字看起來不高,所以「加上消耗機制會不會讓它常常卡手」暫時不是主要問題。


問題二:削弱之後會不會變成沒人想用的卡?

第二個問題是另一個方向。
如果不讓它永久疊加,這張卡還有沒有足夠的價值?

我請 Claude Code 先量戰鬥長度。
貪婪打法的平均戰鬥長度是 6 回合。
一張 +3 攻擊力的卡,在 6 回合內大約還能搭配 8~10 張攻擊卡。
換算成額外傷害,大約是:

8~10 張攻擊卡 × 3 攻擊力
= 24~30 點額外傷害

魔王有 60 HP。
即使一場戰鬥只能使用一次,這張卡仍然可能帶來約四成的傷害量。
所以「加入消耗之後會不會直接變成廢卡」這個問題,目前的答案也是否定的。

到這裡,兩個疑問都有了可以參考的數字。
接下來才進入真正的修改。


四、A/B 對照:兩個版本各跑 150 場

前面的分析完成後,我請 Claude Code 修改兩張增益卡:

  • 加上「消耗」標記
  • 打出後進入消耗堆,不再洗回抽牌堆
  • 效果從「永久 +N 攻擊力」改成「本場戰鬥 +N 攻擊力」

修改之後沒有只靠試玩幾場判斷。

Claude Code 寫了一個模擬腳本,使用固定的亂數種子,讓同一批牌組分別跑兩個版本。

兩邊各跑 150 場。

版本 勝率 平均獲勝回合 4 回合速殺 結束時攻擊力
無消耗(原本) 81% 6.0 13% 14.0
有消耗(新版) 85% 6.2 9% 10.4

結果有幾個變化。

結束時攻擊力:

14.0 → 10.4

下降約 26%。

4 回合就結束戰鬥的速殺率:

13% → 9%

也下降了。

平均獲勝回合:

6.0 → 6.2

戰鬥稍微變長。

這幾個數字和原本希望達成的方向一致:

  • 疊攻不再透過牌組循環無限累積
  • 速殺比例下降
  • 戰鬥時間稍微拉長

不過,勝率反而從:

81% → 85%

上升了。

這個結果和原本「削弱卡片應該讓勝率下降」的直覺不太一樣。


五、為什麼一定要固定亂數種子?

這次 A/B 測試裡,固定亂數種子是一個重要條件。
兩個版本使用的是同一批隨機牌組、同樣的抽牌順序和同樣的貪婪打法,唯一主要差異是消耗機制。

也就是:

同一批牌組
       ↓
 ┌─────┴─────┐
 ↓           ↓
原本版本     新版本
無消耗       有消耗
 ↓           ↓
150 場      150 場

如果兩邊都各自重新產生一批隨機牌組,就很難知道勝率差異到底來自:

卡片機制改變

還是:

剛好抽到比較好的牌

固定亂數種子之後,兩個版本至少是在相同的起始條件下比較。
所以這次的 81% 和 85%,比較適合拿來觀察這個機制改動造成的差異。


六、這次沒有直接改數字

回頭看最開始那句:

「賣血狂暴是有點強,要怎麼調?」

最後實際修改的並不是:

+3 → +2

而是改了卡片的使用方式:

原本:

打出
 ↓
永久 +3
 ↓
進棄牌堆
 ↓
重新洗回牌組
 ↓
再次打出
 ↓
永久 +3

改成:

打出
 ↓
本場戰鬥 +N
 ↓
進入消耗堆
 ↓
本場不再抽到

所以這次真正調整的是成長機制,不是單純調低數字。
而這也是為什麼在動手修改之前,我會先要求 Claude Code 把「這張卡到底強在哪裡」找出來。
如果一開始直接把 +3 改成 +2,後面的永久疊加和生命代價問題都還會存在。


七、表格裡還有一個意外

A/B 測試跑完之後,原本預期的方向大致都出現了:

  • 結束時攻擊力下降
  • 速殺比例下降
  • 平均戰鬥時間增加

但有一個數字例外:
勝率從 81% 上升到 85%。

這不是原本修改時預期的結果。
所以這次模擬並沒有直接告訴我「新版一定比較好」。
它反而留下了下一個問題:

如果卡片被削弱了,為什麼勝率反而上升?

這個問題沒辦法只看勝率兩個數字就回答。
Day 24 就從這裡繼續往下查。

附錄:卡片組合的戰力觀察

除了單張卡片更動的數據測試,後來遊戲也加上了不同選卡流派的測試,查看各種卡牌組合的強弱之處,再跟 AI 討論如何更平衡。

設計多個各流派的選卡邏輯,再看選用的卡牌組合能打出多少場連戰記錄,除了記錄選用的卡牌,也把戰後的修整選的記錄下來。


上一篇
Day 22:【抓蟲實錄】溢殺被誤報成「護甲擋下」
下一篇
Day 24:【數據追查】削弱後勝率反而變高?原來高輸出也有代價
系列文
從 Vibe Coding 到系統架構:Gemini x Claude Code 雙 AI 協同開發 Godot 2D Roguelike 卡牌遊戲實戰 共 26 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言