大爽Python入门教程 7-4 实践演示 控制台版本——简易回合战斗

大爽Python入门公开课教案 点击查看教程总目录

1 背景介绍

不知道大家有没有玩过魔塔。
在我小时候,这是一个很经典又好玩的小游戏。

其实最早想做一个控制台版本的简易魔塔。
后来发现控制台实现的效果实在是不理想,而且耗费的精力又颇大。
总的来讲,就是费力不讨好。

所以做了更进一步的简化,用控制台只实现简化了的回合战斗。

功能大概有两处:

  1. 输入命令,获取玩家信息或者退出游戏。
  2. 输入敌人,让玩家和敌人战斗,将战斗结果展示出来。

2 详细说明

玩家和敌人都属于人,有以下三个基本属性(以下建成三维)

  • 血量: hp
  • 攻击力: attack
  • 防御力: defence

都有一个基本方法

  • 打击(攻击): hit
    攻击的基本计算方式为: 伤害 = 自己攻击力 - 对手防御力
    伤害为正时,扣除敌人对应血量。

  • 是否存活: is_alive
    即血量大于 0

玩家特有属性

  • 等级: lv
    初始等级为1。
    每升一级,血量恢复。三维翻倍。
  • 经验: exp
    该值分两部分,一个是当前经验,一个是升级经验。
    当前经验够升级时,扣除升级经验并升级。
    每升一级,所需升级经验翻倍。

敌人特有方法

  • 经验掉落: drop_exp
    该方法返回经验值,战胜敌人即可获得该经验值。

敌人分三档

  • 普通敌人
  • 高级敌人: 攻击时,无视玩家防御(即伤害=攻击力)
  • BOSS: 攻击时,无视玩家防御(即伤害=攻击力),还能自己回血(回血量=伤害量)

数值设置

这个可以*发挥
我这里的设置如下

玩家

hp, attack, defence = 100, 10, 5
exp = 0 / 20

普通敌人

hp, attack, defence = 50, 10, 5

掉落经验值:10

高级敌人

hp, attack, defence = 100, 20, 10

掉落经验值:20

BOSS

hp, attack, defence = 200, 40, 20

掉落经验值:40

游戏流程

运行游戏,先展示欢迎信息。

Welcome to my game.

再展示玩家信息

======= Player status ========
HP: 100 / 100
Attack: 10
Defence: 10
Lv: 1. EXP: 0/ 20
==============================

接着提醒用户输入

Enter your command:

玩家可以输入命令,或者敌人

可解析的命令如下

  • s: 展示玩家信息
  • q: 退出游戏

退出游戏时,输出如下

Bye.

可解析的敌人如下

  • e: Enemy,普通敌人
  • a: AdvancedEnemy, 高级敌人
  • b: Boss, 老怪

输入敌人,则让玩家和敌人战斗,
战斗流程是,玩家先攻击敌人,然后敌人再攻击玩家,直至一方死亡。

战胜敌人时,输出战胜信息如下(包括敌人种类,获得经验,当前经验,剩余血量)
(比如战胜普通敌人)

Defeat enemy: Enemy. Gain exp: 10. Current exp: 10 / 20. Left hp: 55

战斗过程中,如果有升级,则输出升级信息如下

You upgraded, current level: 2, current hp: 200.

战斗失败,输出失败信息如下,且结束游戏

You lost. Boss's left hp: 100

可以一次输入多个敌人,玩家从前往后依次战斗。

运行效果

输入分别是

e
e
a
b

运行效果如下

Welcome to my game.
======= Player status ========
HP: 100 / 100
Attack: 10
Defence: 10
Lv: 1. EXP: 0/ 20
==============================
Enter your command:e
Defeat enemy: Enemy. Gain exp: 10. Current exp: 10 / 20. Left hp: 55
Enter your command:e
Defeat enemy: Enemy. Gain exp: 10. Current exp: 20 / 20. Left hp: 10
You upgraded, current level: 2, current hp: 200.
Enter your command:a
Defeat enemy: AdvancedEnemy. Gain exp: 20. Current exp: 20 / 40. Left hp: 20
Enter your command:s
======= Player status ========
HP: 20 / 200
Attack: 20
Defence: 20
Lv: 2. EXP: 20/ 40
==============================
Enter your command:b
You lost. Boss's left hp: 240

3 分析

类的构思

首先需要实现一个基础的人物类Person
然后继承Person实现玩家类Player
之后继承Person实现敌人类:
EnemyAdvancedEnemyBoss

人物类就这些。
最后将游戏的处理也放在一个类Game里去进行。

初步架构

class Person:
    pass

class Player(Person):
    pass

class Enemy(Person):
    pass

