diff --git a/roguebasin/actions.py b/roguebasin/actions.py index f5b34f9..9131bb4 100644 --- a/roguebasin/actions.py +++ b/roguebasin/actions.py @@ -1,14 +1,28 @@ #!/usr/bin/env python3 # Eryn Wells +import logging +from .engine import Engine +from .geometry import Vector +from .object import Entity + +LOG = logging.getLogger('events') + class Action: - pass + def perform(self, engine: Engine, entity: Entity) -> None: + ''' + Perform this action. This is an abstract method that all subclasses + should implement. + ''' + raise NotImplementedError() class ExitAction(Action): - pass + def perform(self, engine: Engine, entity: Entity) -> None: + raise SystemExit() class RegenerateRoomsAction(Action): - pass + def perform(self, engine: Engine, entity: Entity) -> None: + ... class MovePlayerAction(Action): class Direction: @@ -22,4 +36,15 @@ class MovePlayerAction(Action): NorthWest = Vector(-1, -1) def __init__(self, direction: Direction): - self.direction = direction \ No newline at end of file + self.direction = direction + + def perform(self, engine: Engine, entity: Entity) -> None: + new_player_position = entity.position + self.direction + + position_is_in_bounds = self.map.tile_is_in_bounds(new_player_position) + position_is_walkable = self.map.tile_is_walkable(new_player_position) + overlaps_an_entity = any(new_player_position.x == obj.x and new_player_position.y == obj.y for obj in engine.entities) + + LOG.debug(f'Attempting to move player to {new_player_position} (in_bounds:{position_is_in_bounds} walkable:{position_is_walkable} overlaps:{overlaps_an_entity})') + if position_is_in_bounds and position_is_walkable and not overlaps_an_entity: + self.player.move_to(new_player_position) diff --git a/roguebasin/engine.py b/roguebasin/engine.py index 26eb6cb..af28047 100644 --- a/roguebasin/engine.py +++ b/roguebasin/engine.py @@ -7,7 +7,7 @@ from .actions import ExitAction, MovePlayerAction, RegenerateRoomsAction from .events import EventHandler from .geometry import Point, Size from .map import Map -from .object import Object +from .object import Entity from typing import AbstractSet LOG = logging.getLogger('engine') @@ -30,10 +30,10 @@ class Engine: first_room = self.map.rooms[0] player_start_position = first_room.midpoint - self.player = Object('@', tcod.white, x=player_start_position.x, y=player_start_position.y) - self.objects: AbstractSet[Object] = {self.player} + self.player = Entity('@', tcod.white, x=player_start_position.x, y=player_start_position.y) + self.entities: AbstractSet[Entity] = {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))) + self.entities.add(Entity('@', 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) @@ -41,18 +41,7 @@ class Engine: if not action: return - if isinstance(action, MovePlayerAction): - map_size = self.configuration.map_size - new_player_position = Point(self.player.x + action.direction[0], - self.player.y + action.direction[1]) - can_move_to_map_position = self.map.tile_is_in_bounds(new_player_position) and self.map.tile_is_walkable(new_player_position) - overlaps_an_object = any(new_player_position.x == obj.x and new_player_position.y == obj.y for obj in self.objects) - EVENT_LOG.debug(f'Attempting to move player to {new_player_position}; can_move:{can_move_to_map_position} overlaps:{overlaps_an_object}') - if can_move_to_map_position and not overlaps_an_object: - self.player.move_to(new_player_position) - - if isinstance(action, ExitAction): - raise SystemExit() + action.perform(self, self.player) # if isinstance(action, RegenerateRoomsAction): # partitions, rooms = generate_rooms(random) @@ -60,5 +49,5 @@ class Engine: def print_to_console(self, console): self.map.print_to_console(console) - for obj in self.objects: - obj.print_to_console(console) + for ent in self.entities: + ent.print_to_console(console) diff --git a/roguebasin/map.py b/roguebasin/map.py index 2cd3424..efaa2ef 100644 --- a/roguebasin/map.py +++ b/roguebasin/map.py @@ -88,4 +88,8 @@ class Map: # fg=(255, 255, 255), bg=(80, 40, 40), clear=True) size = self.size - console.tiles_rgb[0:size.width, 0:size.height] = self.tiles["dark"] \ No newline at end of file + console.tiles_rgb[0:size.width, 0:size.height] = self.tiles["dark"] + +class RectangularRoom: + def __init__(self, bounds: Rect): + self.bounds = bounds \ No newline at end of file diff --git a/roguebasin/object.py b/roguebasin/object.py index d01c1d4..4f1c098 100644 --- a/roguebasin/object.py +++ b/roguebasin/object.py @@ -2,42 +2,16 @@ # Eryn Wells import tcod -from .geometry import Point, Vector +from .geometry import Point +from typing import Optional -class Object: - '''A drawable object with a symbol and (x, y) position.''' +class Entity: + '''A single-tile drawable entity with a symbol and position.''' - def __init__(self, symbol: str, color: tcod.Color = (255, 255, 255), x: int = 0, y: int = 0): - self.__x = int(x) - self.__y = int(y) - self.__color = color - self.__symbol = symbol - - @property - def x(self): - return self.__x - - @x.setter - def x(self, value): - self.__x = int(value) - - @property - def y(self): - return self.__y - - @y.setter - def y(self, value): - self.__y = int(value) - - def move(self, delta: Vector): - '''Move this object by (dx, dy).''' - self.__x += delta.dx - self.__y += delta.dy - - def move_to(self, point: Point) -> None: - '''Move this object directly to the given position.''' - self.__x = point.x - self.__y = point.y + def __init__(self, symbol: str, *, position: Optional[Point] = None, color: Optional[tcod.Color] = None): + self.position = position if position else Point() + self.color = color if color else tcod.white + self.symbol = symbol def print_to_console(self, console: tcod.Console) -> None: console.print(x=self.__x, y=self.__y, string=self.__symbol, fg=self.__color)