diff --git a/03_map.py b/03_map.py new file mode 100644 index 0000000..481ba64 --- /dev/null +++ b/03_map.py @@ -0,0 +1,248 @@ +import pyglet +from pyglet.window import key + +import re + +import sys +import random + +# constants +TILE_SIZE_X = 16 +TILE_SIZE_Y = 16 + +MIN_LEAF_SIZE = 8 + + +class Leaf: + """ Leaf of the BSP """ + + def __init__(self, x, y, w, h, id): + self.id = id + self.x = x + self.y = y + self.width = w + self.height = h + self.left_leaf = None + self.right_leaf = None + self.room = None + + def print_leaf(self): + print('[Leaf]' + str(self.id) + ': (' + str(self.x) + '), (' + str(self.y) + ')' + + ' - ' + str(self.width) + 'x' + str(self.height)) + + def is_terminal(self): + """ Returns True if the leave has no children """ + if self.left_leave or self.right_leave: + return False + return True + + def split(self): + """ + :return: True if the leaf has been split + """ + + # self.print_leaf() + # choose direction + # TODO: if leaf is not so square, split along the long side + # if width > XX% height (25, 33 ?) -> split vertical + if random.random() < 0.5: + # x + if self.width < MIN_LEAF_SIZE * 2: # leaf is too small + return False + split_point = random.randint(MIN_LEAF_SIZE, self.width - MIN_LEAF_SIZE) + self.left_leaf = Leaf(self.x, self.y, split_point, self.height, self.id+1) + self.right_leaf = Leaf(self.x + split_point, self.y, self.width - split_point, self.height, self.id+2) + + else: + # y + if self.height < MIN_LEAF_SIZE * 2: # leaf is too small + return False + split_point = random.randint(MIN_LEAF_SIZE, self.height - MIN_LEAF_SIZE) + self.left_leaf = Leaf(self.x, self.y, self.width, split_point, self.id+1) + self.right_leaf = Leaf(self.x, self.y + split_point, self.width, self.height - split_point, self.id+2) + + return True + + def generate_rooms(self, tilemap): + """ + :return: generate rooms inside partitioned space + """ + if self.left_leaf: + self.left_leaf.generate_rooms(tilemap) + if self.right_leaf: + self.right_leaf.generate_rooms(tilemap) + if not self.left_leaf and not self.right_leaf: + self.room = self.generate_room(tilemap) + + def generate_room(self, tilemap): + # Leave space for walls + x = random.randint(self.x+1, self.x+2) + y = random.randint(self.y+1, self.y+2) + w = random.randint(MIN_LEAF_SIZE / 2, self.width-2) + h = random.randint(MIN_LEAF_SIZE / 2, self.height-2) + + r = Room(x, y, w, h, self.id) + r.draw_map(tilemap) + + return r + + def draw(self, ground): + for y in range(0, self.height): + for x in range(0, self.width): + ground.blit((self.x + x)*TILE_SIZE_X, (self.y+y)*TILE_SIZE_Y) + + +class Room: + """ room """ + + def __init__(self, x, y, w, h, id): + self.x = x + self.y = y + self.width = w + self.height = h + self.id = id + self.print_room() + + def print_room(self): + print('[room]' + str(self.id) + ': (' + str(self.x) + '), (' + str(self.y) + ')' + + ' - ' + str(self.width) + 'x' + str(self.height)) + + def draw(self, wall, ground): + # first wall + for x in range(0, self.width): + wall.blit((self.x+x)*TILE_SIZE_X, self.y*TILE_SIZE_Y) + # middle + for y in range(1, self.height-1): + wall.blit(self.x*TILE_SIZE_X, (self.y+y)*TILE_SIZE_Y) + for x in range(1, self.width - 1): + ground.blit((self.x + x)*TILE_SIZE_X, (self.y+y)*TILE_SIZE_Y) + wall.blit((self.x+self.width-1)*TILE_SIZE_X, (self.y+y)*TILE_SIZE_Y) + # end + for x in range(0, self.width): + wall.blit((self.x+x)*TILE_SIZE_X, (self.y + self.height-1)*TILE_SIZE_Y) + + def draw_map(self, tilemap): + # first wall + for x in range(0, self.width): + tilemap[self.x + x][self.y] = Level.TILE_WALL + # middle + for y in range(1, self.height - 1): + tilemap[self.x][self.y + y] = Level.TILE_WALL + for x in range(1, self.width - 1): + tilemap[self.x + x][self.y + y] = Level.TILE_GROUND + tilemap[self.x ++ self.width - 1][self.y + y] = Level.TILE_WALL + # end + for x in range(0, self.width): + tilemap[self.x + x][self.y + self.height - 1] = Level.TILE_WALL + + + +class Level: + TILE_WALL = 0 + TILE_ROAD = 1 + TILE_GROUND = 2 + + def __init__(self, sizex, sizey, tile_file=None): + self.sizex, self.sizey = sizex, sizey + self.tileset = [] + self.tilemap = [[self.TILE_ROAD for y in range(0, sizey)] for x in range(0, sizex)] + if tile_file: + self.load_tileset(tile_file) + self.generate_tree() + + def load_tileset(self, tile_file): + resource_file = open(tile_file) + line = resource_file.readline().strip() + while line: + image_file = re.compile('\d: ').split(line)[1] + print('loading tile: ' + str(image_file)) + self.tileset.append(pyglet.resource.image(image_file)) + line = resource_file.readline().strip() + resource_file.close() + + def generate_tree(self): + # init tree + self.tree = [Leaf(0, 0, 30, 30, 0)] + + # split leaves until none succeed + # Lists are ordered. Tree will be created and travel from left to right + for l in self.tree: + if l.split(): + self.tree.append(l.left_leaf) + self.tree.append(l.right_leaf) + + # create rooms from partitions + self.tree[0].generate_rooms(self.tilemap) + + def draw_map(self): + for y in range(0, self.sizey): + for x in range(0, self.sizex): + self.tileset[self.tilemap[x][y]].blit(x*TILE_SIZE_X, y*TILE_SIZE_Y) + + def draw_tree(self): + """ + :param t: each leave of t will be draw() + """ + for l in self.tree: + # draw only last leaves + if not l.left_leaf and not l.right_leaf: + l.draw(self.tileset[self.TILE_ROAD]) + for l in self.tree: + # draw only last leaves + if not l.left_leaf and not l.right_leaf: + if l.room: + l.room.draw(self.tileset[self.TILE_WALL], self.tileset[self.TILE_GROUND]) + + def dump_tilemap(self): + for y in range(0, self.sizey): + for x in range(0, self.sizex): + print(self.tilemap[x][y], end="") + print("") + +## +# main +## + +# main window +window = pyglet.window.Window() + + +@window.event +def on_key_press(symbol, modifiers): + # TODO: ugly hack + global level + + if symbol == key.Q: + print('Will quit') + if symbol == key.R: + print('Regeneration') + level.generate_tree() + window.invalid = True + if symbol == key.D: + level.dump_tilemap() + elif symbol == key.LEFT: + print('Left arrow') + elif symbol == key.ENTER: + print('Enter !') + + +@window.event +def on_draw(): + window.clear() + level.draw_tree() + + label.draw() + + +# init random +seed = random.randint(0, sys.maxsize) +print("Using seed: " + str(seed)) +random.seed(seed) + +label_txt = 'Plop World seed: ' + str(seed) +label = pyglet.text.Label(label_txt, x=window.width*5/6, y=window.height*5/6, anchor_x='center', anchor_y='center', + multiline=True, width=window.width - window.width*5/6) + +level = Level(30, 30, 'tiles.txt') + +pyglet.app.run()