From ede94004df1cd18f48dd4c11f23077f32abf43ab Mon Sep 17 00:00:00 2001 From: kleph Date: Tue, 1 Mar 2016 13:03:46 +0100 Subject: [PATCH] Create rooms into the partitioned space --- 02_dynamic_bsp_rooms.py | 211 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 02_dynamic_bsp_rooms.py diff --git a/02_dynamic_bsp_rooms.py b/02_dynamic_bsp_rooms.py new file mode 100644 index 0000000..a75fdb7 --- /dev/null +++ b/02_dynamic_bsp_rooms.py @@ -0,0 +1,211 @@ +import pyglet +from pyglet.window import key + +import sys +import re + +import random + +# constants +TILE_SIZE_X = 16 +TILE_SIZE_Y = 16 + +MIN_LEAF_SIZE = 7 + +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 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-1, self.y, self.width - split_point+1, 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-1, self.width, self.height - split_point+1, self.id+2) + + return True + + def generate_rooms(self): + """ + :return: generate rooms inside partitioned space + """ + if self.left_leaf: + self.left_leaf.generate_rooms() + if self.right_leaf: + self.right_leaf.generate_rooms() + if not self.left_leaf and not self.right_leaf: + self.room = self.generate_room() + + def generate_room(self): + x = random.randint(self.x+1, self.x+2) + y = random.randint(self.y+1, self.y+2) + w = random.randint(3, self.width-1) + h = random.randint(3, self.height-1) + return Room(x, y, w, h, self.id) + + 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 generate_tree(): + # init tree + tree = [Leaf(0, 0, 30, 30, 0)] + #tree = [Leaf(0, 0, 10, 10, 0)] + #tree = [Leaf(0, 0, 5, 5, 0)] + + # split leaves until none succeed + split_done = True + while split_done: + split_done = False + for l in tree: + if l.left_leaf == None and l.right_leaf == None: + if (l.split()): + tree.append(l.left_leaf) + tree.append(l.right_leaf) + split_done = True + + # create rooms from partitions + tree[0].generate_rooms() + + return tree + + +## +# main +## + +# main window +window = pyglet.window.Window() + +@window.event +def on_key_press(symbol, modifiers): + #TODO: ugly hack + global level_tree + + if symbol == key.Q: + print('Will quit') + if symbol == key.R: + print('Regeneration') + level_tree = generate_tree() + window.invalid = True + elif symbol == key.LEFT: + print('Left arrow') + elif symbol == key.ENTER: + print('Enter !') + +@window.event +def on_draw(): + window.clear() + draw_tree(level_tree) + + label.draw() + +def draw_tree(t): + """ + :param t: each leave of t will be draw() + """ + for l in t: + # draw only last leaves + if l.left_leaf == None and l.right_leaf == None: + l.draw(tiles[TILE_ROAD]) + for l in t: + # draw only last leaves + if l.left_leaf == None and l.right_leaf == None: + if l.room: + l.room.draw(tiles[TILE_WALL], tiles[TILE_GROUND]) + + +# init random +#TODO add seed mode (how ?) +random.seed() + +label = pyglet.text.Label('Plop World', x = window.width*5/6, y = window.height*5/6, anchor_x='center', anchor_y='center') + +# load images +tiles = [] +resource_file = open('tiles.txt') +line = resource_file.readline().strip() +while line: + tile_file = re.compile('\d: ').split(line)[1] + print('loading tile: ' + str(tile_file)) + tiles.append(pyglet.resource.image(tile_file)) + line = resource_file.readline().strip() + +TILE_WALL = 0 +TILE_ROAD = 1 +TILE_GROUND = 2 + +level_tree = generate_tree() + +# artificial tree to test drawing +# troot = Leaf(0, 0, 24, 24, 0) +# tll = Leaf(0, 0, 16, 24, 1) +# trl = Leaf(16, 0, 8, 24, 2) +# troot.left_leaf = tll +# troot.right_leaf = trl +# tllvl = Leaf(0, 0, 16, 4, 3) +# tllvr = Leaf(0, 4, 16, 20, 4) +# level_tree = [troot, tll, trl, tllvl, tllvr] + +pyglet.app.run()