python实现冒险者游戏(文字版,无界面)

1、总体框架

角色扮演、RPG、回合制游戏、文字版、无界面。
说明文档内容附在文末

1.1 实体关系图 E-R图

要组成一个大整体,首先要有各种实体,这在大学里面叫什么分析来着,ER图?反正就是那么个东西,工欲善其事必先利其器,先分析就对了,只有结构清晰了,才能下笔如有神。
在这里插入图片描述

1.2 活动流程图

在这里插入图片描述

2 具体模块:

每个实体写成一个类,这叫封装,面向对象的过程中是一个非常好的习惯。后续添加属性或者方法都很容易定位。

2.1 实体bean类

(1) 冒险者adventurer

E-R图
在这里插入图片描述
代码实现
从ER图可以看到冒险者拥有几种属性:名字name,最大血量maxHP,当前血量hp,是否存活alive,是否眩晕stunned,是否处于格挡状态blocking。
同时,冒险者可以equip装备:武器,盾牌,护甲。
同时,冒险者还具有物品栏。
将这些属性写在init里,需要用户初始化的东西通过传参的形式传递用户需求。无须用户设计的就直接写在代码里面即可,就不用通过传参的方式了,防止过于冗余。

class Adventurer:
    # 名字name,最大血量maxHP,当前血量hp,生存状态alive,格挡blocking,控制stunned,
    def __init__(self, name, weapon, shield, armour, inventory, maxHP=100):
        self.name = name
        self.maxHP = maxHP
        self.hp = maxHP
        self.alive = 'true'
        self.stunned = 'false'
        self.blocking = 'false'

        # 初始化装备
        self.weapon = weapon  # 初始化武器设置
        self.shield = shield
        self.armour = armour
        # 初始化物品栏
        self.inventory = inventory

    # showHero:输出冒险者的面板
    def showHero(self):
        print('名字:', self.name)
        self.showStatus()
        self.showEquipment()
        self.showInventory()

    def isAlive(self):
        if self.hp <= 0:
            self.alive = 'false'
            return "false"
        else:
            self.alive = 'true'
            return "true"

    def showStatus(self):
        print('状态:')
        print('最大生命值:', self.maxHP, 't当前血量:', self.hp, 'talive:', self.alive)
        print('stunned:', self.stunned, 'tblocking:', self.blocking)

    def showEquipment(self):
        print('装备:')
        print(f"weapon:tname={self.weapon.name};tdamage={self.weapon.damage};ttweight={self.weapon.weight};")
        print(
            f"shield:tname={self.shield.name};tarmourRating={self.shield.armourRating};tweight={self.shield.weight};tpercentage={self.shield.percentage}")
        print(f"armour:tname={self.armour.name};tarmourRating={self.armour.armourRating};tweight={self.armour.weight}")

    def showInventory(self):
        print('物品栏:')
        num = len(self.inventory.items)
        if num == 0:
            print("空的。")
        else:
            for i in range(num):
                item = self.inventory.items[i]
                print(f"item{i + 1}:t{item.name}")

    def getWeight(self):
        return self.weapon.weight+self.armour.weight+self.shield.weight

根据后面的需求,我们应该能够展示冒险者的信息,所以构造一个showhero()方法,本来我是写在一起的,但是,后面也有分开展示的需求,如果每次都全部展示就太过于冗余啦,所以我把每个showhero分成三个部分:show状态,show装备,show物品栏。分别通过三个方法实现。
isAlive判断存货状态和getweight计算身上装备的重量。这些都是后来功能需要又添加的,这就体现出来把bean分离出单个文档的好处了,

(2) 背包Inventory

代码实现
原需求的背包是要一个6格的数组放置,但我不喜欢,这样不利于我以后的扩充,且在代码上不美观,感觉不够高级,所以我选择了可变数组作为背包属性。没有设置类或者结构体,直接用两个属性来表示,一个表示空位,一个表示元素。
背包理应具有两个方法:放进去物品,丢掉物品,展示背包栏。
放物品要考虑放满的情况,说明书要求置换,但我觉得先丢后放会更简单,更适合我这种结构。逻辑清晰,看代码就行了。

