03 - init - Add internal map representation and basis for level handling
This commit is contained in:
		
							parent
							
								
									1539bcc057
								
							
						
					
					
						commit
						1befb38cb1
					
				
					 1 changed files with 248 additions and 0 deletions
				
			
		
							
								
								
									
										248
									
								
								03_map.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								03_map.py
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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()
 | 
				
			||||||
		Loading…
	
		Reference in a new issue