掘金 后端 ( ) • 2024-04-28 10:45

今天改造老代码,用Python class实现棋子类、英雄类、和第一个英雄——孙悟空类。

老代码——# 零基础入门Python·基础篇(四)从Python基础到自走棋

今天就这样吧,遭不住了

image.png

面向对象编程(OOP)是一种编程范式,它使用“对象”来模拟现实世界中的事物和事物之间的交互。在Python中,我们可以通过定义类(class)来创建对象。类是一种定义对象属性(数据)和行为(方法)的蓝图或模板。

在本文中,我们将使用面向对象的概念来改造之前的自走棋游戏模拟。这将使代码更加模块化、易于理解和维护。

改造老代码,定义基本类

1. 定义棋子类(Champion)

棋子类将代表游戏中的一个棋子,包含棋子的名称、成本等属性,以及可能的行为。

# champion.py
# champions.py升级而来,模块的内容逻辑有变化了
class Champion:
    """
    代表游戏中的一个棋子。

    属性:
    - name (str): 棋子的名称。
    - cost (int): 购买棋子所需的金币数量。

    方法:
    - __str__: 返回棋子的字符串表示,包括名称和成本。
    """
    def __init__(self, name, cost):
        self.name = name
        self.cost = cost

    def __str__(self):
        return f"{self.name} (成本: {self.cost})"

2. 定义商店类(Shop)

商店类将管理棋子的展示和购买。

# shop.py
import random  # 导入random模块,以便进行随机操作

class Shop:
    """
    管理游戏中的商店,包括棋子的展示和刷新。

    属性:
    - champions_list (list): 可购买的棋子列表。
    - store_champions (list): 当前商店中展示的棋子列表。

    方法:
    - refresh_store: 随机从champions_list中选择3个棋子展示在商店中。
    - show_champions: 打印当前商店中可购买的棋子。
    """
    def __init__(self, champions_list):
        self.champions_list = champions_list
        self.store_champions = []

    def refresh_store(self):
        self.store_champions = random.sample(self.champions_list, 3)

    def show_champions(self):
        for champ in self.store_champions:
            print(champ)

3. 定义玩家类(Player)

玩家类将管理玩家的金币和购买行为。

# player.py
# 该模块是buy.py的升级版本,后续游戏中玩家的相关封装都在这儿
class Player:
    """
    代表游戏中的玩家,管理玩家的金币和购买行为。

    属性:
    - gold (int): 玩家拥有的金币数量。

    方法:
    - buy_champion: 尝试使用金币购买指定的棋子。
    """
    def __init__(self, gold=5):
        self.gold = gold

    def buy_champion(self, champion, shop):
        if champion in shop.store_champions and self.gold >= champion.cost:
            self.gold -= champion.cost
            shop.store_champions.remove(champion)
            print(f"已购买{champion}。")
        else:
            print("无法购买该英雄。")

重写主函数main.py整合游戏逻辑

接下来,我们将使用上述定义的类来构建游戏的主要逻辑。

# main.py
from shop import Shop
from champion import Champion
from player import Player

def main():
    """
    游戏的主入口。初始化游戏环境,并进入游戏的主循环。
    """
    # 定义可用的英雄列表
    champions_list = [
        Champion("赵云", 1),
        Champion("亚索", 2),
        Champion("韩信", 3),
        Champion("孙悟空", 4),
    ]

    # 创建商店和玩家实例
    shop = Shop(champions_list)
    player = Player()

    # 游戏主循环
    while True:
        shop.refresh_store()
        print("可购买的英雄:")
        shop.show_champions()

        choice = input("想购买哪位英雄?(输入名称或'退出'结束游戏)")
        if choice.lower() == '退出':
            break

        found_champion = None
        for champ in shop.store_champions:
            if champ.name.lower() == choice.lower():
                found_champion = champ
                break

        if found_champion:
            player.buy_champion(found_champion, shop)
        else:
            print("商店中找不到该英雄。")

        print(f"剩余金币: {player.gold}")

if __name__ == "__main__":
    main()

在这个改造版本中,我们定义了三个核心类:ChampionShopPlayer,它们分别代表游戏中的棋子、商店和玩家。通过这些类的实例化和相互作用,我们构建了游戏的基本框架和逻辑。

现在整个项目是这样的

