Actually generate a map, completing part 3
This commit is contained in:
parent
56267fe8a7
commit
3506edd85f
15
main.py
15
main.py
@ -12,7 +12,11 @@ def main() -> None:
|
||||
screen_height = 50
|
||||
|
||||
map_width = 80
|
||||
map_height = 50
|
||||
map_height = 45
|
||||
|
||||
room_max_size = 10
|
||||
room_min_size = 6
|
||||
max_rooms = 30
|
||||
|
||||
tileset = tcod.tileset.load_tilesheet(
|
||||
"dejavu10x10_gs_tc.png",
|
||||
@ -27,7 +31,14 @@ def main() -> None:
|
||||
npc = Entity(int(screen_width / 2 - 5), int(screen_height / 2), "@", (255, 255, 0))
|
||||
entities = {npc, player}
|
||||
|
||||
game_map = generate_dungeon(map_width, map_height)
|
||||
game_map = generate_dungeon(
|
||||
max_rooms,
|
||||
room_min_size,
|
||||
room_max_size,
|
||||
map_width,
|
||||
map_height,
|
||||
player,
|
||||
)
|
||||
|
||||
engine = Engine(entities, event_handler, game_map, player)
|
||||
|
||||
|
81
procgen.py
81
procgen.py
@ -1,8 +1,16 @@
|
||||
from typing import Tuple
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from typing import Iterator, List, Tuple, TYPE_CHECKING
|
||||
|
||||
import tcod
|
||||
|
||||
from game_map import GameMap
|
||||
import tile_types
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from entity import Entity
|
||||
|
||||
|
||||
class RectangularRoom:
|
||||
def __init__(self, x: int, y: int, width: int, height: int):
|
||||
@ -23,14 +31,75 @@ class RectangularRoom:
|
||||
"""Return the inner area of this room as a 2D array index."""
|
||||
return slice(self.x1 + 1, self.x2), slice(self.y1 + 1, self.y2)
|
||||
|
||||
def intersects(self, other: RectangularRoom) -> bool:
|
||||
"""Return True if this room overlaps with another RectangularRoom."""
|
||||
return (
|
||||
self.x1 <= other.x2
|
||||
and self.x2 >= other.x1
|
||||
and self.y1 <= other.y2
|
||||
and self.y2 >= other.y1
|
||||
)
|
||||
|
||||
def generate_dungeon(map_width, map_height) -> GameMap:
|
||||
|
||||
def tunnel_between(start: Tuple[int, int], end: Tuple[int, int]) -> Iterator[Tuple[int, int]]:
|
||||
"""Return an L-shaped tunnel between these two points."""
|
||||
x1, y1 = start
|
||||
x2, y2 = end
|
||||
if random.random() < 0.5: # 50% chance.
|
||||
# Move horizontally, then vertically
|
||||
corner_x, corner_y = x2, y1
|
||||
else:
|
||||
# Move vertically, then horizontally
|
||||
corner_x, corner_y = x1, y2
|
||||
|
||||
# Generate the coordinates for this tunnel
|
||||
for x, y in tcod.los.bresenham((x1, y1), (corner_x, corner_y)).tolist():
|
||||
yield x, y
|
||||
|
||||
for x, y in tcod.los.bresenham((corner_x, corner_y), (x2, y2)).tolist():
|
||||
yield x, y
|
||||
|
||||
|
||||
def generate_dungeon(
|
||||
max_rooms: int,
|
||||
room_min_size: int,
|
||||
room_max_size: int,
|
||||
map_width: int,
|
||||
map_height: int,
|
||||
player: Entity,
|
||||
) -> GameMap:
|
||||
"""Generate a new dungeon map."""
|
||||
dungeon = GameMap(map_width, map_height)
|
||||
|
||||
room_1 = RectangularRoom(x=20, y=15, width=10, height=15)
|
||||
room_2 = RectangularRoom(x=35, y=15, width=10, height=15)
|
||||
rooms: List[RectangularRoom] = []
|
||||
|
||||
dungeon.tiles[room_1.inner] = tile_types.floor
|
||||
dungeon.tiles[room_2.inner] = tile_types.floor
|
||||
for r in range(max_rooms):
|
||||
room_width = random.randint(room_min_size, room_max_size)
|
||||
room_height = random.randint(room_min_size, room_max_size)
|
||||
|
||||
x = random.randint(0, dungeon.width - room_width - 1)
|
||||
y = random.randint(0, dungeon.height - room_height - 1)
|
||||
|
||||
# "RectangularRoom" class makes rectangles easier to work with
|
||||
new_room = RectangularRoom(x, y, room_width, room_height)
|
||||
|
||||
# Run through the other rooms and see if they intersect with this one.
|
||||
# If there are no intersections then the room is valid
|
||||
if any(new_room.intersects(other_room) for other_room in rooms):
|
||||
continue # This room intersects, so go to the next attempt.
|
||||
|
||||
# Dig out this room's inner area.
|
||||
dungeon.tiles[new_room.inner] = tile_types.floor
|
||||
|
||||
if len(rooms) == 0:
|
||||
# The first room, where the player starts.
|
||||
player.x, player.y = new_room.center
|
||||
else: # All rooms after the first.
|
||||
# Dig out a tunnel between this room and the previous one
|
||||
for x, y in tunnel_between(rooms[-1].center, new_room.center):
|
||||
dungeon.tiles[x, y] = tile_types.floor
|
||||
|
||||
# Finally, append the new room to the list.
|
||||
rooms.append(new_room)
|
||||
|
||||
return dungeon
|
||||
|
Loading…
Reference in New Issue
Block a user