0
\$\begingroup\$

I'm trying to create a 2D console game, where I have a player who can freely move around in a level (~map, but map is a reserved keyword) and interfere with other objects. Levels construct out of multiple Blocks, such as player(s), rocks, etc.

Here's the Block class:

class Block(object):
    def __init__(self, x=0, y=0, char=' ', solid=False):
        self.x = x
        self.y = y
        self.char = char
        self.solid = solid

As you see, each block has a position (x, y) and a character to represent the block when it's printed. Each block also has a solid attribute, defining whether it can overlap with other solids or not. (Two solid blocks cannot overlap)

I've now created few subclasses from Block (Rock might be useless for now)

class Rock(Block):
    def __init__(self, x=0, y=0):
        super(Rock, self).__init__(x, y, 'x', True)

class Player(Block):
    def __init__(self, x=0, y=0):
        super(Player, self).__init__(x, y, 'i', True)

    def move_left(self, x=1):
        ... # How do I make sure Player wont overlap with rocks?
        self.x -= x

And here's the Level class:

class Level(object):
    def __init__(self, name='', blocks=None):
        self.name = name
        self.blocks = blocks or []

Only way I can think of is to store a Player instance into Level's attributes (self.player=Player(), or so) and then give Level a method:

def player_move_left(self):
    for block in self.blocks:
        if block.x == self.player.x - 1 and block.solid:
            return False

But this doesn't really make any sense, why have a Player class if it can't even be moved without Level? Imo. player should be moved by a method inside Player.

Am I wrong at something here, if not, how could I implement such behavior?

\$\endgroup\$
  • 2
    \$\begingroup\$ Don't think of classes as "Objects", think of them as "Bundled Functionality." \$\endgroup\$ – API-Beast Mar 14 '14 at 14:22
1
\$\begingroup\$

You have different options:

Option 1: Not making a Player class

You keep a level attribute: self.player = Block(). Then you don't have to worry for having an extra class. But in the future you might want to add extra methods/attributes to player, so perhaps it isn't the best option.

Option 2: Player receives blocks

def player_move_left(self):
    self.player.move_left(self.blocks)

# Then implement the movement in the player class

Option 3: Player receives the whole level

Player doesn't need to be an attribute of your level if you keep player as a global, ie:

player.move_left(level)

class Player(Block):
    ...

    def move_left(self, level):
        for block in level.blocks:
            if block.x == self.player.x - 1 and block.solid:
                return False

Even better, level could have a can_move method:

    def move_left(self, level):
        if level.can_move(self.player.x - 1):
            self.player.x -= 1
            return true
        else:
            return false
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.