Add an Engine class and move all the engine-y bits over there from main
This commit is contained in:
parent
dc78669abf
commit
d56bcc7b4a
3 changed files with 68 additions and 73 deletions
62
roguebasin/engine.py
Normal file
62
roguebasin/engine.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# Eryn Wells <eryn@erynwells.me>
|
||||||
|
|
||||||
|
import logging
|
||||||
|
import tcod
|
||||||
|
from .actions import ExitAction, MovePlayerAction, RegenerateRoomsAction
|
||||||
|
from .events import EventHandler
|
||||||
|
from .geometry import Point, Size
|
||||||
|
from .map import Map
|
||||||
|
from .object import Object
|
||||||
|
from typing import AbstractSet
|
||||||
|
|
||||||
|
LOG = logging.getLogger('engine')
|
||||||
|
EVENT_LOG = logging.getLogger('events')
|
||||||
|
|
||||||
|
class Configuration:
|
||||||
|
def __init__(self, map_size: Size):
|
||||||
|
self.map_size = map_size
|
||||||
|
self.random_seed = None
|
||||||
|
|
||||||
|
class Engine:
|
||||||
|
def __init__(self, event_handler: EventHandler, configuration: Configuration):
|
||||||
|
self.event_handler = event_handler
|
||||||
|
self.configuration = configuration
|
||||||
|
|
||||||
|
self.rng = tcod.random.Random(seed=configuration.random_seed)
|
||||||
|
|
||||||
|
map_size = configuration.map_size
|
||||||
|
self.map = Map(map_size)
|
||||||
|
|
||||||
|
self.player = Object('@', tcod.white, x=int(map_size.width / 2), y=int(map_size.height / 2))
|
||||||
|
self.objects: AbstractSet[Object] = {self.player}
|
||||||
|
for _ in range(self.rng.randint(1, 15)):
|
||||||
|
self.objects.add(Object('@', color=tcod.yellow, x=self.rng.randint(0, map_size.width), y=self.rng.randint(0, map_size.height)))
|
||||||
|
|
||||||
|
def handle_event(self, event: tcod.event.Event):
|
||||||
|
action = self.event_handler.dispatch(event)
|
||||||
|
|
||||||
|
if not action:
|
||||||
|
return
|
||||||
|
|
||||||
|
if isinstance(action, MovePlayerAction):
|
||||||
|
map_size = self.configuration.map_size
|
||||||
|
new_player_position = Point(max(0, min(map_size.width - 1, self.player.x + action.direction[0])),
|
||||||
|
max(0, min(map_size.height - 1, self.player.y + action.direction[1])))
|
||||||
|
can_move_to_level_position = not self.map.tile_for_point(new_player_position).blocks_movement
|
||||||
|
overlaps_an_object = any(new_player_position.x == obj.x and new_player_position.y == obj.y for obj in self.objects)
|
||||||
|
if can_move_to_level_position and not overlaps_an_object:
|
||||||
|
EVENT_LOG.debug(f'Moving player to {new_player_position}; can_move:{can_move_to_level_position} overlaps:{overlaps_an_object}')
|
||||||
|
self.player.move_to(new_player_position)
|
||||||
|
|
||||||
|
if isinstance(action, ExitAction):
|
||||||
|
raise SystemExit()
|
||||||
|
|
||||||
|
# if isinstance(action, RegenerateRoomsAction):
|
||||||
|
# partitions, rooms = generate_rooms(random)
|
||||||
|
|
||||||
|
def print_to_console(self, console):
|
||||||
|
self.map.print_to_console(console)
|
||||||
|
|
||||||
|
for obj in self.objects:
|
||||||
|
obj.print_to_console(console)
|
|
@ -10,6 +10,7 @@ import logging
|
||||||
import os.path
|
import os.path
|
||||||
import random
|
import random
|
||||||
import tcod
|
import tcod
|
||||||
|
from .engine import Configuration, Engine
|
||||||
from .events import EventHandler, ExitAction, MovePlayerAction, RegenerateRoomsAction
|
from .events import EventHandler, ExitAction, MovePlayerAction, RegenerateRoomsAction
|
||||||
from .geometry import Point, Rect, Size, Vector
|
from .geometry import Point, Rect, Size, Vector
|
||||||
from .object import Object
|
from .object import Object
|
||||||
|
@ -75,83 +76,15 @@ def main(argv):
|
||||||
|
|
||||||
level = [[Tile(False) for y in range(MAP_HEIGHT)] for x in range(MAP_WIDTH)]
|
level = [[Tile(False) for y in range(MAP_HEIGHT)] for x in range(MAP_WIDTH)]
|
||||||
|
|
||||||
random = tcod.random.Random()
|
|
||||||
partitions, rooms = generate_rooms(random)
|
|
||||||
|
|
||||||
objects = [PLAYER, NPC]
|
|
||||||
|
|
||||||
event_handler = EventHandler()
|
event_handler = EventHandler()
|
||||||
|
configuration = Configuration(map_size=Size(MAP_WIDTH, MAP_HEIGHT))
|
||||||
|
engine = Engine(event_handler, configuration)
|
||||||
|
|
||||||
with tcod.context.new(columns=console.width, rows=console.height, tileset=tileset) as context:
|
with tcod.context.new(columns=console.width, rows=console.height, tileset=tileset) as context:
|
||||||
while True:
|
while True:
|
||||||
#
|
|
||||||
# Draw
|
|
||||||
#
|
|
||||||
|
|
||||||
console.clear()
|
console.clear()
|
||||||
|
engine.print_to_console(console)
|
||||||
for part in partitions:
|
|
||||||
console.draw_frame(part.x, part.y, part.width, part.height, bg=(40, 40, 80), clear=True, decoration="···· ····")
|
|
||||||
|
|
||||||
for room in rooms:
|
|
||||||
console.draw_frame(room.origin.x, room.origin.y, room.size.width, room.size.height,
|
|
||||||
fg=(255, 255, 255), bg=(80, 40, 40), clear=True)
|
|
||||||
|
|
||||||
for obj in objects:
|
|
||||||
obj.print(console)
|
|
||||||
|
|
||||||
context.present(console)
|
context.present(console)
|
||||||
|
|
||||||
#
|
|
||||||
# Handle Events
|
|
||||||
#
|
|
||||||
|
|
||||||
for event in tcod.event.wait():
|
for event in tcod.event.wait():
|
||||||
action = event_handler.dispatch(event)
|
engine.handle_event(event)
|
||||||
|
|
||||||
if not action:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if isinstance(action, MovePlayerAction):
|
|
||||||
new_player_position = Point(max(0, min(CONSOLE_WIDTH, PLAYER.x + action.direction[0])),
|
|
||||||
max(0, min(CONSOLE_HEIGHT, PLAYER.y + action.direction[1])))
|
|
||||||
can_move_to_level_position = not level[new_player_position.x][new_player_position.y].blocks_movement
|
|
||||||
overlaps_an_object = any(new_player_position.x == obj.x and new_player_position.y == obj.y for obj in objects)
|
|
||||||
if can_move_to_level_position and not overlaps_an_object:
|
|
||||||
LOG.debug(f'Moving player to {new_player_position}; can_move:{can_move_to_level_position} overlaps:{overlaps_an_object}')
|
|
||||||
PLAYER.move_to(new_player_position)
|
|
||||||
|
|
||||||
if isinstance(action, ExitAction):
|
|
||||||
raise SystemExit()
|
|
||||||
|
|
||||||
if isinstance(action, RegenerateRoomsAction):
|
|
||||||
partitions, rooms = generate_rooms(random)
|
|
||||||
|
|
||||||
def generate_rooms(random: tcod.random.Random) -> List[Rect]:
|
|
||||||
bsp = tcod.bsp.BSP(x=0, y=0, width=MAP_WIDTH, height=MAP_HEIGHT)
|
|
||||||
bsp.split_recursive(
|
|
||||||
depth=4,
|
|
||||||
min_width=8, min_height=8,
|
|
||||||
max_horizontal_ratio=1.5, max_vertical_ratio=1.5)
|
|
||||||
|
|
||||||
partitions = []
|
|
||||||
rooms = []
|
|
||||||
indent = 0
|
|
||||||
for node in bsp.pre_order():
|
|
||||||
if node.children:
|
|
||||||
LOG.debug(f'{" " * indent}{Rect(node.x, node.y, node.width, node.height)}')
|
|
||||||
indent += 2
|
|
||||||
# TODO: Connect the two child rooms
|
|
||||||
else:
|
|
||||||
LOG.debug(f'{" " * indent}{Rect(node.x, node.y, node.width, node.height)} (room)')
|
|
||||||
size = Size(random.randint(5, min(15, max(5, node.width - 2))),
|
|
||||||
random.randint(5, min(15, max(5, node.height - 2))))
|
|
||||||
origin = Point(node.x + random.randint(1, max(1, node.width - size.width - 1)),
|
|
||||||
node.y + random.randint(1, max(1, node.height - size.height - 1)))
|
|
||||||
room = Rect(origin.x, origin.y, size.width, size.height)
|
|
||||||
LOG.debug(f'{" " * indent}`-> {room}')
|
|
||||||
partitions.append(node)
|
|
||||||
rooms.append(room)
|
|
||||||
indent -= 2
|
|
||||||
|
|
||||||
return partitions, rooms
|
|
|
@ -39,5 +39,5 @@ class Object:
|
||||||
self.__x = point.x
|
self.__x = point.x
|
||||||
self.__y = point.y
|
self.__y = point.y
|
||||||
|
|
||||||
def print(self, console: tcod.Console) -> None:
|
def print_to_console(self, console: tcod.Console) -> None:
|
||||||
console.print(x=self.__x, y=self.__y, string=self.__symbol, fg=self.__color)
|
console.print(x=self.__x, y=self.__y, string=self.__symbol, fg=self.__color)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue