各位開發者們,在經歷了變數、資料型態、條件判斷、迴圈、函式與模組的學習後,我們已經掌握了 Python 程式設計的基本骨架。今天,我們將邁入物件導向程式設計(Object-Oriented Programming, OOP)的核心概念:Class (類別)。這個概念對於建構像我們《奇幻卡牌競技場》這樣複雜的遊戲,至關重要。
Python 零基礎新手入門 #10 Class (類別):
https://www.youtube.com/watch?v=AJfZvl9Hsn4&list=TLGGSr9Ziz99uDIxMzA5MjAyNQ&t=2s
你可以將 Class (類別) 想像成一個家族裡的 「家長」。每個從這個「家長」衍生出的「子子孫孫」,我們稱之為 「物件」(Objects)。這些物件會繼承「家長」的某些特質,例如長相、個性、身高和體型等,這些靜態特徵在程式中被稱為 「屬性」(Attributes)。除了靜態特質,每個子孫也從家長那邊繼承了相同的生活技能,像是說話、行走、跑步等動作,這些動態行為在 Python 中則被稱為 「方法」(Methods)。
事實上,我們之前所學到的任何資料類型,例如數字 (int, float)、字串 (str)、清單 (list) 和字典 (dictionary) 等,它們底層都是源自於 Class 的概念。每個從 Class 衍生出去的物件,都各自記錄著不同的資料和數據,而每個 Class 也都有專屬的方法,可用來執行各項特定的任務。
在 Python 中建立 Class 的流程非常簡單。假設我們要為《奇幻卡牌競技場》遊戲建立一個 「遊戲角色」(Game Character) 的 Class。通常,Class 名稱的命名規範會採用 首字大寫 的原則。
# 定義一個遊戲角色的類別
class GameCharacter:
# 共同屬性,所有新創建的角色都會有這些初始值
level = 1
experience = 0
# 實例化兩個遊戲角色物件
player1 = GameCharacter()
player2 = GameCharacter()
print(f"玩家1的等級: {player1.level}, 經驗值: {player1.experience}") # 輸出: 玩家1的等級: 1, 經驗值: 0
print(f"玩家2的等級: {player2.level}, 經驗值: {player2.experience}") # 輸出: 玩家2的等級: 1, 經驗值: 0
在這個例子中,GameCharacter 就是我們的藍圖 (Class),而 player1 和 player2 則是從這個藍圖「實例化」出來的具體物件。它們各自擁有獨立的記憶體空間,但都具備 Class 所定義的共同屬性,例如 level 和 experience。
雖然 Class 可以設定共同屬性,但每個獨立的物件也需要有自己獨特的屬性,例如角色名稱。如果每次都手動設定,當屬性很多時會非常麻煩。這時,init (initialize 的縮寫,意為初始化) 這個特殊的函式就派上用場了。
init 是一個在 物件被創建時會自動執行 的函式。它允許我們在創建物件的同時,直接傳遞參數來設定物件的初始屬性。
class GameCharacter:
# __init__ 函式用於初始化物件
def __init__(self, name, age):
self.name = name # 將傳入的 name 賦值給物件本身的 name 屬性
self.age = age # 將傳入的 age 賦值給物件本身的 age 屬性
self.level = 1
self.experience = 0
# 在創建物件時直接設定姓名和年齡
player1 = GameCharacter("英雄阿明", 25)
player2 = GameCharacter("魔導小華", 30)
print(f"{player1.name} 的年齡是 {player1.age},等級是 {player1.level}")
print(f"{player2.name} 的年齡是 {player2.age},等級是 {player2.level}")
在 init 函式中,self 參數代表了 「正在被建立的物件本身」。透過 self.屬性名稱 = 值,我們可以將傳入的引數賦值給物件的對應屬性。
方法 (Methods) 簡單來說,就是 Class 中的函式,但它專屬於該類別的物件,用來執行特定的任務。就像遊戲角色除了名字、年齡等屬性外,還具備攻擊、防禦、施展魔法等特殊技能。
class GameCharacter:
def __init__(self, name, health, attack_power):
self.name = name
self.health = health
self.attack_power = attack_power
self.shield = 0 # 新增護盾屬性
# 攻擊方法
def attack(self, target):
damage = self.attack_power
print(f"{self.name} 對 {target.name} 發動了攻擊,造成 {damage} 點傷害。")
target.take_damage(damage) # 目標受到傷害
# 受傷方法 (將在綜合練習中詳細說明)
def take_damage(self, amount):
actual_damage = amount - self.shield # 傷害扣除護盾
if actual_damage < 0:
actual_damage = 0
self.shield -= amount # 護盾吸收傷害
else:
self.shield = 0 # 護盾歸零
self.health -= actual_damage # 生命值減少
if self.health < 0:
self.health = 0
print(f"{self.name} 受到 {actual_damage} 點傷害,剩餘 HP: {self.health}, 護盾: {self.shield}")
# 顯示狀態的方法
def show_status(self):
print(f"{self.name} - HP: {self.health}, 護盾: {self.shield}")
# 創建角色
player1 = GameCharacter("勇者阿明", 100, 20)
enemy = GameCharacter("哥布林", 50, 10)
player1.attack(enemy) # 勇者阿明對哥布林發動了攻擊...
enemy.show_status() # 哥布林 - HP: 30, 護盾: 0
在 Class 中定義方法與定義普通函式類似,但它的第一個參數總是 self,它讓方法能夠存取物件自身的屬性。
在實際開發中,我們可能會有多種類型的角色,例如「戰士」、「法師」等,它們可能都共享一些基本功能(如攻擊、受傷),但又各有獨特的技能。這時,「繼承」 的概念就能派上用場。
繼承允許一個 Class (子類別) 重用另一個 Class (父類別) 的屬性和方法。這可以大幅簡化程式碼,提高可維護性。例如,我們可以讓「戰士」Class 繼承「遊戲角色」Class:
class Warrior(GameCharacter): # 戰士繼承遊戲角色
def __init__(self, name, health, attack_power, armor):
super().__init__(name, health, attack_power) # 呼叫父類別的 __init__
self.armor = armor # 戰士特有的屬性
def special_attack(self, target):
damage = self.attack_power * 1.5
print(f"{self.name} 發動特殊攻擊,對 {target.name} 造成 {damage} 點傷害!")
target.take_damage(damage)
# 創建一個戰士物件
my_warrior = Warrior("鐵壁戰士", 120, 25, 10)
my_warrior.show_status() # 繼承自 GameCharacter 的方法
# 戰士可以發動普通攻擊和特殊攻擊
enemy_goblin = GameCharacter("小哥布林", 40, 5)
my_warrior.attack(enemy_goblin)
my_warrior.special_attack(enemy_goblin)
透過在子類別名稱旁使用圓括號標註父類別名稱 (class Warrior(GameCharacter):),Warrior 就繼承了 GameCharacter 的所有屬性和能力。super().init(...) 則用於呼叫父類別的初始化函式,確保基本屬性得到正確設定 [自行補充,但符合繼承的原理]。
讓我們將 Class 的概念應用到一個回合制戰鬥遊戲的設計中,這也是您《奇幻卡牌競技場》的基礎。
在 player.py 中定義的 Player 類別就是這樣一個實例。它包含了角色的核心屬性,如 名稱 (name)、生命值 (health)、護盾 (shield)、最大生命值 (max_health) 和 額外行動次數 (extra_moves)。更重要的是,它定義了關鍵方法:
• take_damage(amount, pierce_shield=False):處理角色受到的傷害。這個方法會根據是否有護盾、以及傷害是否為穿透傷害來精確計算實際扣除的生命值。
• heal(amount):讓角色恢復生命值。
• add_shield(amount):增加角色的護盾值。
• reset_for_turn():重置每回合的狀態,例如清除額外行動次數。
在 gamemanager.py 中,GameManager 類別會利用這些 Player 物件來管理遊戲流程。它會實例化玩家和敵人,並通過調用它們的方法來模擬戰鬥。
例如,遊戲中的「攻擊」動作,不再是簡單的數值相減,而是調用目標角色的 take_damage 方法。這個方法內部已經包含了複雜的邏輯,例如先扣除護盾,再扣除生命值。
在遊戲的回合制戰鬥邏輯中,我們還可以整合 random 模組 來實現隨機性。例如,敵人的「防禦動作」可以隨機選擇「格擋」或「閃避」。如果「閃避」成功,則可能不受到傷害,失敗則受到全額傷害。特殊攻擊也可能因為精準度問題,導致傷害值減半。這些判斷都可以透過 random.choice() 或 random.randint() 函式來實現。
戰鬥流程的簡化範例:
import random # 引入 random 模組
# 假設這是簡化的 Player 類別
class Player:
def __init__(self, name, health, attack_power):
self.name = name
self.health = health
self.attack_power = attack_power
self.shield = 0
self.max_health = health
def take_damage(self, amount):
if self.shield > 0:
if amount >= self.shield:
actual_damage = amount - self.shield
self.shield = 0
self.health -= actual_damage
else:
self.shield -= amount
actual_damage = 0
else:
actual_damage = amount
self.health -= actual_damage
if self.health < 0:
self.health = 0
print(f" {self.name} 受到 {actual_damage} 點傷害。")
def heal(self, amount):
self.health = min(self.health + amount, self.max_health)
print(f" {self.name} 恢復 {amount} HP。")
def add_shield(self, amount):
self.shield += amount
print(f" {self.name} 獲得 {amount} 護盾。")
# 假設這是遊戲主邏輯的一部分
player_char = Player("勇者", 100, 20)
enemy_char = Player("惡魔", 80, 15)
print("--- 戰鬥開始 ---")
player_char.add_shield(10) # 玩家增加護盾
# 玩家攻擊回合
print(f"{player_char.name} 的回合:")
player_char.attack(enemy_char)
print(f"{enemy_char.name} 剩餘 HP: {enemy_char.health}")
# 敵人攻擊回合,隨機防禦
print(f"{enemy_char.name} 的回合:")
enemy_attack_value = enemy_char.attack_power
defense_choice = random.choice(["格擋", "閃避"]) # 隨機選擇防禦方式
if defense_choice == "格擋":
print(f" {player_char.name} 選擇格擋!傷害減半。")
player_char.take_damage(enemy_attack_value * 0.5)
elif defense_choice == "閃避":
print(f" {player_char.name} 嘗試閃避!")
if random.randint(0, 1) == 0: # 50% 機率閃避成功
print(" 閃避成功!未受到傷害。")
else:
print(" 閃避失敗!受到全額傷害。")
player_char.take_damage(enemy_attack_value)
print(f"{player_char.name} 剩餘 HP: {player_char.health}")
print("--- 戰鬥結束 ---")
這個綜合範例展示了如何使用 Class 來封裝角色的屬性和行為,並在遊戲邏輯中調用這些方法,同時結合 random 模組來增加遊戲的趣味性和不確定性。
恭喜您!今天我們深入學習了 Python 中 Class (類別) 的概念,它為我們建構複雜、有組織的遊戲物件提供了強大的藍圖。我們學會了如何定義類別、創建物件、初始化屬性、定義方法,以及利用繼承來重用程式碼。這些知識將是您開發《奇幻卡牌競技場》不可或缺的基石。明天,我們將綜合應用所有基礎語法,為更大型的專案開發做準備!