class AdvancedEnemy(Enemy):
    pass

class Boss(Enemy):
    pass

class Game:
    pass

4 逐步实现

基础类Person

代码如下

class Person:
    def __init__(self, hp, attack, defence):
        self.hp = hp
        self.attack = attack
        self.defence = defence

    def hit(self, other):
        damage = self.attack - other.defence
        if damage > 0:
            other.hp -= damage

    def is_alive(self):
        return self.hp > 0

玩家类Player

class Player(Person):
    def __init__(self):
        hp, attack, defence = 100, 10, 5
        super().__init__(hp, attack, defence)

        self.lv = 1
        self.base_hp = self.hp  # base_hp: 当前等级总HP, 升级时是这个翻倍
        self.exp = [0, 20]  # 第一个是现有经验,第二个是升级需要的总经验。

    def show_info(self):
        """
        展示玩家信息。
        效果示例如下:
        ======= Player status ========
        HP: 20 / 200
        Attack: 20
        Defence: 20
        Lv: 2. EXP: 20/ 40
        ==============================
        """
        print("{:=^30s}".format(" Player status "))
        print("HP: %s / %s" % (self.hp, self.base_hp))
        print("Attack: %s" % self.attack)
        print("Defence: %s" % self.attack)
        print("Lv: %s. EXP: %s / %s" % (self.lv, self.exp[0], self.exp[1]))
        print("=" * 30)

    def win(self, enemy):
        exp = enemy.drop_exp()
        self.exp[0] += enemy.drop_exp()
        print("Defeat enemy: %s. Gain exp: %s. Current exp: %s / %s. Left hp: %s" %
              (enemy.__class__.__name__, exp, self.exp[0], self.exp[1] ,self.hp))

        if self.exp[0] >= self.exp[1]:
            self.exp[0] -= self.exp[1]  # 升级时扣除升级需要的经验
            self.lv_up()

    def lv_up(self):
        self.exp[1] = self.exp[1] * 2  # 每升一级,升级时需要的经验翻倍
        self.lv += 1

        # 每升一级,三维翻倍
        self.base_hp = self.base_hp * 2
        self.attack = self.attack * 2
        self.defence = self.defence * 2

        # 升级后,恢复满血
        self.hp = self.base_hp
        print("You upgraded, current level: %s, current hp: %s." % (self.lv, self.hp))

    def lose(self, enemy):
        print("You lost. %s's left hp: %s" % (enemy.__class__.__name__, enemy.hp))

其中,有这样一个语法

enemy.__class__.__name__

enemy.__class__: 作用是得到enemy这个对象object的类__class__
class.__name__: 作用是得到一个类class的名字(字符串形式)

使用示例如下

class AAA:
    pass

a = AAA()
print(a.__class__)
print(a.__class__ == AAA)
print(a.__class__.__name__)
print(AAA.__name__)

输出为

<class '__main__.AAA'>
True
AAA
AAA

敌人类

三种敌人代码如下
Enemy

class Enemy(Person):
    def __init__(self, base=1):
        hp, attack, defence = 50 * base, 10 * base, 5 * base
        super().__init__(hp, attack, defence)

        self.exp = 10 * base

    def drop_exp(self):
        return self.exp

AdvancedEnemy

class AdvancedEnemy(Enemy):
    def __init__(self):
        super().__init__(base=2)

    def hit(self, other):
        damage = self.attack
        if damage > 0:
            other.hp -= damage

Boss

class Boss(Enemy):
    def __init__(self):
        super().__init__(base=4)

    def hit(self, other):
        damage = self.attack
        if damage > 0:
            other.hp -= damage
            self.hp += damage

游戏类Game

class Game:
    def __init__(self):
        self.player = Player()

    def run(self):
        print("Welcome to my game.")
        self.player.show_info()
        while True:
            cmd = input("Enter your command:")
            cmd = cmd.lower()
            if cmd == "s":
                self.player.show_info()
            elif cmd == "q":
                print("Bye")
                return
            else:
                self.handle_commands(cmd)

    def handle_commands(self, cmd):
        for c in cmd:
            if c == "e":
                enemy = Enemy()
            elif c == "a":
                enemy = AdvancedEnemy()
            elif c == "b":
                enemy = Boss()
            else:
                print("Invalid Input.")
                return

            self.fight(enemy)

    def fight(self, enemy):
        while True:
            self.player.hit(enemy)
            if not enemy.is_alive():
                self.player.win(enemy)
                return

            enemy.hit(self.player)
            if not self.player.is_alive():
                self.player.lose(enemy)
                exit()

调用

调用起来非常简单

game = Game()
game.run()

4 优化

Game类的handle_commands(self, cmd)方法中,
条件判断有些罗嗦,如果敌人类增加,则又要增加。

