1 """ Procedural map generation for levels """
12 ' ': {'base': 'floor',
13 'behaviour': ['walk', 'fly'],
19 def __init__(self, coordinates, region):
22 self.coordinates = [coordinates]
24 self.max_connections = 1
30 Check if the room is linked to another room
31 :return: Whether the room has any links or not
33 return len(self.passages) + len(self.tunnels) > 0
35 def add_region(self, coordinates):
37 Add a new region into an existing room
38 :param coordinates: region coordinates to be added to room
41 self.coordinates.append(coordinates)
43 def connect_rooms(self, other_rooms):
44 """ Find the nearest rooms to this room
45 :param other_rooms: list of Rooms objects that we are searching
52 for coord in self.coordinates:
53 for room in other_rooms:
56 for new_coord in room.coordinates:
58 math.sqrt((coord[0] - new_coord[0]) ** 2 +
59 (coord[1] - new_coord[1]) ** 2))
60 other_tile.append(new_coord)
61 this_tile.append(coord)
62 target_rooms.append(room)
64 sorted_indices = [i[0] for i in sorted(enumerate(distance),
66 for index in sorted_indices:
67 if len(self.passages) + len(self.tunnels) >= self.max_connections:
69 if not target_rooms[index].is_linked():
70 self.link_passage(this_tile[index], other_tile[index])
71 target_rooms[index].link_passage(
72 other_tile[index], this_tile[index])
74 def link_passage(self, local_tile, foriegn_tile):
75 """ Link a passage between two rooms
76 :param local_tile: tile in this room to which we wish to link
77 :param foriegn_tile: tile in another room to which we wish to link
80 self.passages.append([local_tile, foriegn_tile])
82 def render_region(self, region, room_dist, region_size, tile_map, x, y):
83 """ Check if a region is in this room and return the required tiles
84 :param region: Region that we wish to render
85 :param room_dist: Tile separation distance from other rooms
86 :param region_size: Region size in tiles
89 if region in self.coordinates:
92 print(self.coordinates)
93 for ht in range(room_dist, region_size - room_dist):
94 for wt in range(room_dist, region_size - room_dist):
95 tile_map[x + ht][y + wt] = ' '
98 # w_dist = self.dist_from_other_rooms
99 # elif self.region_map[h][w-1] == region_selected:
102 # w_dist = self.dist_from_other_rooms
104 # if w + 1 == self.width:
105 # e_dist = self.region_size - self.dist_from_other_rooms
106 # elif self.region_map[h][w+1] == region_selected:
107 # e_dist = self.region_size
109 # e_dist = self.region_size - self.dist_from_other_rooms
112 # n_dist = self.dist_from_other_rooms
113 # elif self.region_map[h-1][w] == region_selected:
116 # n_dist = self.dist_from_other_rooms
118 # if h + 1 == self.height:
119 # s_dist = self.region_size - self.dist_from_other_rooms
120 # elif self.region_map[h+1][w] == region_selected:
121 # s_dist = self.region_size
123 # s_dist = self.region_size - self.dist_from_other_rooms
125 # for wt in range(w_dist, e_dist):
126 # for ht in range(n_dist, s_dist):
127 # self.map[h * self.region_size + ht]\
128 # [w * self.region_size + wt] = ' '
131 class LevelGenerator:
138 dist_from_other_rooms = 0
143 def __init__(self, width, height, no_rooms, dist_from_other_rooms,
145 """ Initialize the level parameters
149 self.no_rooms = no_rooms
150 self.dist_from_other_rooms = dist_from_other_rooms
151 self.region_size = region_size
152 self.region_coordinates = []
155 """ Generate a random level map
157 self.generate_rooms()
158 regions_selected = random.sample(range(self.regions),
159 min(self.regions, self.no_rooms))
160 row = ['#' for x in range(self.width * self.region_size)]
161 self.map = [row[:] for x in range(self.height * self.region_size)]
162 self.map2 = [row[:] for x in range(self.height * self.region_size)]
163 print('Regions: %s' % str(regions_selected))
164 for region in regions_selected:
165 self.rooms[region].connect_rooms(
166 [self.rooms[i] for i in regions_selected])
167 self.generate_tiles(region)
168 region_coordinates_selected = [p for p in self.region_coordinates if
169 p[0] in regions_selected]
170 print('Coords: %s' % str(region_coordinates_selected))
171 for coord in region_coordinates_selected:
173 # self.rooms[coord[0]].render_region(
174 # coord[1], self.dist_from_other_rooms, self.region_size,
175 # self.map2, coord[1][0] * self.region_size,
176 # coord[1][1] * self.region_size)
178 def generate_rooms(self):
179 """ Generate a random level region map
181 row = [0 for x in range(self.width)]
182 self.region_map = [row[:] for x in range(self.height)]
183 for h in range(self.height):
184 for w in range(self.width):
185 random_number = random.randint(0, 2)
186 increment_region = False
188 update_value = self.regions
189 increment_region = True
191 if random_number > 1:
192 update_value = self.region_map[h][w - 1]
194 update_value = self.regions
195 increment_region = True
197 if random_number > 1:
198 update_value = self.region_map[h - 1][w]
200 update_value = self.regions
201 increment_region = True
203 if random_number > 1:
204 update_value = self.region_map[h - 1][w]
205 elif random_number > 0:
206 update_value = self.region_map[h][w - 1]
208 update_value = self.regions
209 increment_region = True
210 self.region_map[h][w] = update_value
212 r = Room([h, w], self.regions)
214 self.region_coordinates.append([update_value, [h, w]])
217 self.rooms[-1].add_region([h, w])
218 self.region_coordinates.append([update_value, [h, w]])
220 def generate_tiles(self, region_selected):
222 :param region_selected:
225 for h in range(self.height):
226 for w in range(self.width):
227 if self.region_map[h][w] == region_selected:
229 w_dist = self.dist_from_other_rooms
230 elif self.region_map[h][w-1] == region_selected:
233 w_dist = self.dist_from_other_rooms
235 if w + 1 == self.width:
236 e_dist = self.region_size - self.dist_from_other_rooms
237 elif self.region_map[h][w+1] == region_selected:
238 e_dist = self.region_size
240 e_dist = self.region_size - self.dist_from_other_rooms
243 n_dist = self.dist_from_other_rooms
244 elif self.region_map[h-1][w] == region_selected:
247 n_dist = self.dist_from_other_rooms
249 if h + 1 == self.height:
250 s_dist = self.region_size - self.dist_from_other_rooms
251 elif self.region_map[h+1][w] == region_selected:
252 s_dist = self.region_size
254 s_dist = self.region_size - self.dist_from_other_rooms
256 for wt in range(w_dist, e_dist):
257 for ht in range(n_dist, s_dist):
258 self.map[h * self.region_size + ht]\
259 [w * self.region_size + wt] = str(region_selected)
262 file = open('map.txt', 'w')
263 print('-----------------')
266 file.write(''.join(l))
268 print('-----------------')
271 file.write(''.join(l))
273 print('-----------------')
275 for l in self.region_map:
285 row.append(ATTRIBUTE_MAP[t])
286 level['tiles'].append(row)
287 name = os.path.join(os.path.dirname(__file__), '..', 'levels', 'map.json')
288 # FIXME: Do a lot better here
289 # Crude hack so the level is written into the levels folder
295 if __name__ == '__main__':
297 level = LevelGenerator(width=4, height=3, no_rooms=4,
298 dist_from_other_rooms=0, region_size=3)
301 input("Press Enter to continue...")