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
# 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:
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
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 .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)

View file

@ -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"]
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>
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)