class Inventory:
    def __init__(self):
        self.empty = 6
        self.items = []

    def getItem(self, item):
        if self.empty == 0:
            print("背包放满了,不能再放了,你需要从以下物品中输入序号(-1表示不替换)替换一件物品:")
            self.showBag()
            while 1:
                i = int(input("想要扔掉物品的序号(-1返回上一级表示你不换了):"))
                if i == "-1":  # 上一级
                    break
                else:
                    ack = input("你确认要换这件物品?(Y or N)")
                    if ack == "Y":
                        self.dropItem(i-1)
                    else:
                        print("已取消更换,请重新选择")
                        continue
        self.items.append(item)
        self.empty -= 1

    def dropItem(self, i):
        self.items.pop(i - 1)
        self.empty += 1

    def showBag(self):
        for i in range(len(self.items)):
            item = self.items[i]
            print(f"item{i + 1}:{item.name}")

(3) 物品Item

代码实现
物品分为两种,药水和装备,一开始对python中的类不熟悉,考虑分开去做,但是最后都是要放在物品栏里面,所以没有好的想法,还是需要是一个类别,所以敲定必须是类,就直接搜了类继承相关的知识,通过继承实现,确实好用。

class Item:
    def __init__(self, name):
        self.name = name

① 药水potion

代码实现
继承物品类item,根据需求,一个名字就够了,通过名字判断功用。

class Potions(Item):
    # 创建药水类
    def __init__(self, name):
        self.name = name

② 装备equipments

武器E-R图
在这里插入图片描述
盾牌E-R图
在这里插入图片描述
护甲E-R图
在这里插入图片描述

继承物品类Item,根据需求,武器有三个属性,盾牌四个属性,护甲三个属性,设置就完事了。

class Equipments(Item):
    # 创建武器类
    class Weapon:
        def __init__(self, name, damage, weight):
            self.name = name
            self.damage = damage
            self.weight = weight

    # 创建盾牌类
    class Shield:
        def __init__(self, name, armourRating, percentage, weight):
            self.name = name
            self.armourRating = armourRating
            self.percentage = percentage
            self.weight = weight

    # 创建盔甲类
    class Armour:
        def __init__(self, name, armourRating, weight):
            self.name = name
            self.armourRating = armourRating
            self.weight = weight

附加文档也提供了一些装备的属性作为参考:

2.2 活动方法

(1) 初始化参数 init

① 初始化物品列表 getItemList()

从附加文档的参考装备中挑选一部分作为系统物品库,放入ItemList列表中存待用。

def getItemsList():
    w1 = Equipments.Weapon('Redsword', 15, 1)
    s1 = Equipments.Shield('Redshield', 10, 1.5, 0.1)
    a1 = Equipments.Armour('Redarmour', 10, 2)

    w2 = Equipments.Weapon('Orangesword', 15, 1)
    s2 = Equipments.Shield('Orangeshield', 15, 2, 0.15)
    a2 = Equipments.Armour('Orangearmour', 15, 2.5)

    w3 = Equipments.Weapon('Yellowsword', 20, 1.5)
    s3 = Equipments.Shield('Yellowshield', 20, 2.5, 0.2)
    a3 = Equipments.Armour('Yellowarmour', 10, 2)

    w4 = Equipments.Weapon('Greensword', 40, 2.5)
    s4 = Equipments.Shield('Greenshield', 30, 3, 0.25)
    a4 = Equipments.Armour('Greenarmour', 30, 3.5)

    w5 = Equipments.Weapon('Cyansword', 50, 3)
    s5 = Equipments.Shield('Cyanshield', 40, 3.5, 0.3)
    a5 = Equipments.Armour('Cyanarmour', 40, 4)

    w6 = Equipments.Weapon('Bluesword', 60, 3.5)
    s6 = Equipments.Shield('Blueshield', 50, 4, 0.35)
    a6 = Equipments.Armour('Bluearmour', 50, 4.5)

    potion1 = Potions("healthPotion")
    potion2 = Potions("damagePotion")
    itemsList = [w1, w2, w3, w4, w5, w6, s1, s2, s3, s4, s5, s6, a1, a2, a3, a4, a5, a6, potion1, potion2]

    return itemsList

