Move the action perform logic to Action.perform() on each Action subclass

Rename Object to Entity to avoid name clashes with Python.object
This commit is contained in:
Eryn Wells 2022-05-01 09:29:30 -07:00
parent cde6ea2065
commit 5ce26e310b
4 changed files with 49 additions and 57 deletions

View file

@ -1,14 +1,28 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# Eryn Wells <eryn@erynwells.me> # Eryn Wells <eryn@erynwells.me>
import logging
from .engine import Engine
from .geometry import Vector
from .object import Entity
LOG = logging.getLogger('events')
class Action: 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): class ExitAction(Action):
pass def perform(self, engine: Engine, entity: Entity) -> None:
raise SystemExit()
class RegenerateRoomsAction(Action): class RegenerateRoomsAction(Action):
pass def perform(self, engine: Engine, entity: Entity) -> None:
...
class MovePlayerAction(Action): class MovePlayerAction(Action):
class Direction: class Direction:
@ -22,4 +36,15 @@ class MovePlayerAction(Action):
NorthWest = Vector(-1, -1) NorthWest = Vector(-1, -1)
def __init__(self, direction: Direction): def __init__(self, direction: Direction):
self.direction = direction 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)

View file

@ -7,7 +7,7 @@ from .actions import ExitAction, MovePlayerAction, RegenerateRoomsAction
from .events import EventHandler from .events import EventHandler
from .geometry import Point, Size from .geometry import Point, Size
from .map import Map from .map import Map
from .object import Object from .object import Entity
from typing import AbstractSet from typing import AbstractSet
LOG = logging.getLogger('engine') LOG = logging.getLogger('engine')
@ -30,10 +30,10 @@ class Engine:
first_room = self.map.rooms[0] first_room = self.map.rooms[0]
player_start_position = first_room.midpoint player_start_position = first_room.midpoint
self.player = Object('@', tcod.white, x=player_start_position.x, y=player_start_position.y) self.player = Entity('@', tcod.white, x=player_start_position.x, y=player_start_position.y)
self.objects: AbstractSet[Object] = {self.player} self.entities: AbstractSet[Entity] = {self.player}
for _ in range(self.rng.randint(1, 15)): 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): def handle_event(self, event: tcod.event.Event):
action = self.event_handler.dispatch(event) action = self.event_handler.dispatch(event)
@ -41,18 +41,7 @@ class Engine:
if not action: if not action:
return return
if isinstance(action, MovePlayerAction): action.perform(self, self.player)
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()
# if isinstance(action, RegenerateRoomsAction): # if isinstance(action, RegenerateRoomsAction):
# partitions, rooms = generate_rooms(random) # partitions, rooms = generate_rooms(random)
@ -60,5 +49,5 @@ class Engine:
def print_to_console(self, console): def print_to_console(self, console):
self.map.print_to_console(console) self.map.print_to_console(console)
for obj in self.objects: for ent in self.entities:
obj.print_to_console(console) ent.print_to_console(console)

View file

@ -88,4 +88,8 @@ class Map:
# fg=(255, 255, 255), bg=(80, 40, 40), clear=True) # fg=(255, 255, 255), bg=(80, 40, 40), clear=True)
size = self.size size = self.size
console.tiles_rgb[0:size.width, 0:size.height] = self.tiles["dark"] console.tiles_rgb[0:size.width, 0:size.height] = self.tiles["dark"]
class RectangularRoom:
def __init__(self, bounds: Rect):
self.bounds = bounds

View file

@ -2,42 +2,16 @@
# Eryn Wells <eryn@erynwells.me> # Eryn Wells <eryn@erynwells.me>
import tcod import tcod
from .geometry import Point, Vector from .geometry import Point
from typing import Optional
class Object: class Entity:
'''A drawable object with a symbol and (x, y) position.''' '''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): def __init__(self, symbol: str, *, position: Optional[Point] = None, color: Optional[tcod.Color] = None):
self.__x = int(x) self.position = position if position else Point()
self.__y = int(y) self.color = color if color else tcod.white
self.__color = color self.symbol = symbol
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 print_to_console(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)