From d56bcc7b4ab066f14bf53e971df6f1700519f84f Mon Sep 17 00:00:00 2001 From: Eryn Wells Date: Sat, 30 Apr 2022 23:30:23 -0700 Subject: [PATCH] Add an Engine class and move all the engine-y bits over there from main --- roguebasin/engine.py | 62 +++++++++++++++++++++++++++++++++++ roguebasin/main.py | 77 +++----------------------------------------- roguebasin/object.py | 2 +- 3 files changed, 68 insertions(+), 73 deletions(-) create mode 100644 roguebasin/engine.py diff --git a/roguebasin/engine.py b/roguebasin/engine.py new file mode 100644 index 0000000..f3d6058 --- /dev/null +++ b/roguebasin/engine.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 +# Eryn Wells + +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) diff --git a/roguebasin/main.py b/roguebasin/main.py index b894070..b9f170b 100644 --- a/roguebasin/main.py +++ b/roguebasin/main.py @@ -10,6 +10,7 @@ import logging import os.path import random import tcod +from .engine import Configuration, Engine from .events import EventHandler, ExitAction, MovePlayerAction, RegenerateRoomsAction from .geometry import Point, Rect, Size, Vector 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)] - random = tcod.random.Random() - partitions, rooms = generate_rooms(random) - - objects = [PLAYER, NPC] - 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: while True: - # - # Draw - # - console.clear() - - 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) - + engine.print_to_console(console) context.present(console) - # - # Handle Events - # - for event in tcod.event.wait(): - action = event_handler.dispatch(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 \ No newline at end of file + engine.handle_event(event) \ No newline at end of file diff --git a/roguebasin/object.py b/roguebasin/object.py index 1f02bfb..d01c1d4 100644 --- a/roguebasin/object.py +++ b/roguebasin/object.py @@ -39,5 +39,5 @@ class Object: self.__x = point.x 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)