② 初始化勇士 Initadventurer()

带着名字就能创建一个勇士,勇士初始装备设置为新手套装,hp你看着改

def initAdventurer(name):
    w1 = Equipments.Weapon('新手刀', 10, 1)
    s1 = Equipments.Shield('新手盾', 2, 0.3, 1)
    a1 = Equipments.Armour('新手甲', 3, 1)
    potion1 = Potions("healthPotion")
    potion2 = Potions("damagePotion")
    myInventory = Inventory()
    myInventory.getItem(potion1)
    myInventory.getItem(potion2)
    adventurer = Adventurer(name, w1, s1, a1, myInventory, 100)
    return adventurer

(2) 战斗过程 battle

① 前三波初始化弱敌 initEnemy()

def initEnemy(enemyNum):
    # 后续可以考虑随机怪兽的装备和初始血量
    enemyName = f"怪物{enemyNum}号"
    w1 = Equipments.Weapon('新手刀', 10, 1)
    s1 = Equipments.Shield('新手盾', 2, 0.3, 1)
    a1 = Equipments.Armour('新手甲', 3, 1)
    enemy = Adventurer(enemyName, w1, s1, a1, Inventory(), 50)
    return enemy

② 随机加强敌人 RandomEnemy()

随机化的,取个随机数从物品库里面随机取就行,和后面奖励机制一样

def randomEnemy(enemyNum):
    enemyName = f"怪物{enemyNum}号"
    wNum = random.randint(0, 5)
    sNum = random.randint(6, 11)
    aNum = random.randint(12, 17)
    randomHP = random.randint(40+6*enemyNum, 80+6*enemyNum)  # 这里用enemyNum系数加成
    enemy = Adventurer(enemyName, itemsList[wNum], itemsList[sNum], itemsList[aNum], Inventory(), randomHP)
    return enemy

③ 判断先手 回合战斗

    if adv.getWeight() <= enemy.getWeight():  # 谁轻谁先手,一样你先手
        while adv.isAlive() == "true" and enemy.isAlive() == "true":  # 都活着就继续干
            enemySub, advAdd, advSub, enemyAdd = 0, 0, 0, 0
            enemySub, advAdd = actions.action(adv, enemy)  # 冒险者打怪兽
            if enemySub == -99 and advAdd == -99:
                return
            advSub, enemyAdd = actions.enemyAction(enemy, adv)  # 怪兽打冒险者
            settleRound(adv, enemy, enemySub, advAdd, advSub, enemyAdd)  # 结算这一回合
    else:
        while adv.isAlive() == "true" and enemy.isAlive() == "true":  # 都活着就继续干
            enemySub, advAdd, advSub, enemyAdd = 0, 0, 0, 0
            advSub, enemyAdd = actions.enemyAction(enemy, adv)  # 怪兽打冒险者
            enemySub, advAdd = actions.action(adv, enemy)  # 冒险者打怪兽
            if enemySub == -99 and advAdd == -99:
                return
            settleRound(adv, enemy, enemySub, advAdd, advSub, enemyAdd)  # 结算这一回合
    if enemy.alive == 'false':
        print("===========================牛批,恭喜你战胜了怪兽===================================================")
        win = 1
