-1

I've found a few versions of this question on the site, but none of the answers quite give me an answer I understand (this question is the closest, but the 'already answered' answer seemed to go off in a different direction).

I'm working my way through the learn python the hard way book and have gotten to the point where I'm trying to build a simple combat system for a game. The good news is that it seems to work when I leave it as a stand alone program. The bad news is that it breaks as soon as I try and add it as a class. I can add the full code if it is helpful, but I think the question is essentially related to code that looks like this:

class Room1(Scene):

    def kick():
        #things happen here

    def start():
        move = raw_input("> ")
        if move == "kick":
            kick()
    start()

This worked fine when it was just a standalone set of defs, but now that I've added classes it throws up a global name error when move == kick. What am I missing?

Thanks in advance, sorry if there is an obvious answer that I'm missing.

Thanks to everyone for the quick responses! It looks like it may be helpful for me to add the entire code. Just to be clear, this is part of a larger game modeled on example 43 from Learn Python the Hard Way. I very much appreciate the suggestions on improving the structure, but my sense right now is that I want to figure out why this doesn't work with the structure I almost understand before moving on to change more things. Of course, I'm more than willing to accept an answer of "what you are trying to do does not fit in the structure you are trying to use."

When I run the code below as part of a larger structure (in the interest of space I won't paste the entire thing, but the game engine structure is linked to above) I get the error I described. I tried adding 'self.start()' or 'Room1.start()' I get errors that name 'self' or name 'Room1' is not defined.

class Room1(Scene):

gothon_power = 500
move_points = 10
damage = 0


def kick(self):
    global gothon_power
    global move_points
    global damage
    damage = randint(10,201)
    gothon_power = gothon_power - damage
    move_points = move_points - 2
    result()

def punch(self):
    global gothon_power
    global move_points
    global damage
    damage = randint(1, 101)
    gothon_power = gothon_power - damage
    move_points = move_points -1
    result()

def result(self):
    if gothon_power > 0 and move_points > 1:
        print "You did %s damage." % damage 
        print "The Gothon is down to %s health points." %                   gothon_power
        print "You are down to %s move points." % move_points
        print "\n"
        print "What's your next move?"
        move = raw_input("> ")
        if move == "kick":
            kick()
        elif move == "punch":
            punch()
        else:
            print "This isn't going to go anywhere unless                       you type 'kick' or 'punch'"
            print "\n"
            result()

    elif gothon_power > 0 and move_points == 1:
        print "You did %s damage." % damage 
        print "The Gothon is down to %s health points." %                   gothon_power
        print "You are down to %s move points." % move_points
        print "\n"
        print "What's your next move? Remember, you only have                   1 move  point."
        move = raw_input("> ")
        if move == "kick":
            print "You don't have enough move points for a                      kick."
            print "\n"
            result()
        elif move == "punch":
            punch()
        else:
            print "This isn't going to go anywhere unless                       you type 'kick' or 'punch'"
            print "\n"
            result()

    elif gothon_power < 1 and move_points > 0:
        print "Congratuations, you killed the Gothon!"
        return 'room2'

    else:
        print "The Gothon still has health but you don't have                   moves."
        print "You know what that means."
        print "\n"
        print "The Gothon killed you."
        return 'death'



def start(self):
    print "It is time to fight the Gothon"
    print "First, let's pause to explain the fighting rules."
    print "\n"
    print "The Gothon has 500 health points."
    print "You have 10 move points."
    print "\n"
    print "Kicks cost 2 move points and do between 10 and 200               points of damage."
    print "Punches cost 1 move opint and do between 1 and 100               points of damage."
    print "\n"
    print "If you get rid of all 500 Gothon health points before                you run out of"
    print "move points you win.  If you run out of move points              before the Gothon"
    print "moves out of health points you lose."
    print "\n"
    print "What's your first move?"

    move = raw_input("> ")

    if move == "kick":
        kick()

    elif move == "punch":
        punch()
    else:
        print "This isn't going to go anywhere unless you type                  'kick' or 'punch'"
        start()
start()
Community
  • 1
  • 1
mweinberg
  • 161
  • 11

3 Answers3

1

A proper set of methods on a class will look like:

class Room1(Scene):

    def kick(self):
        #things happen here

    def start(self):
        move = raw_input("> ")
        if move == "kick":
            self.kick()


Room1().start()

But you might want to rethink your design a little bit. It really doesn't make sense for a Scene to query for input. You'll have to replicate that code in every room in your game.

Think about this kind of top-level driver for a minute:

game = Game()
starting_room = FrontPorch()
game.move_to(starting_room)

while not game.is_over():
    move = raw_input("> ")
    cmd, args = move.split(None, 1)
    game.current_room.do_command(cmd, args)

Then let each room process the commands that it does specially. At the base level Room class, you can implement commands that are common to most rooms, like "GOTO", "LOOK", "WHERE", etc. Then rooms that allow kicking would override do_command and include logic like you have now.

Here is a presentation I gave at PyCon '06 on writing a text adventure. Skip over the parsing stuff, and go to the part where the game/room/items design is described. You don't have to follow this design verbatim, but you might get some ideas about how your objects and classes will interact. Think about that before actually diving in to write a lot of code.

PaulMcG
  • 62,419
  • 16
  • 94
  • 130
0

To call kick() as a method you need to use the self.<method Name> syntax and add self as the first argument to it:

def kick(self):
    #things happen here
    print('kicking')

#call method
self.kick()

or additionally make kick() a static method by calling simply

A.kick()
elegent
  • 3,857
  • 3
  • 23
  • 36
0

You can't execute instance methods of a class, without creating an instance. For example, you could instead write:

class Room1(Scene):

    def kick(self):
        #things happen here

    def start(self):
        move = raw_input("> ")
        if move == "kick":
            self.kick()

room = Room1()
room.start()

However, I don't recommend using a class at all in this case. Classes are meant to give a way to represent your own custom objects with state. For example, you could have a Monster class with attributes damage, name, etc.

For this example that you show, it's probably better to just use a function for Room1.

Eric Zhang
  • 591
  • 6
  • 13