procgen re-added

This commit is contained in:
Kayne Ruse 2025-03-20 10:56:10 +11:00
parent 2f7f2c3c4f
commit fc11ea9dbd
6 changed files with 98 additions and 12 deletions

View File

@ -2,7 +2,7 @@
## Concept
"Fun value", inspired by Undertale, activates different secrets at different times.
"Fun value", inspired by Undertale, activates different secrets in different runs.
## Links

View File

@ -21,6 +21,10 @@ class MoveAction(Action):
x = self.entity.x + self.xdir
y = self.entity.y + self.ydir
#TODO: bounds checks
#bounds and collision checks
if not engine.floor_map.in_bounds(x, y):
return
if not engine.floor_map.tiles["walkable"][x, y]:
return
self.entity.set_pos(x, y)

View File

@ -20,9 +20,9 @@ class Engine:
if action is None:
continue
action.apply(Engine)
action.apply(self)
def render(self, context: Context, console: Console) -> None:
self.floor_map.render(console)

View File

@ -9,9 +9,9 @@ class FloorMap:
self.width = width
self.height = height
self.tiles = np.full((width, height), fill_value=tile_types.wall, order="F")
def in_bounds(self, x: int, y: int) -> bool:
return 0 <= x < self.width and 0 <= y < self.height
def render(self, console: Console) -> None:
console.rgb[0:self.width, 0:self.height] = self.tiles["dark"]

View File

@ -1,9 +1,8 @@
#!./bin/python
import tcod
from floor_map import FloorMap #TODO: replace with "DungeonMap"
from engine import Engine
from procgen import generate_floor_map
def main() -> None:
#assets
@ -25,9 +24,9 @@ def main() -> None:
order = "F"
)
floor_map = FloorMap(80, 45) # same as context settings
engine = Engine(floor_map)
engine = Engine(
floor_map = generate_floor_map(80, 45, 10, 10)
)
# game loop
while True:

83
source/procgen.py Normal file
View File

@ -0,0 +1,83 @@
from __future__ import annotations
import random
from typing import Iterator, List, Tuple
import tcod
import tile_types
from floor_map import FloorMap
#utils
def make_corridor(start: Tuple[int, int], end: Tuple[int, int]) -> Iterator[Tuple[int,int]]:
#simplistic, but it works
x1, y1 = start
x2, y2 = end
if random.random() < 0.5:
corner_x, corner_y = x2, y1
else:
corner_x, corner_y = x1, y2
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
class RectangularRoom:
def __init__(self, x: int, y: int, width: int, height: int):
self.x1 = x
self.y1 = y
self.x2 = x + width
self.y2 = y + height
@property
def center(self) -> Tuple[int, int]:
center_x = (self.x1 + self.x2) // 2
center_y = (self.y1 + self.y2) // 2
return center_x, center_y
@property
def inner(self) -> Tuple[slice, slice]:
return slice(self.x1 + 1, self.x2), slice(self.y1 + 1, self.y2)
def intersects(self, other: RectangularRoom) -> bool:
return (
self.x1 <= other.x2 and
self.x2 >= other.x1 and
self.y1 <= other.y2 and
self.y2 >= other.y1
)
#generators
def generate_floor_map(map_width: int, map_height: int, room_width_max: int, room_height_max: int, room_width_min: int = 6, room_height_min: int = 6, room_count_max: int = 20) -> FloorMap:
#simplistic floor generator
floor_map = FloorMap(map_width, map_height)
rooms: List[RectangularRoom] = []
for r in range(room_count_max):
room_width = random.randint(room_width_min, room_width_max)
room_height = random.randint(room_height_min, room_height_max)
x = random.randint(0, floor_map.width - room_width - 1)
y = random.randint(0, floor_map.height - room_height - 1)
new_room = RectangularRoom(x, y, room_width, room_height)
if any(new_room.intersects(other_room) for other_room in rooms):
continue
floor_map.tiles[new_room.inner] = tile_types.floor
if len(rooms) == 0:
# TODO: specify player spawn point
pass
else:
for x, y in make_corridor(rooms[-1].center, new_room.center):
floor_map.tiles[x, y] = tile_types.floor
rooms.append(new_room)
return floor_map