a) 勇士行为action
def action(adv, enemy):
    eSub, aAdd = 0, 0
    if adv.stunned == 'true':
        print("你被对面用盾牌格挡眩晕了,将跳过这回合")
        adv.stunned = 'false'
        return eSub, aAdd

    print("你有如下选择:")
    print("1.攻击attack")
    print("2.格挡block")
    print("3.使用物品use an item")
    print("4.逃跑run away")

    while 1:
        choice = input("请输入你的选择:")
        # switch在python3.10的版本之前只能通过字典实现,此处不努力了。
        if choice == "1":
            eSub = attack(adv, enemy)
        elif choice == "2":
            aAdd = defend(adv, enemy)
        elif choice == "3":
            usePotion(adv, enemy)
        elif choice == "4":
            runAway()
            return -99, -99
        else:
            print("输入指令无效,请重新输入:")
            continue
        break

    return eSub, aAdd
攻击attack
def attack(attacker=initAdventurer("无衣"), victim=randomEnemy(0)):
    attacker.blocking = 'false'
    eSub = attacker.weapon.damage - victim.armour.armourRating
    return eSub
格挡defend
def defend(attacker=initAdventurer("无衣"), victim=randomEnemy(0)):
    attacker.blocking = "true"  # 设置为格挡,直到冒险者选择攻击或者使用物品或者冒险者受到伤害。
    aAdd = attacker.shield.armourRating
    # 设置一个自由值(random number)在0到1之间,如果这个值等于盾牌眩晕对手的几率(percentage),设置对手的被控制状态(stunned)为true,对手必须跳过这一回合。
    safePer = random.random()  # 产生随机浮点数,小于等于概率就是晕了
    if safePer <= attacker.shield.percentage:
        print("============格挡成功并眩晕了=========")
        victim.stunned = "true"
    else:
        print("==============格挡失败,不眩晕===========")
        victim.stunned = "false"
    return aAdd
用药usePotion
def usePotion(adv=initAdventurer("无衣"), enemy=randomEnemy(0)):
    adv.blocking = 'false'
    adv.showInventory()
    while 1:
        dex = input("请输入序号选择你要使用的物品(没有药的话用-1后退),战斗状态只能用药品,希望你不要不识好歹:")
        if dex == "-1":  # 没有药就让他重新选择干嘛,不然就死循环了
            action(adv, enemy)
            break
        else:
            dex = int(dex)
            item = adv.inventory.items[dex - 1]
            if "Potion" in item.name:  # 如果是药品,就用
                adv.inventory.items.pop(dex - 1)  # 把物品从背包取出来
                if item.name == "healthPotion":
                    adv.hp += 200
                    if adv.hp > adv.maxHP:
                        adv.hp = adv.maxHP
                if item.name == "damagePotion":
                    enemy.hp -= 50
                    if enemy.hp <= 0:
                        enemy.alive = "false"
                break
            else:
                print("重新选!只能使用药品")
逃跑runAway
def runAway():
    print("不要气馁,再试试能不能抽到较弱的怪兽,实在不行就自杀吧。")
    pass
b) 怪物行为enemyAction

怪物不能用药和逃跑,所以只有攻击和格挡

def enemyAction(enemy, adv):
    aSub, eAdd = 0, 0
    if enemy.stunned == 'true':
        print("怪兽被你用盾牌格挡眩晕了,将跳过这回合")
        enemy.stunned = 'false'
        return aSub, eAdd
    ran = random.randint(1, 2)
    if ran == 1:
        print("=======怪兽选择进攻======")
        aSub = attack(enemy, adv)
    if ran == 2:
        print("=======怪兽选择格挡=====")
        eAdd = defend(enemy, adv)

    return aSub, eAdd

④ 结算回合

a) 结算勇士
    # 结算勇士
    if enemy.blocking == 'false':  # 怪兽不格挡,才会攻击,才需要统计血量
        if adv.blocking == 'true':
            if advSub > advAdd:  # 格挡且对面攻击护甲之后掉的血比盾牌挡的多
                adv.hp = adv.hp - advSub + advAdd
            elif advSub != 0:
                adv.hp -= 1
        else:
            if advSub > 0:
                adv.hp = adv.hp - advSub
            elif advSub != 0:  # 对面攻击没我护甲高,掉1 且怪兽不是格挡
                adv.hp -= 1
    else:  # 怪兽格挡,不用管勇士血量了
        pass