零基础入门Python/code/day2
├── __pycache__                  # Python自动生成的字节码缓存文件夹,用于加速模块加载
├── champion.py                  # 定义了Champion类,代表游戏中的棋子,包含棋子的属性和方法
├── main.py                      # 游戏的主入口文件,负责初始化游戏环境并控制游戏的主循环
├── player.py                    # 定义了Player类,代表游戏中的玩家,管理玩家的金币和购买行为
└── shop.py                      # 定义了Shop类,管理游戏中的商店,包括棋子的展示和刷新

这种面向对象的方法让代码的结构更清晰,也更容易扩展。例如,如果想要增加棋子的属性(如种族、职业等),只需在Champion类中添加相应的属性和方法,而不需要修改其他部分的代码。这样的灵活性和可维护性是面向对象编程的主要优势之一。

体验一下

root@obkose3:/home/Python/零基础入门Python/code/day2# python3 main.py
可购买的英雄:
亚索 (成本: 2)
韩信 (成本: 3)
孙悟空 (成本: 4)
想购买哪位英雄?(输入名称或'退出'结束游戏)亚索
已购买亚索 (成本: 2)。
剩余金币: 3
可购买的英雄:
孙悟空 (成本: 4)
韩信 (成本: 3)
亚索 (成本: 2)
想购买哪位英雄?(输入名称或'退出'结束游戏)亚索
已购买亚索 (成本: 2)。
剩余金币: 1
可购买的英雄:
赵云 (成本: 1)
韩信 (成本: 3)
孙悟空 (成本: 4)
想购买哪位英雄?(输入名称或'退出'结束游戏)赵云
已购买赵云 (成本: 1)。
剩余金币: 0
可购买的英雄:
亚索 (成本: 2)
韩信 (成本: 3)
赵云 (成本: 1)
想购买哪位英雄?(输入名称或'退出'结束游戏)

是不是有内味儿了?

扩展棋子与英雄类

对于平时玩游戏,相对于PVP或者PVE而言我最喜欢的还是收集各种兵种和英雄、武将。所以,我们的扩展还是从英雄开始。道具、战斗系统、匹配平台、大厅啥的后面再说吧~

重写Champion

在下棋游戏中,每个英雄都有自己的属性,比如生命值、攻击力、防御力、等级、品质、职业、羁绊以及特殊技能等等。我们之前定义了棋子类Campion,而英雄、野怪/小兵也是一个棋子。所以我们先需要重写一下棋子类 Champion

# champion.py
from typing import List

class Champion:
    """代表游戏中所有角色的基类。
    
    属性:
        name (str): 角色名称。
        attack (int): 攻击力。
        health (int): 生命值。
        defense (int): 防御力。
        speed (int): 速度。
        attack_range (int): 攻击距离。
        attack_speed (int): 攻击速度。
    """
    
    def __init__(self, name: str, attack: int, health: int, defense: int, speed: int, attack_range: int = 1, attack_speed: int = 1) -> None:
        """初始化角色的基本属性以及攻击距离和攻击速度。"""
        self.name: str = name
        self.attack: int = attack
        self.health: int = health
        self.defense: int = defense
        self.speed: int = speed
        self.attack_range: int = attack_range
        self.attack_speed: int = attack_speed

    def take_damage(self, amount: int) -> None:
        """角色受到伤害并减少生命值,如果生命值小于等于0,则调用die方法。
        
        参数:
            amount (int): 受到的伤害量。
        """
        self.health -= amount
        if self.health <= 0:
            self.die()

    def die(self) -> None:
        """角色死亡时的处理方法。"""
        print(f"{self.name} has died.")

    def display_info(self) -> None:
        """显示角色的所有基本信息。"""
        info = (
            f"Name: {self.name}\n"
            f"Attack: {self.attack}\n"
            f"Health: {self.health}\n"
            f"Defense: {self.defense}\n"
            f"Speed: {self.speed}\n"
            f"Attack Range: {self.attack_range}\n"
            f"Attack Speed: {self.attack_speed}"
        )
        print(info)

重写Champion类中定义了以下属性,用于描述角色的基本特征和能力:

  • name (str): 角色的名称。
  • attack (int): 角色的攻击力,影响角色对敌人造成的伤害。
  • health (int): 角色的生命值,表示角色的生存能力。生命值降到0时,角色死亡。
  • defense (int): 角色的防御力,能够减少受到的伤害。
  • speed (int): 角色的速度,可能影响角色的行动顺序或者移动速度。
  • attack_range (int): 角色的攻击距离,表示角色能够攻击到多远的敌人。
  • attack_speed (int): 角色的攻击速度,可能影响角色攻击的频率。

