iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0
自我挑戰組

順著感覺走!從零開始的 Python & Vibe Coding 遊戲創作系列 第 17

第17天: 遊戲運行的心臟:《奇幻卡牌競技場》GameManager 的啟動與核心屬性

  • 分享至 

  • xImage
  •  

嗨,各位程式碼冒險家!歡迎來到我的「順著感覺走!從零開始的 Python & Vibe Coding 遊戲創作」第十七天。昨天我們打造了遊戲的基礎單位 Player 類別,但光有角色還不足以構成一場完整的遊戲。今天,我們將深入探討整個《奇幻卡牌競技場》的總指揮官——GameManager 類別。它就像是遊戲的心臟與大腦,負責初始化所有遊戲元素、管理回合流程、追蹤戰局狀態,並協調玩家與敵人的所有行動

在物件導向設計中,GameManager 是一個典型的核心邏輯控制器 (Core Logic Controller),它將遊戲的各個部分(玩家、牌組、規則)串連起來,形成一個有機的整體。現在,讓我們深入 gamemanager.py 檔案,剖析其結構與功能。


一、初始化遊戲世界:__init__ 方法

當一個 GameManager 物件被建立時,它的 __init__ 方法會被自動執行,這個階段的任務是建立並準備好遊戲所需的一切資源

程式碼實現 (gamemanager.py)
class GameManager:
    def __init__(self, player1_name, player2_name, max_hand_size):
        pygame.mixer.init()  # 初始化音效系統
        
        # 1. 建立玩家物件
        self.player1 = Player(player1_name)
        self.player2 = Player(player2_name)
        self.players = [self.player1, self.player2]
        
        # 2. 初始化牌組與牌堆
        self.full_deck = []
        self.remaining_deck = []
        self.center_pile = []
        self.discard_piles = {self.player1: [], self.player2: []}
        
        # 3. 設定遊戲狀態與規則
        self.current_player_index = 0
        self.turn_count = 0
        self.max_rounds = 15
        self.game_state = "INITIALIZING"
        self.max_hand_size = max_hand_size
        self.max_actions_per_turn = 5
        self.action_count = 0
        self.min_center_cards = 5

        # 4. 建立戰鬥日誌與音效資源
        self.combat_log = []
        self.add_to_log("遊戲開始!")
        self.sounds = {
            "draw_card": pygame.mixer.Sound(os.path.join(base_path, "audio", "draw_card_bg.wav")),
            "touch_card": pygame.mixer.Sound(os.path.join(base_path, "audio", "touch_card_bg.wav")),
            # ... 其他音效
        }
核心屬性技術解析
  1. 玩家與牌堆管理

    • self.player1self.player2:透過傳入的名稱,實例化兩個 Player 物件。
    • self.full_deckself.remaining_deck:分別代表完整的 54 張牌組與遊戲中剩餘可抽的牌組。
    • self.center_pile:一個清單(List),存放桌面中央的公共卡牌。
    • self.discard_piles:一個字典(Dictionary)鍵(Key) 是玩家物件,值(Value) 是對應玩家的棄牌堆(一個清單)。這種結構能清晰地將棄牌堆與特定玩家綁定。
  2. 遊戲狀態與規則

    • self.game_state:一個字串,用來追蹤遊戲目前所處的階段(例如 "INITIALIZING", "PLAYER_TURN", "GAME_OVER"),這是控制遊戲流程的關鍵。
    • self.turn_count:記錄目前的回合數,用於判斷是否達到 15 回合的上限。
    • self.max_actions_per_turn:定義了每回合最多可進行 5 次行動的規則。
    • self.action_count:計數器,用於追蹤當前回合已執行的行動次數。
  3. 輔助系統

    • self.combat_log:一個清單,用來儲存遊戲過程中發生的事件字串,形成戰鬥日誌。
    • self.sounds:一個字典,集中管理所有遊戲音效。鍵是音效的名稱(如 "draw_card"),值是載入後的 pygame.mixer.Sound 物件,方便後續透過 play_sound("draw_card") 這樣直觀的方式呼叫。

二、資源路徑的守護者:resource_path 函式

在開發遊戲時,我們通常使用相對路徑來讀取圖片、音效等資源。但當使用 PyInstaller 這類工具將遊戲打包成獨立執行檔(.exe)時,程式的執行環境會發生改變,原本的相對路徑會失效。

為了讓遊戲無論是在開發環境執行,還是在打包後執行,都能正確找到資源檔,我們需要一個特別的函式來處理路徑問題。

程式碼實現 (gamemanager.py)
import sys
import os

def resource_path(relative_path):
    """取得資源的絕對路徑,不論是在開發環境還是打包後的 .exe。"""
    try:
        # PyInstaller 建立一個暫存資料夾並將路徑儲存在 _MEIPASS
        base_path = sys._MEIPASS
    except Exception:
        # 在非打包環境中,取得腳本所在的絕對路徑
        base_path = os.path.abspath(".")
    return os.path.join(base_path, relative_path)

# 將 base_path 設為指向根目錄
base_path = resource_path(".")
  • sys._MEIPASS:這是 PyInstaller 在執行打包後的程式時,會建立的一個特殊屬性。它指向一個暫存資料夾,所有資源檔(圖片、音效等)都會被解壓縮到這裡。
  • try-except 結構:這個結構非常關鍵。程式會嘗試讀取 sys._MEIPASS,如果成功,代表目前是在打包後的環境執行,base_path 就會是暫存資料夾的路徑。如果失敗(except),則代表是在正常的開發環境中,base_path 就會是專案的根目錄。
  • os.path.join():這個函式會根據作業系統,智慧地將 base_path 和我們傳入的相對路徑(如 "audio/draw_card_bg.wav")組合成一個完整的、正確的絕對路徑。

透過今天對 GameManager 初始化過程的深度剖析,我們可以看到一個好的遊戲架構是如何在開頭就將所有元素——玩家狀態、牌組管理、遊戲規則、乃至於底層的資源路徑——都考慮周全。這個穩固的基礎,為後續實現複雜的卡牌配對、技能觸發和 AI 邏輯提供了強而有力的支援。

明天,我們將繼續探索 GameManager 的內部,揭示卡牌技能是如何被程式碼精準觸發的。敬請期待!


上一篇
第16天: 戰場上的生存者:《奇幻卡牌競技場》Player 類別的屬性與行為
下一篇
第18天: 觸發強力效果:卡牌技能的程式碼實現深度解析
系列文
順著感覺走!從零開始的 Python & Vibe Coding 遊戲創作20
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言