有的语言有case语法,能简化这里。
python虽然没有这个语法,但是有办法实现对应效果,甚至更简单。

优化方法如下
先在之前的空白处添加变量enemy_map如下

enemy_map = {
    "e": Enemy,
    "a": AdvancedEnemy,
    "b": Boss,
}

再修改handle_commands(self, cmd)方法如下

def handle_commands(self, cmd):
    for c in cmd:
        if c in enemy_map:
            enemy_class = enemy_map[c]
            enemy = enemy_class()
            self.fight(enemy)
        else:
            print("Invalid Input.")
            return

5 总代码

最后总代码如下

class Person:
    def __init__(self, hp, attack, defence):
        self.hp = hp
        self.attack = attack
        self.defence = defence

    def hit(self, other):
        damage = self.attack - other.defence
        if damage > 0:
            other.hp -= damage

    def is_alive(self):
        return self.hp > 0


class Player(Person):
    def __init__(self):
        hp, attack, defence = 100, 10, 5
        super().__init__(hp, attack, defence)

        self.lv = 1
        self.base_hp = self.hp  # base_hp: 当前等级总HP, 升级时是这个翻倍
        self.exp = [0, 20]  # 第一个是现有经验,第二个是升级需要的总经验。

    def show_info(self):
        """
        展示玩家信息。
        效果示例如下:
        ======= Player status ========
        HP: 20 / 200
        Attack: 20
        Defence: 20
        Lv: 2. EXP: 20/ 40
        ==============================
        """
        print("{:=^30s}".format(" Player status "))
        print("HP: %s / %s" % (self.hp, self.base_hp))
        print("Attack: %s" % self.attack)
        print("Defence: %s" % self.attack)
        print("Lv: %s. EXP: %s / %s" % (self.lv, self.exp[0], self.exp[1]))
        print("=" * 30)

    def win(self, enemy):
        exp = enemy.drop_exp()
        self.exp[0] += enemy.drop_exp()
        print("Defeat enemy: %s. Gain exp: %s. Current exp: %s / %s. Left hp: %s" %
              (enemy.__class__.__name__, exp, self.exp[0], self.exp[1], self.hp))

        if self.exp[0] >= self.exp[1]:
            self.exp[0] -= self.exp[1]  # 升级时扣除升级需要的经验
            self.lv_up()

    def lv_up(self):
        self.exp[1] = self.exp[1] * 2  # 每升一级,升级时需要的经验翻倍
        self.lv += 1

        # 每升一级,三维翻倍
        self.base_hp = self.base_hp * 2
        self.attack = self.attack * 2
        self.defence = self.defence * 2

        # 升级后,恢复满血
        self.hp = self.base_hp
        print("You upgraded, current level: %s, current hp: %s." % (self.lv, self.hp))

    def lose(self, enemy):
        print("You lost. %s's left hp: %s" % (enemy.__class__.__name__, enemy.hp))


class Enemy(Person):
    def __init__(self, base=1):
        hp, attack, defence = 50 * base, 10 * base, 5 * base
        super().__init__(hp, attack, defence)

        self.exp = 10 * base

    def drop_exp(self):
        return self.exp


class AdvancedEnemy(Enemy):
    def __init__(self):
        super().__init__(base=2)

    def hit(self, other):
        damage = self.attack
        if damage > 0:
            other.hp -= damage


class Boss(Enemy):
    def __init__(self):
        super().__init__(base=4)

    def hit(self, other):
        damage = self.attack
        if damage > 0:
            other.hp -= damage
            self.hp += damage


enemy_map = {
    "e": Enemy,
    "a": AdvancedEnemy,
    "b": Boss,
}


class Game:
    def __init__(self):
        self.player = Player()

    def run(self):
        print("Welcome to my game.")
        self.player.show_info()
        while True:
            cmd = input("Enter your command:")
            cmd = cmd.lower()
            if cmd == "s":
                self.player.show_info()
            elif cmd == "e":
                print("Bye")
                return
            else:
                self.handle_commands(cmd)

    def handle_commands(self, cmd):
        for c in cmd:
            if c in enemy_map:
                enemy_class = enemy_map[c]
                enemy = enemy_class()
                self.fight(enemy)
            else:
                print("Invalid Input.")
                return

    def fight(self, enemy):
        while True:
            self.player.hit(enemy)
            if not enemy.is_alive():
                self.player.win(enemy)
                return

            enemy.hit(self.player)
            if not self.player.is_alive():
                self.player.lose(enemy)
                exit()


game = Game()
game.run()
上一篇:CSS: transform-style


下一篇:Dappradar报告:过山车二季度,Polygon超越以太坊