嗨,各位程式碼冒險家!歡迎來到我的「順著感覺走!從零開始的 Python & Vibe Coding 遊戲創作」第二十天。今天,我們將深入《奇幻卡牌競技場》的心臟地帶,探討整個遊戲最核心的互動機制——卡牌配對(Card Matching) 與那令人振奮的自動連擊(Auto-Combo)。這不僅是遊戲策略的體現,更是 GameManager
類別中一系列精密方法協同運作的成果。
這兩個機制將玩家的策略選擇與遊戲的隨機性巧妙地結合在一起,創造出充滿變數與驚喜的戰鬥體驗。現在,讓我們剖析 gamemanager.py
中負責實現這一切的關鍵程式碼。
process_player_match
方法當玩家從手牌中選擇一張卡,並點擊桌面上相同類型的卡牌時,process_player_match
方法就會被觸發。這個方法是玩家行動的主要入口,它負責驗證操作的合法性,並執行一連串精心設計的連鎖反應。
gamemanager.py
)def process_player_match(self, player, hand_index, center_index):
# 1. 條件驗證
if self.game_state != "PLAYER_TURN":
return False, "現在不是你的回合!"
if self.action_count >= self.max_actions_per_turn:
return False, f"已達本回合行動上限 ({self.max_actions_per_turn} 次)。請結束回合。"
# 2. 索引合法性檢查 (略) ...
hand_card = player.hand[hand_index]
center_card = self.center_pile[center_index]
# 3. 核心配對邏輯
if hand_card.card_type == center_card.card_type:
self.play_sound("touch_card") # 播放音效
# 3a. 觸發卡牌效果
self.trigger_card_effect(hand_card.card_type, player, self.get_other_player(player))
# 3b. 移除並棄牌
removed_hand_card = player.hand.pop(hand_index)
removed_center_card = self.center_pile.pop(center_index)
self.discard_piles[player].append(removed_hand_card)
self.discard_piles[player].append(removed_center_card)
# 3c. 消耗行動次數
self.action_count += 1
# 3d. 從牌組翻開新牌
flipped_card = self.draw_card_to_center()
# 3e. 嘗試觸發自動連擊
if flipped_card:
auto_matched, auto_match_result_msg = self._attempt_auto_match_on_new_card(flipped_card, player)
return True, "配對成功!" # 返回成功訊息
else:
return False, "❌ 卡牌類型不同,無法配對。"
前置條件驗證:在執行任何核心邏輯前,程式會先進行嚴格的防呆檢查。它會確認 self.game_state
是否為 "PLAYER_TURN"
,以及 self.action_count
是否已達到 self.max_actions_per_turn
(預設為 5 次)的上限。這確保了玩家只能在自己的回合且有行動次數時才能操作,維持了遊戲規則的嚴謹性。
核心配對流程:
trigger_card_effect
):一旦確認卡牌類型相符,程式會立即呼叫我們前幾天建立的 trigger_card_effect
方法。例如,配對「劍士」卡會造成 15 點傷害,而「吟遊詩人」則會恢復 5 點生命並提供 5 點護盾。pop()
方法從手牌 (player.hand
) 和桌面牌堆 (self.center_pile
) 移除,再被 append()
到玩家的棄牌堆 (self.discard_piles[player]
) 中。這個過程確保了牌局的持續流動。draw_card_to_center
):配對後,系統會立刻從牌組翻開一張新牌到桌面。這個機制為遊戲注入了關鍵的隨機性與刺激感,因為接下來發生的事,將取決於這張新牌。_attempt_auto_match_on_new_card
方法這是遊戲中最令人興奮的機制——自動連擊。當 process_player_match
翻開一張新牌後,會立即呼叫這個私有方法,檢查這張新牌是否能與桌面上已有的牌觸發連鎖反應。
gamemanager.py
)def _attempt_auto_match_on_new_card(self, new_card, player_who_caused_draw):
# 遍歷桌面上除了新牌之外的所有牌
for i in range(len(self.center_pile) - 1):
card_on_table = self.center_pile[i]
# 如果找到相同類型的牌
if card_on_table.card_type == new_card.card_type:
# 移除這兩張配對的牌
removed_center_card_1 = self.center_pile.pop(i)
removed_center_card_2 = self.center_pile.pop() # 此時 new_card 在列表末端
# 再次觸發技能效果!
self.trigger_card_effect(removed_center_card_1.card_type, player_who_caused_draw, self.get_other_player(player_who_caused_draw))
# 將配對的牌放入棄牌堆
self.discard_piles[player_who_caused_draw].append(removed_center_card_1)
self.discard_piles[player_who_caused_draw].append(removed_center_card_2)
self.play_sound("touch_card")
self.add_to_log(f"自動配對 {removed_center_card_1.card_type.value}!")
return True, "自動配對成功!" # 返回成功標記
return False, "" # 沒有找到可自動配對的牌
for
迴圈遍歷桌面牌堆 (self.center_pile
) 中除了剛翻開的新牌之外的所有卡牌。如果發現任何一張牌的 card_type
與新牌相同,自動配對即告成功。action_count
)。這使得一次普通的配對,有可能因為運氣好而演變成一連串強大的連擊,瞬間扭轉戰局。透過 process_player_match
和 _attempt_auto_match_on_new_card
這兩個方法的無縫銜接,我們不僅實現了玩家策略性的卡牌配對,更融入了充滿變數的自動連擊機制。這套系統讓每一次出牌都充滿了期待,也使得《奇幻卡牌競技場》的戰鬥節奏更加緊湊、富有深度。
明天,我們將把目光轉向對手,深入探討敵方 AI 是如何思考與行動的。敬請期待!