Create rooms into the partitioned space

This commit is contained in:
kleph 2016-03-01 13:03:46 +01:00
parent 1697018d7b
commit ede94004df

211
02_dynamic_bsp_rooms.py Normal file
View file

@ -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()