b) 结算怪物
    # 结算怪物
    if adv.blocking == 'false':  # 勇士不格挡,才会攻击,才更新怪兽血量
        if enemy.blocking == 'true':
            if enemySub > enemyAdd:  # 对面攻击护甲之后掉的血比盾牌挡的多
                enemy.hp = enemy.hp - enemySub + enemyAdd
            elif enemySub != 0:  # 对面攻击护甲之后掉的血比盾牌挡的少
                enemy.hp -= 1
        else:
            if enemySub > 0:
                enemy.hp = enemy.hp - enemySub
            elif enemySub != 0:  # 我攻击没对面护甲高,掉1
                enemy.hp -= 1
    else:  # 我格挡了,怪兽无所谓
        pass
c) 展示状态并更新
    # 刷新状态
    adv.showStatus()
    enemy.showStatus()
    adv.blocking = 'false'
    enemy.blocking = 'false'
    if adv.hp <= 0:
        adv.alive = 'false'
    if enemy.hp <= 0:
        enemy.alive = 'false'

(3) 清扫战场与装备管理 InventorManagement

def inventoryManagement(adv, itemsList):
    global enemyNum
    print("===========================即将迎接下一个怪兽,请做好准备===================================================")
    empty0 = adv.inventory.empty
    while 1:
        print("你有如下选择:")
        print("1.挑选胜利奖品pick up items")
        print("2.丢弃物品栏物品drop held items")
        print("3.装备物品栏物品equip held items")
        print("4.继续战斗fight next enemy")
        choice = input("请输入你的胜利选择(-1表示退出):")
        # switch在python3.10的版本之前只能通过字典实现,此处不努力了。
        if choice == "1":
            if win == 1:
                if empty0 - adv.inventory.empty < 3:
                    actions.pickUpItem(adv, itemsList)
                else:
                    print("你已经挑选了三个奖品了,请不要利用漏洞多选哦~")
            else:
                print("n----------------你击败了怪兽吗就想领奖励?逃跑可是没有战利品的------------------n")
        elif choice == "2":
            actions.dropItem(adv)
        elif choice == "3":
            actions.equipItem(adv)
        elif choice == "4":
            enemyNum += 1
            battle(adv)
        elif choice == '-1':
            break
        else:
            print("输入指令无效,请重新输入:")
            continue

① 挑选战利品 pickUpItem()

def pickUpItem(adv, itemsList):
    wNum = random.randint(0, 5)
    sNum = random.randint(6, 11)
    aNum = random.randint(12, 17)
    potionNum = random.randint(18, 19)
    winList = [itemsList[wNum], itemsList[sNum], itemsList[aNum], itemsList[potionNum]]
    # print(winList)
    for i in range(len(winList)):
        item = winList[i]
        print(f"item{i + 1}:{item.name}")
    for i in range(1, 4):
        dex = input("请输入序号选择你要的物品(-1返回上一级表示你不要物品,将直接开始战斗):")
        # =======================有个bug,如果这里选1个2个出去了,其实就可以无限刷装备。=============
        # 已修复:在pickUp的入口处加了个判断
        if dex == "-1":  # 上一级
            break
        elif len(re.findall("d", dex)) == 0:  # 如果不是数字
            print("输入指令无效,请重新输入:")
            continue
        else:
            ack = input("你确认要这件物品?(Y or N):")
            if ack == "Y":
                dex = int(dex)
                item = winList[dex - 1]
                adv.inventory.getItem(item)  # 把物品从背包取出来
                # adv.inventory.showBag()
            else:
                print("已取消捡起,请重新选择")
                continue

② 丢弃物品 DropItem()

