Python: Pokemon battle (classes, functions)

2019-04-12 22:02发布

问题:

I just started learning python and I am hoping you guys can help me comprehend things a little better. If you have ever played a pokemon game for the gameboy you'll understand more as to what I am trying to do. I started off with a text adventure where you do simple stuff, but now I am at the point of pokemon battling eachother. So this is what I am trying to achieve.

  • Pokemon battle starts
  • You attack target
  • Target loses HP and attacks back
  • First one to 0 hp loses

Of course all of this is printed out.

This is what I have for the battle so far, I am not sure how accurate I am right now. Just really looking to see how close I am to doing this correctly.

class Pokemon(object):  
    sName = "pidgy"
    nAttack = 5
    nHealth = 10
    nEvasion = 1


    def __init__(self, name, atk, hp, evd):
        self.sName = name
        self.nAttack = atk
        self.nHealth = hp
        self.nEvasion = evd


    def fight(target, self):
        target.nHealth - self.nAttack



def battle():
    print "A wild  appeared" 
    #pikachu = Pokemon("Pikafaggot", 18, 80, 21)
    pidgy = Pokemon("Pidgy", 18, 80, 21)
    pidgy.fight(pikachu)
    #pikachu.fight(pidgy)   

Full code here: http://pastebin.com/ikmRuE5z

I am also looking for advice on how to manage variables; I seem to be having a grocery list of variables at the top and I assume that is not good practice, where should they go?

回答1:

If I was to have fight as a instance method (which I'm not sure I would), I would probably code it up something like this:

class Pokemon(object):
    def __init__(self,name,hp,damage):
        self.name = name     #pokemon name
        self.hp = hp         #hit-points of this particular pokemon
        self.damage = damage #amount of damage this pokemon does every attack

    def fight(self,other):
        if(self.hp > 0):
            print("%s did %d damage to %s"%(self.name,self.damage,other.name))
            print("%s has %d hp left"%(other.name,other.hp))

            other.hp -= self.damage
            return other.fight(self)  #Now the other pokemon fights back!
        else:
            print("%s wins! (%d hp left)"%(other.name,other.hp))
            return other,self  #return a tuple (winner,loser)

pikachu=Pokemon('pikachu', 100, 10)
pidgy=Pokemon('pidgy', 200, 12)
winner,loser = pidgy.fight(pikachu)

Of course, this is somewhat boring since the amount of damage does not depend on type of pokemon and isn't randomized in any way ... but hopefully it illustrates the point.

As for your class structure:

class Foo(object):
    attr1=1
    attr2=2
    def __init__(self,attr1,attr2):
        self.attr1 = attr1
        self.attr2 = attr2

It doesn't really make sense (to me) to declare the class attributes if you're guaranteed to overwrite them in __init__. Just use instance attributes and you should be fine (i.e.):

class Foo(object):
    def __init__(self,attr1,attr2):
        self.attr1 = attr1
        self.attr2 = attr2v


回答2:

  1. You don't need the variables up the top. You just need them in the init() method.
  2. The fight method should return a value:

    def fight(self, target): 
        target.nHealth -= self.nAttack
        return target
    
  3. You probably want to also check if someone has lost the battle:

    def checkWin(myPoke, target):
        # Return 1 if myPoke wins, 0 if target wins, -1 if no winner yet.
        winner = -1
        if myPoke.nHealth == 0:
            winner = 0
        elif target.nHealth == 0:
            winner = 1
        return winner
    

Hope I helped.



回答3:

I am only going to comment on a few obvious aspects, because a complete code review is beyond the scope of this site (try codereview.stackexchange.com)

Your fight() method isn't saving the results of the subtraction, so nothing is changed. You would need to do something like this:

def fight(target, self):
    target.nHealth -= self.nAttack
    # check if target is dead now?

I might even recommend not imposing a modification on your target directly. It may be better if you can call an attack(power) on your target, and let it determine how much damage is done. You can then check if the target is dead yet. Ultimately I would think you would have some "dice" object that would determine the outcomes for you.

As for globals... just stop using them. It is a bad habit to have them unless you really have a good reason. Have functions that return results to the caller, which you then make use of:

def func(foo):
    return 'bar'

You can however have a module of constants. These are a bunch of values that don't change for the life of the application. They are merely variables that provide common values. You might create a constants.py and have stuff like:

UP = "up"
DOWN = "down"
DEAD = 0
...

... And in your other modules you do:

from constants import *