# Player & Level class structure in 2D python console game?

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?

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

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.

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