价格属性被删除了,因为这不是所有棋子的通用属性。这个会在英雄类中出现

__init__ 方法

def __init__(self, name: str, attack: int, health: int, defense: int, speed: int, attack_range: int = 1, attack_speed: int = 1) -> None:

这个方法是类的构造函数,用于在创建类的新实例时初始化其属性。构造函数接受角色的名称、攻击力、生命值、防御力、速度以及可选的攻击距离和攻击速度作为参数,并将它们赋值给实例的属性。

take_damage 方法

def take_damage(self, amount: int) -> None:

这个方法用于处理角色受到伤害的情况。它接受一个表示伤害量的整数 amount 作为参数,将这个伤害量从角色的生命值中扣除。如果角色的生命值降至0或以下,将调用 die 方法处理角色的死亡。

die 方法

def die(self) -> None:

这个方法用于处理角色死亡的情况。当角色的生命值降至0或以下时,此方法被调用。目前,它的实现仅仅是打印出一条消息,表示角色已经死亡。后面写到战斗系统的时候这个方法还会负责给战斗系统、羁绊系统等发送棋子阵亡消息

display_info 方法

def display_info(self) -> None:

打印出角色的所有基本属性,包括名称、攻击力、生命值、防御力、速度、攻击距离和攻击速度。通过调用这个方法,可以很方便地查看和验证角色的当前状态和属性。这种方式使得代码具有更好的可读性和易于调试的特点。

英雄类Hero

基于 Champion 类的基础属性,我们接下来将开发一个名为 Hero 的子类。这个子类不仅继承了 Champion 的所有基础属性,还引入了几个专属于英雄的特性,包括等级(Level)、品质(Quality)、羁绊(Bond)以及价格(Price)。这些特性的引入旨在丰富英雄角色,增添游戏的策略性和深度。具体来说:

  1. 等级(Level):反映了英雄的成长和经验积累,等级的提升可能增强英雄的基本属性或赋予新的技能,为玩家的战略选择提供更多的灵活性。
  2. 品质(Quality):代表了英雄的稀有程度和强度,一般而言,更高品质的英雄具备更为出众的能力和潜力,是玩家追求的重要目标。
  3. 羁绊(Bond):描述了英雄之间的特定联系,当特定的英雄组合在一起时,可以激活相应的羁绊效果,为团队提供额外的加成或特殊能力,增加了游戏的组队策略性。
  4. 价格(Price):定义了获取英雄所需的资源或货币数量,价格因素影响了玩家在购买、升级英雄时的经济策略,使游戏经济系统与英雄系统相互影响,共同构成了游戏的复杂性。

通过在 Hero 类中融入这些特性,我们不仅保留了 Champion 类的通用属性和行为,还为英雄角色添加了更多的维度和战略价值,极大地提升了游戏的可玩性和多样性。

代码如下:

from typing import List

class Hero(Champion):
    """代表游戏中的英雄,继承自Champion类,并添加了英雄特有的属性,包括价格。
    
    属性:
        level (int): 英雄的等级。
        quality (str): 英雄的品质。
        bond (List[str]): 英雄的羁绊列表。
        price (int): 购买或升级英雄所需的价格。
    """
    
    def __init__(self, name: str, attack: int, health: int, defense: int, speed: int, level: int = 1, quality: str = "Common", bond: List[str] = None, price: int = 100) -> None:
        """初始化英雄的基本属性以及英雄特有的属性,包括价格。"""
        super().__init__(name, attack, health, defense, speed)
        self.level = level
        self.quality = quality
        self.bond = bond if bond is not None else []
        self.price = price
        
    def level_up(self) -> None:
        """提升英雄的等级,并相应增加价格。"""
        self.level += 1
        print(f"{self.name} has leveled up to level {self.level}! New price: {self.price}")
        
    def display_info(self) -> None:
        """显示英雄的所有信息,包括继承自Champion的属性和英雄特有的属性,以及价格。"""
        super().display_info()
        extra_info = (
            f"Level: {self.level}\n"
            f"Quality: {self.quality}\n"
            f"Bond: {', '.join(self.bond) if self.bond else 'None'}\n"
            f"Price: {self.price}"
        )
        print(extra_info)

