今天改造老代码,用Python class实现棋子类、英雄类、和第一个英雄——孙悟空类。
老代码——# 零基础入门Python·基础篇(四)从Python基础到自走棋
今天就这样吧,遭不住了
面向对象编程(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()
在这个改造版本中,我们定义了三个核心类:Champion
、Shop
和Player
,它们分别代表游戏中的棋子、商店和玩家。通过这些类的实例化和相互作用,我们构建了游戏的基本框架和逻辑。
现在整个项目是这样的
零基础入门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)。这些特性的引入旨在丰富英雄角色,增添游戏的策略性和深度。具体来说:
- 等级(Level):反映了英雄的成长和经验积累,等级的提升可能增强英雄的基本属性或赋予新的技能,为玩家的战略选择提供更多的灵活性。
- 品质(Quality):代表了英雄的稀有程度和强度,一般而言,更高品质的英雄具备更为出众的能力和潜力,是玩家追求的重要目标。
- 羁绊(Bond):描述了英雄之间的特定联系,当特定的英雄组合在一起时,可以激活相应的羁绊效果,为团队提供额外的加成或特殊能力,增加了游戏的组队策略性。
- 价格(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
类获得了所有基本的角色属性,并添加了三个新的属性:level
、quality
和 bond
。此外,我们还实现了两个新的方法:
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自走棋游戏模拟。这种方法使得我们的代码更加模块化和易于维护。我们定义了三个核心类:Champion
、Shop
、和Player
,它们分别代表游戏中的棋子、商店和玩家。通过这些类的实例化和相互作用,我们构建了游戏的基本框架和逻辑。
此外,我们还扩展了Champion
类,创建了一个Hero
子类,它不仅继承了Champion
的所有基础属性,还引入了专属于英雄的特性,如等级(Level)、品质(Quality)、羁绊(Bond)以及价格(Price)。这些特性的引入旨在丰富英雄角色,增添游戏的策略性和深度。
通过具体实现孙悟空这个英雄类,我们展示了如何为英雄添加特殊技能和行为,使每个英雄具有独特的特性和能力,从而增加游戏的多样性和策略性。
综合作业——设计一个新的英雄
作为一个综合作业,我希望你能设计一个新的英雄类。你可以根据自己喜欢的英雄或创意来设计这个类。尝试为你的英雄添加独特的属性和技能。以下是一些指导性的问题来帮助你开始:
- 英雄的基本属性:你的英雄有什么名字?他们的基本攻击力、生命值、防御力、速度等属性是多少?
- 特殊技能:你的英雄有什么特殊技能?这个技能的效果是什么?
- 羁绊和品质:你的英雄属于哪个羁绊?他们的品质(如普通、稀有、史诗等)是什么?
- 价格和等级:获取你的英雄需要多少价格?他们如何升级,升级会带来哪些变化?
请尝试编写一个Python类来实现你设计的英雄,并确保包括初始化方法__init__
、一个或多个描述英雄技能的方法,以及一个display_info
方法来展示英雄的所有信息。
这是一个开放性的任务,鼓励你发挥创意。完成这个作业后,你将更加熟悉面向对象编程的概念,以及如何在实际项目中应用这些概念。