iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0
自我挑戰組

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

第二十七天:清晰的戰局:即時訊息與可滾動戰鬥日誌

  • 分享至 

  • xImage
  •  

歡迎來到我的「順著感覺走!從零開始的 Python & Vibe Coding 遊戲創作」的第 27 天!今天,我們將深入探討一個對於提升玩家體驗至關重要的功能:即時訊息系統可滾動的戰鬥日誌,並附上核心的程式碼實現與解釋。在 Vibe Coding 的開發哲學下,我不僅僅是實現功能,更是要讓玩家能「感覺」到戰局的每一次變化。一個清晰的資訊反饋系統,能讓玩家完全沉浸在策略思考中,而不會被混亂的介面所干擾,這正是 Vibe Coding 強調的「忘記程式碼存在」的流暢體驗。

一、即時訊息系統:短暫卻關鍵的戰況提示

在快節奏的卡牌對戰中,玩家需要立即知道他們的操作是否成功、為何失敗,或是敵人採取了什麼行動。為此,我設計了一個短暫顯示的訊息系統,由 show_message 方法驅動。

show_message 方法程式碼
# 位於 main.py 的 Game 類別中
def show_message(self, message, duration=60):
    self.last_action_message = message
    self.message_timer = duration
程式碼解釋與運作機制
  • show_message(self, message, duration=60):這個方法的核心非常直觀:接收一個 message 字串,並將其顯示在畫面上,持續一個預設的 duration(以遊戲幀數計算,60 幀約為 1 秒)。
  • 訊息儲存:當 show_message 被呼叫時,它會將傳入的訊息儲存到 self.last_action_message 變數中。
  • 計時器啟動:同時,self.message_timer 會被設定為指定的持續時間 duration
  • 逐幀遞減與顯示:在遊戲的主迴圈 run() 中,每一幀都會檢查 self.message_timer。只要計時器大於 0,就會將 self.last_action_message 繪製在螢幕中央頂部,並將計時器減 1。當計時器歸零時,訊息便不再顯示。

這個簡單的計時器機制,確保了戰況提示既能及時傳達,又不會永久佔用螢幕空間,讓介面始終保持整潔。

二、深度回顧:可滾動的戰鬥日誌

雖然即時訊息很方便,但玩家有時需要回顧整個戰鬥的詳細過程。這就是 draw_combat_log_window 方法的用武之地,它不僅僅是顯示文字,更是一個功能完整的互動視窗。

draw_combat_log_window 核心程式碼
# 位於 main.py 的 Game 類別中
def draw_combat_log_window(self):
    # ... (視窗尺寸定義)
    
    # 1. 建立半透明遮罩
    s = pygame.Surface((mask_width, mask_height), pygame.SRCALPHA)
    s.fill((0, 0, 0, 200)) # Alpha值設為200,呈現半透明
    screen.blit(s, (mask_x, mask_y))
    # 繪製白色邊框
    pygame.draw.rect(screen, (255, 255, 255), (window_x, window_y, window_width, window_height), border_thickness)

    # ... (標題繪製)

    # 2. 限制滾動範圍
    total_log_height = len(self.gm.combat_log) * log_entry_height
    max_scroll = max(0, total_log_height - log_area_height)
    self.log_scroll_offset = max(0, min(self.log_scroll_offset, max_scroll))

    # 3. 創建子表面以限制繪圖區域
    log_surface_rect = pygame.Rect(log_area_x, log_area_start_y, window_width - 40, log_area_height)
    log_surface = screen.subsurface(log_surface_rect)
    
    # 4. 繪製可見內容
    for i, entry in enumerate(self.gm.combat_log):
        draw_y = i * log_entry_height - self.log_scroll_offset
        if 0 < draw_y + log_entry_height and draw_y < log_area_height:
            # 5. 根據內容設定不同顏色
            if "回合:" in entry:
                text_color = (255, 255, 0)
            elif "敵" in entry:
                text_color = (255, 100, 100)
            elif "玩家" in entry:
                text_color = (100, 255, 100)
            else:
                text_color = (255, 255, 255)
            self.draw_text(entry, 10, draw_y, text_color, FONT_COMBAT_LOG, surface=log_surface)
程式碼解釋與運作機制
  1. 半透明背景與邊框
    為了在不完全遮擋遊戲畫面的情況下清晰顯示日誌,我首先創建了一個帶有 Alpha 通道的半透明黑色 Surface (pygame.SRCALPHA),並將其繪製在白色邊框內。這創造了一種層次感,讓 UI 看起來更專業。

  2. 日誌內容的滾動實現

    • 滾動偏移量 self.log_scroll_offset:這是一個關鍵屬性,記錄了日誌內容向上滾動的像素距離。
    • 滑鼠滾輪事件:在主迴圈 run() 中,我們監聽 pygame.MOUSEWHEEL 事件。當玩家滾動滑鼠滾輪時,event.y 會回傳一個正值(向上滾動)或負值(向下滾動)。我們用這個值來更新 self.log_scroll_offset
    • 限制滾動範圍:為了防止滾動超出內容邊界,我們計算出最大可滾動距離 max_scroll,並確保 self.log_scroll_offset 始終介於 0 和 max_scroll 之間。
    • 繪製可見內容:在繪製日誌時,每一條目的 Y 座標都會減去 self.log_scroll_offset。我們只繪製那些計算後仍在可見區域 (log_area_height) 內的條目,從而實現了高效的滾動視覺效果。
  3. 日誌內容的顏色區分
    為了讓日誌更具可讀性,我根據日誌內容的關鍵字(如「回合:」、「敵」、「玩家」)賦予不同的顏色。這讓玩家可以快速掃描並定位到自己感興趣的資訊。

三、日誌的產生與管理

戰鬥日誌的內容來源於 GameManager 中的 add_to_log 方法。遊戲中幾乎每一個重要事件——從抽牌、卡牌效果觸發到回合開始——都會呼叫此方法,將一條格式化的訊息添加到 self.combat_log 列表中。

為了防止日誌無限增長導致記憶體問題,我還設置了一個上限(500 條)。當日誌超過這個長度時,最舊的紀錄會被自動移除 (pop(0)),確保了系統的穩定性。

# 位於 gamemanager.py 的 GameManager 類別中
def add_to_log(self, message):
    self.combat_log.append(message)
    if len(self.combat_log) > 500:
        self.combat_log.pop(0)

透過即時訊息和可滾動的戰鬥日誌,我們為《奇幻卡牌競技場》打造了一個清晰、反應迅速且使用者友善的資訊系統。這正是我在 Vibe Coding 理念下所追求的:將複雜的底層邏輯轉化為玩家直覺、流暢的遊戲體驗。明天,我們將為這款遊戲進行遊戲音效與背景音樂!


上一篇
第二十六天:指尖的策略:滑鼠事件處理與卡牌的精準選取
下一篇
第二十八天:聽覺的盛宴:遊戲音效與背景音樂的魅力
系列文
順著感覺走!從零開始的 Python & Vibe Coding 遊戲創作30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言