I develop a RogueLike in python, and I try to make my best with OOP and my little knowledge to construct a python course for student.
mapRogue = ['~~~~~~~~~~',
'~~~~.....Y',
'YYYYY+YYYY',
'YYYY....YY']
I want to transform this string map into 2D list containing object defining the nature of my tile in the RogueLike. For that I decide to use a dictionary to map character key and class to instantiate when I read this variable mapRogue
.
I find a solution using inheritance, but imho this code is not really as elegant as i want, and probably not very flexible if I want to add other type of tile behavior later.
DOOR class using inheritance
class Tile(object):
#a tile of the map and its properties
def __init__(self, name, char, position, blocked, color=(255, 255, 255), bgcolor=(0, 0, 0)):
self.name = name
self.blocked = blocked
self.char = char
self.color = color
self.bgcolor = bgcolor
self.position = position
class Door(Tile):
def __init__(self, name, char, position, blocked, bgcolor, key,color=(255, 255, 255), open=False ):
Tile.__init__( self,name, char, position, blocked, color, bgcolor)
self.state = open
self.key = key
def opening(self, key):
if self.key == key:
self.state = True
tilesObject = {".": {"name": 'floor', "obj": Tile, "bgcolor": (233, 207, 177), "block": False},
"Y": {"name": 'forest', "obj": Tile, "bgcolor": (25, 150, 64), "block": True},
"~": {"name": 'water', "obj": Tile, "bgcolor": (10, 21, 35), "block": False},
"+": {"name": 'doors', "obj": Door, "bgcolor": (10, 10, 25), "block": False}}
import types
def load(mymap):
tileMap = []
x, y = (0,0)
for line in mymap:
tileLine = []
for value in line:
try:
tile = tilesObject[value]
except KeyError:
return "Error on key"
if tile["obj"].__name__ == "Door":
obj = tile["obj"](name=tile["name"], position=(x, y), char=value, blocked=tile["block"],bgcolor=tile["bgcolor"], key="42isTheKey", open=False)
else:
obj = tile["obj"](name=tile["name"], position=(x, y), char=value, blocked=tile["block"],bgcolor=tile["bgcolor"])
x += 1
tileLine.append(obj)
x = 0
y += 1
tileMap.append(tileLine)
return tileMap
for line in load(mapRogue):
for obj in line:
print obj , "\n"
DOOR class using composition
I suspect there is an other answer using composition and/or strategy pattern, so i try to decorate the Tile object with Door behavior, but i'm blocked with this dictionnary ...
Actually i try multiple solution without success, do you have a proposition to help me to solve this problem of conception using elegant oop and python ?
class Tile(object):
#a tile of the map and its properties
def __init__(self, name, char, position, blocked, color=(255, 255, 255), bgcolor=(0, 0, 0), door=None):
self.name = name
self.blocked = blocked
self.char = char
self.color = color
self.bgcolor = bgcolor
self.door = door
self.position = position
# Door decorate the Tile object using composition
class Door(object):
def __init__(self, key, open=False):
self.state = open
self.key = key
def opening(self, key):
if self.key == key:
self.state = True
tilesObject = {".": {"name": 'floor', "obj": Tile, "bgcolor": (233, 207, 177), "block": False},
"Y": {"name": 'forest', "obj": Tile, "bgcolor": (25, 150, 64), "block": True},
"~": {"name": 'water', "obj": Tile, "bgcolor": (10, 21, 35), "block": False},
"+": {"name": 'doors', "obj": Door, "bgcolor": (10, 10, 25), "block": False}}
def load(mymap):
tileMap = []
x, y = (0,0)
for line in mymap:
tileLine = []
for value in line:
try:
tile = tilesObject[value]
except KeyError:
return "Error on key"
# Here i need to detect when obj is Door
# because i need to define a special Tile
# decorated by Door behavior,
# so it seems this is not a good solution :/
x += 1
tileLine.append(obj)
x = 0
y += 1
tileMap.append(tileLine)
return tileMap
An update with some informations:
Thanks for answer @User and @Hyperborreus, you're right, I simplify my example here, and in my code, I have two layers:
- the
Tile
which don't move, - and the
GameObjects
which can move, attack, defend, and a lot of other function decorated usingcomposition
like in this tutorial here
Using pygame
, I display all my Tiles
object using a draw_tile()
function.
So at this point I need a link between Door
and Tile
class to compute correctly a fov for player later, because Door
have behavior and limit the vision of my character (with an attributes blocked or fovState). After that, I drawn all gameObject
, on top of these already drawed Tile
surfaces. Door is part of computation only specific to Tile, and other things in roguelike so that explain why I define the Door
like that I hope.
So probably you're right with your proposition of game definition dictionary, I need to change the way i instantiate object, the oop definition of Door / Tiles rest the same, but when I read the initial string map which contain item, door and also static object, I separate gameObject
instantiation and Tile
instantiation..
The idea of dictionary to instantiate element on a rogueLike map defined in string list is based on the idea founded here: https://bitbucket.org/BigYellowCactus/dropout/
Perhaps the creator of this code, @dominic-kexel can also help us to on this point?