Python - 视频游戏的战斗系统

时间:2016-07-08 11:49:43

标签: python-3.x tkinter

我正在创建一个允许用户在回合制系统中对抗敌人的系统,但是在三周之后,我遇到了一系列问题。在遇到这个新问题时,我担心自己会变得更糟,而不是更好,所以我会感激任何帮助。

该计划应该:

  • 允许用户点击轮到他们中的四个操作按钮之一
  • 如果采取行动,他们的转弯结束,敌人轮到他们,但只有在没有死的情况下
  • 根据输入参数
  • 中的敌人,在开始时设置健康状况

战斗代码

from tkinter import * #needs for GUI
import random #needed for randomisation of options

def YNquestion(questionString): #putting the code necessary for the GUI into a function allows it to be called every time the quesiton is asked
    global answer #allows the vaiable to be used anywhere in the program 
    def yes_command(): #called by the GUI to change the variable when the button is clicked
        answer.set('yes') #.set allows this to exit the GUI as it is a gloabal variable
        window.destroy() #closes the GUI window so the program does no become stuck
    def no_command(): #similar to the procedure above but sets the variable to 'no'
        answer.set('no')
        window.destroy()

    window = Tk() #creates GUI window 

    yes_no_label = Label(window, text=questionString) #sets the label text within this GUI specified as 'window', set to the string specified when called so this can be used in multiple ways such as in tic tac toe or setting gender of character
    yes_no_label.grid(row=0, column=1) #sets a place for the label to be displayed on the GUI

    answer=StringVar() #needed when running Tkinter with multiple Tk instances to allow variable to be used outside of program (value cannot be assigned within tkinter). 

    YESbutton = Button(window, text="Yes", fg='green', command = lambda :yes_command()) #sets the button with test and colour deatils, as well as what happens when pressed. 
    YESbutton.grid(row=1, column=0) #sets button location
    NObutton = Button(window, text = 'No', fg = 'red', command= lambda :no_command()) #same as for button above
    NObutton.grid(row=1, column=2)

    window.mainloop() #required to create the GUI which is essentially an infinite loop waiting for changes (button press)

#where the fighting code starts

global health#needs to be used anywhere
global energy
global armor
health = 20#stats altered through fight
energy = 10
weapon = 'Rusty Old Sword' 
necklace = "Mother's Pendant" #used to assign damage done by user during their turn
boots = 'Well Worn Boots'#used to assign chance to dodge for user
armor = 1
inventory = ["Water(+5 energy)", "Meat(+6 health)"] #items that can be used, to be deleted from or appended to