def dropItem(adv=initAdventurer(" ")):
    adv.showInventory()
    while 1:
        dex = input("请输入序号选择你要丢弃的物品(-1返回上一级):")
        if dex == "-1":  # 上一级
            break
        else:
            ack = input("你确认要丢这件物品?(Y or N)")
            if ack == "Y":
                dex = int(dex)
                adv.inventory.items.pop(dex - 1)  # 把物品从背包取出来
            else:
                print("已取消丢弃,请重新选择")
                continue

③ 装备物品 equipItem()

def equipItem(adv):
    adv.showInventory()
    while 1:
        dex = input("请输入序号选择你要装备的物品(没有装备的话用-1后退),不能用药品,希望你不要不识好歹:")
        if dex == "-1":  # 退出换装,不然就死循环了
            print("退出换装")
            break
        else:
            dex = int(dex)
            item = adv.inventory.items[dex - 1]
            if "Potion" in item.name:  # 如果是药品
                print("重新选!只能使用装备")
            elif "sword" in item.name:  # 如果是武器
                # adv.inventory.items.pop(dex - 1)  # 把物品从背包取出来
                adv.inventory.dropItem(dex-1)  # 把物品从背包取出来
                adv.inventory.getItem(adv.weapon)  # 把装备放进背包
                adv.weapon = item  # 把取出的装备换上
                adv.showInventory()
                continue
            elif "shield" in item.name:  # 如果是盾
                # adv.inventory.items.pop(dex - 1)  # 把物品从背包取出来
                adv.inventory.dropItem(dex-1)  # 把物品从背包取出来
                adv.inventory.getItem(adv.weapon)  # 把装备放进背包
                adv.shield = item  # 把取出的装备换上
                adv.showInventory()
                continue
            elif "armour" in item.name:  # 如果是护甲
                # adv.inventory.items.pop(dex - 1)  # 把物品从背包取出来
                adv.inventory.dropItem(dex-1)  # 把物品从背包取出来
                adv.inventory.getItem(adv.weapon)  # 把装备放进背包
                adv.armour = item  # 把取出的装备换上
                adv.showInventory()
                continue
            else:
                print("这是bug,可能是我给装备改名字了")

④ 继续战斗 battle()

		elif choice == "4":
            enemyNum += 1
            battle(adv)

战斗结束条件

while adventurer.alive == "true":

3 主程序中main函数流程:

if __name__ == '__main__':
    # test()
    # 初始化一些参数
    enemyNum = 0
    itemsList = getItemsList()

    # 创建勇士
    name = input("欢迎来到冒险岛,请为勇士创建一个名字:")
    adventurer = initAdventurer(name)
    adventurer.showHero()

    print()
    print("欢迎来到新世界,努力打倒敌人变得更强吧,勇士,请踏上你的征程!")
    print("*****************************************************************")
    print()
    while adventurer.alive == "true":
        enemyNum += 1
        battle(adventurer)
        inventoryManagement(adventurer, itemsList)

附加文件

说明文档

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

装备属性

武器: 攻击力 重量
Redsword 15 1
Orangesword 20 1.5
Yellowsword 30 2
Greensword 40 2.5
Cyansword 50 3
Bluesword 60 3.5
Purplesword 70 4
Lightsword 80 4.5
Darksword 90 5
Excalibur 100 1

盾牌: 防御值 重量 眩晕值
Redshield 10 1.5 0.1
Orangeshield 15 2 0.15
Yellowshield 20 2.5 0.2
Greenshield 30 3 0.25
Cyanshield 40 3.5 0.3
Blueshield 50 4 0.35
Purpleshield 60 4.5 0.4
Lightshield 70 5 0.45
Darkshield 80 5.5 0.5
Mirrorshield 90 6 0.6

盔甲: 防御值 重量
Redarmour 10 2
Orangearmour 15 2.5
Yellowarmour 20 3
Greenarmour 30 3.5
Cyanarmour 40 4
Bluearmour 50 4.5
Purplearmour 60 5
Lightarmour 70 5.5
Darkarmour 80 6
Goldenarmour 100 8

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>