在这个实现中,Hero 类通过继承 Champion 类获得了所有基本的角色属性,并添加了三个新的属性:levelqualitybond。此外,我们还实现了两个新的方法:

  • level_up 方法用于提升英雄的等级,每次调用时英雄的等级增加1,并打印一条消息表示英雄升级了。
  • 覆盖了基类的 display_info 方法,以包含显示英雄特有属性的功能。首先,它调用基类的 display_info 方法打印出基本属性,然后打印出英雄的等级、品质和羁绊信息。

定义孙悟空类

这个实现将展示如何基于Hero类创建具体的英雄,并定义其特有的属性和可能的特殊技能。

孙悟空是一个具有高攻击力和特殊技能的英雄。在这个例子中,我们假设孙悟空有一个特殊技能叫做“七十二变”,这个技能让他在一定时间内免疫所有伤害。

首先,我们需要从之前定义的Hero类继承,然后添加孙悟空特有的属性和技能。

class SunWukong(Hero):
    """
    孙悟空英雄类,继承自Hero类。
    """
    def __init__(self):
        # 假设孙悟空的基本属性如下:攻击力100,生命值1000,防御力50,速度20,价格5
        # 孙悟空是一个高级英雄,因此设置其品质为"Epic",并具有特定的羁绊
        super().__init__(name="孙悟空", attack=100, health=1000, defense=50, speed=20, quality="Epic", bond=["西游记", "神仙"], price=300)
        self.skill = "七十二变"  # 特殊技能

    def use_skill(self):
        """
        使用孙悟空的特殊技能“七十二变”,在一定时间内免疫所有伤害。
        """
        print(f"{self.name} 使用了特殊技能:{self.skill},短时间内免疫所有伤害!")

    def display_info(self):
        """
        显示孙悟空的所有信息,包括继承自Hero的属性和孙悟空特有的属性。
        """
        super().display_info()
        print(f"Special Skill: {self.skill}")

在这个类中,我们做了以下几点:

  • 通过调用super().__init__方法,继承了Hero类的构造函数,并设置了孙悟空特有的属性值。
  • 添加了一个新的属性skill,用来表示孙悟空的特殊技能“七十二变”。
  • 定义了一个新的方法use_skill,模拟孙悟空使用其特殊技能的行为。在实际的游戏中,这个方法可以被进一步扩展,以实现技能的具体效果,比如免疫伤害。
  • 重写了display_info方法,以包含显示孙悟空特有的技能信息。

总结

在本次改造中,我们采用了面向对象编程(OOP)的方法来重构Python自走棋游戏模拟。这种方法使得我们的代码更加模块化和易于维护。我们定义了三个核心类:ChampionShop、和Player,它们分别代表游戏中的棋子、商店和玩家。通过这些类的实例化和相互作用,我们构建了游戏的基本框架和逻辑。

此外,我们还扩展了Champion类,创建了一个Hero子类,它不仅继承了Champion的所有基础属性,还引入了专属于英雄的特性,如等级(Level)、品质(Quality)、羁绊(Bond)以及价格(Price)。这些特性的引入旨在丰富英雄角色,增添游戏的策略性和深度。

通过具体实现孙悟空这个英雄类,我们展示了如何为英雄添加特殊技能和行为,使每个英雄具有独特的特性和能力,从而增加游戏的多样性和策略性。

综合作业——设计一个新的英雄

作为一个综合作业,我希望你能设计一个新的英雄类。你可以根据自己喜欢的英雄或创意来设计这个类。尝试为你的英雄添加独特的属性和技能。以下是一些指导性的问题来帮助你开始:

  1. 英雄的基本属性:你的英雄有什么名字?他们的基本攻击力、生命值、防御力、速度等属性是多少?
  2. 特殊技能:你的英雄有什么特殊技能?这个技能的效果是什么?
  3. 羁绊和品质:你的英雄属于哪个羁绊?他们的品质(如普通、稀有、史诗等)是什么?
  4. 价格和等级:获取你的英雄需要多少价格?他们如何升级,升级会带来哪些变化?

请尝试编写一个Python类来实现你设计的英雄,并确保包括初始化方法__init__、一个或多个描述英雄技能的方法,以及一个display_info方法来展示英雄的所有信息。

这是一个开放性的任务,鼓励你发挥创意。完成这个作业后,你将更加熟悉面向对象编程的概念,以及如何在实际项目中应用这些概念。