#section that creates the function that can be called to bring up the fight GUI!!!!!!!!!!!!!!!!!!!!!!
def fight(enemy):

    #section that decides what enemy is being fought and therefore their health and flavour text
    def endTurn():#finishes the user's turn
        fightWindow.destroy()#closes the GUI used to fight
        #turn.set(False)#ends the turn so the enemy can attack

    def enemies(enemy):#used at beginning of fight to decide ow much health the enemy has
        if enemy == 'goblin':#the enemy will be defined in the beginning so the amount of damage needed to win can be determined
            global eHealth
            eHealth = 10

    def eAtt(enemy, health):#called when it is the enemy's turn
        if enemy == 'goblin':#used to calculate possible damage output and flavour text when attacking
            gFlavTxt = random.choice(["It attacks wildly!", "It attacks without skill!", "It aims it's weapon nervously!"])#flavour text chosen randomly
            print(gFlavTxt)#flavour text outputted
            health = health - (3 - armor)#takes away a certain amount of health, with this lessoned by the amount of armour the user has
            print ('You have '+str(health)+' health left!')
        #turn = True

    #section that decides how much damage is beign done by a regular attack    
    def attPwr(weapon):#branches to test how much damage should be done each turn
        if weapon == 'Rusty Old Sword':
            global damage
            damage = 5

    def att(health, enemy, eHealth): #command assigned to GUI button
        endTurn()
        attPwr(weapon)
        eHealth -= damage#stats reassigned so fight can end and user can win
        print ('It has '+str(eHealth)+' health left!')#user info
        if eHealth > 0: #only outputs if not defeated
            if enemy == 'goblin': #will output different text depending on enemy
                gFlavTxt = random.choice(["It screams wildly!", "It recoils in fear!", "It fails to defend!"])
                print(gFlavTxt)
        turn.set(eHealth)

    #section that decides how much damage is done my a magic attack
    def magPwr(necklace):#branches to test how much damage should be done each turn
        if necklace == "Mother's Pendant":
            global damage
            damage = 10

    def mag(health, enemy, eHealth): 
        endTurn()
        magPwr(necklace) #decides how much damage should be done when the attack is used
        eHealth -= damage#re-assigns value so user can win
        print ('It has '+str(eHealth)+' health left!')#user info
        if eHealth > 0:    
            if enemy == 'goblin': 
                gFlavTxt = random.choice(["It screams wildly!", "It recoils in fear!", "It fails to defend!"])
                print(gFlavTxt)
        return (eHealth)

    #inventory system
    def checkHealth(health):#validates stats to make sure the user canot go above maximum health
        if health > 20:
            health = 20
            return health
    def checkEnergy(energy):    
        if energy > 10:
            energy = 10
            return energy
    def inv(health, energy):
        def close():
            window.destroy()
        def water(): #called by the GUI to use the item when the button is clicked
            itemText.set('5 energy has been restored!') #allows this to exit the GUI as it is a global variable
            window.destroy() #closes the GUI window so the program does not become stuck
            turn.set('False')#used to end the turn so the fight can continue
        def meat(): 
            itemText.set('6 health has been restored!')
            window.destroy()
            turn.set('False')

        window = Tk() #creates GUI window 

        itemText=StringVar() #allows variable to be used outside of program (value cannot be assigned within tkinter). 
        turn=StringVar()

        invLabel = Label(window, text='Choose an item from your inventory!')
        invLabel.grid(row=1, column=1) #sets a place for the label to be displayed on the GUI

        closeButton = Button(window, text='Back', fg = 'red', command = lambda :close())#ends if the user does not want to use an item
        closeButton.grid(row=2, column=1) #sets button location
        for i in range(0,len(inventory)): #each item is checked to see if it is in the inventory   
            if inventory[i] == "Water(+5 energy)":#if it is in the inventory then the branch is chosen
                waterButton = Button(window, text= inventory[i], command = lambda :water()) #the button will be displayed with the command to use the item
                waterButton.grid(row=3, column=0) 
            if inventory[i] == "Meat(+6 health)":
                meatButton = Button(window, text = inventory[i], command = lambda :meat()) 
                meatButton.grid(row=4, column=0)

        window.mainloop() #required to create the GUI which is essentially an infinite loop waiting for changes (button press)
        itemChoice = itemText.get()
        turn = turn.get()#fetches the choices and assigns them so they can be used to branch below and end the user's turn
        if itemChoice == '5 energy has been restored!':#gives a different output depending on the item used
            energy += 5#such as by assigning a stat  
            energy = checkEnergy(energy) #makes sure that the user does not do over their limit of stats eg max 20 health
            inventory.remove("Water(+5 energy)") #removes the item from the inventory list so it does not appear again
            print ('You now have '+ str(energy)+' energy!')#gives user information
        elif itemChoice == '6 health has been restored!':
            health += 6
            health = checkHealth(health)
            inventory.remove("Meat(+6 health)")
            print ('You now have '+ str(health) +' health!')
        #turn = turn.get()#fetches the choices and assigns them so they can be used to branch below and end the user's turn
        #if turn == False:
        endTurn()

    #section that decides if the user can run from a fight
    def dodgeChance(boots):
        if boots == 'Well Worn Boots':
            global dodge
            dodge = random.choice(['y','y','y','n','n','n','n','n','n','n']) #this gives a 3/10 chance because there are 3 y and 7 n and if it is y then it is successful

    def flee(enemy, boots):
        if boots == 'Well Worn Boots':
            print('You have a 30% chance to escape.')
        if enemy != 'gBoss':#only works if the fight can be run from (not boss fights)
            YNquestion('Would you still like to try to flee?') #calls GUI which sets variable and asks for label text as arguement
            choice = answer.get() #as answer.get() must be used as it is '.set()', then assigned to a variable which is easier to use eg in selection 
            if choice == 'yes': 
                print("You try to run!")#user info
                dodgeChance(boots)#redoes the chance to dodge again
                if dodge == 'y':#if successful
                    print ('You escape successfully!')
                    fightWindow.destroy#the fight ends
                else:
                    print ('You cannot get away!')#user information if fails
                endTurn()
                #turn = turn.get()
        else:
            print("You can't run now! This is too important!")#user information if too important



    enemies(enemy)#sets the health of the enemy
    #turn = True#sets loops condition
    while eHealth > 0:#continues fighting if enemy is alive
        #while turn == True:#allows users to make their decision 
        fightWindow = Tk()

        turn = StringVar()

        fightLabel = Label(fightWindow, text='Pick an action for this turn!') #sets the label text within this GUI specified as 'fightWindow'
        fightLabel.grid(row=0, column=2) #sets a place for the label to be displayed on the GUI

        attButton = Button(fightWindow, text= 'Attack', command = lambda :att(health, enemy, eHealth)) #the button will be displayed with the command to attack
        attButton.grid(row=1, column=0)

        magButton = Button(fightWindow, text= 'Magic', command = lambda :mag(health, enemy, eHealth)) #the button will be displayed with the command to use magic
        magButton.grid(row=1, column=1)

        invButton = Button(fightWindow, text= 'Inventory', command = lambda :inv(health, energy)) #the button will be displayed with the command to use the item
        invButton.grid(row=1, column=3)

        fleButton = Button(fightWindow, text= 'Flee', command = lambda :flee(enemy, boots)) #the button will be displayed with the command to end the fight
        fleButton.grid(row=1, column=4)

        fightWindow.mainloop()

        eHealth = turn.get()    

        eAtt(enemy, health)

    else:
        print('You defeated the enemy!')

fight('goblin') 

这个当前代码在赋值之前提出了变量引用的新问题,即使不是这种情况。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

def enemies(enemy)
    if enemy == 'goblin':
        global eHealth
        eHealth = 10
        return eHealth

eHealth = enemies(enemy)

进行了这些更改并且有效。看起来代码还有其他一些问题。但是应该解决已发布的问题