This commit is contained in:
2021-05-26 16:36:59 -04:00
parent 3fff7ef498
commit d05eec6c03
5 changed files with 98 additions and 96 deletions

View File

@@ -1,13 +1,42 @@
class Action: from __future__ import annotations
pass
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from engine import Engine
from entity import Entity
class Action:
def perform(self, engine: Engine, entity: Entity) -> None:
"""Perform this action with the objects needed to determine its scope
'engine' is the scope this action is being perfrmed in.
'entity is the object performing the action.
This method must be overridden by Action subclasses
"""
raise NotImplementedError()
class EscapeAction(Action): class EscapeAction(Action):
pass def perform(self, engine: Engine, entity: Entity) -> None:
raise SystemExit()
class MovementAction(Action): class MovementAction(Action):
def __init__(self, dx: int, dy: int): def __init__(self, dx: int, dy: int):
super().__init__() super().__init__()
self.dx = dx self.dx = dx
self.dy = dy self.dy = dy
def perform(self, engine: Engine, entity: Entity) -> None:
dest_x = entity.x + self.dx
dest_y = entity.y + self.dy
if not engine.game_map.in_bounds(dest_x, dest_y):
return # Destination is out of bounds.
if not engine.game_map.tiles["walkable"][dest_x, dest_y]:
return # Destination is blocked by a tile
entity.move(self.dx, self.dy)

View File

@@ -5,12 +5,15 @@ from tcod.console import Console
from actions import EscapeAction, MovementAction from actions import EscapeAction, MovementAction
from entity import Entity from entity import Entity
from game_map import GameMap
from input_handlers import EventHandler from input_handlers import EventHandler
class Engine: class Engine:
def __init__(self, entities: Set[Entity], event_handler: EventHandler, player: Entity): def __init__(self, entities: Set[Entity], event_handler: EventHandler, game_map: GameMap, player: Entity):
self.entities = entities self.entities = entities
self.event_handler = event_handler self.event_handler = event_handler
self.game_map = game_map
self.player = player self.player = player
def handle_events(self, events: Iterable[Any]) -> None: def handle_events(self, events: Iterable[Any]) -> None:
@@ -20,15 +23,14 @@ class Engine:
if action is None: if action is None:
continue continue
if isinstance(action, MovementAction): action.perform(self, self.player)
self.player.move(dx=action.dx, dy=action.dy)
elif isinstance(action, EscapeAction):
raise SystemExit()
def render(self, console: Console, context: Context) -> None: def render(self, console: Console, context: Context) -> None:
self.game_map.render(console)
for entity in self.entities: for entity in self.entities:
console.print(entity.x, entity.y, entity.char, fg=entity.color) console.print(entity.x, entity.y, entity.char, fg=entity.color)
context.present(console) context.present(console)
console.clear() console.clear()

View File

@@ -1,90 +1,18 @@
from map_objects import * import numpy as np
from random import randint from tcod.console import Console
import tile_types
class GameMap: class GameMap:
def __init__(self, width, height): def __init__(self, width: int, height: int):
self.width = width self.width, self.height = width, height
self.height = height self.tiles = np.full((width,height), fill_value=tile_types.floor, order="F")
self.tiles = self.initialize_tiles()
def initialize_tiles(self): self.tiles[30:33, 22] = tile_types.wall
tiles = [[Tile(True) for y in range(self.height)] for x in range(self.width)]
return tiles def in_bounds(self, x: int, y: int) -> bool:
"""Return True if x and y are inside the bounds of this map"""
return 0 <= x < self.width and 0 <= y < self.height
def is_blocked(self, x, y): def render(self, console: Console) -> None:
if self.tiles[x][y].blocked: console.tiles_rgb[0:self.width, 0:self.height] = self.tiles["dark"]
return True
return False
def create_room(self, room):
# go through the tiles in the rectangle and make them passable
for x in range(room.x1 + 1, room.x2):
for y in range(room.y1 +1, room.y2):
self.tiles[x][y].blocked = False
self.tiles[x][y].block_sight = False
def create_h_tunnel(self, x1, x2, y):
for x in range(min(x1, x2), max(x1, x2) + 1):
self.tiles[x][y].blocked = False
self.tiles[x][y].block_sight = False
def create_v_tunnel(self, y1, y2, x):
for y in range(min(y1, y2), max(y1, y2) + 1):
self.tiles[x][y].blocked = False
self.tiles[x][y].block_sight = False
def make_map(self, max_rooms, room_min_size, room_max_size, map_width, map_height, player):
rooms = []
num_rooms = 0
for r in range(max_rooms):
# print(rooms)
# print(num_rooms)
# random width and height
w = randint(room_min_size, room_max_size)
h = randint(room_min_size, room_max_size)
# random position without going out of bounds
x = randint(0, map_width - w - 1)
y = randint(0, map_height - h - 1)
#call Rect Class
new_room = Rect(x, y, w, h)
# if rooms == []:
# print('first')
# rooms.append(new_room)
#run through other rooms to check for overlap
for other_room in rooms:
if new_room.intersect(other_room):
break
else:
# no overlap, room is valid
# paint to map's tiles
self.create_room(new_room)
#center coords of new room
(new_x, new_y) = new_room.center()
if num_rooms == 0:
#first room where player starts
player.x = new_x
player.y = new_y
else:
# all rooms after the first are connected
# center coords of previous room
(prev_x, prev_y) = rooms[num_rooms - 1].center()
if randint(0, 1) == 1:
#first horizontally then vertically
self.create_h_tunnel(prev_x, new_x, prev_y)
self.create_v_tunnel(prev_y, new_y, new_x)
else:
#first vertically then horizontally
self.create_v_tunnel(prev_y, new_y, prev_x)
self.create_h_tunnel(prev_x, new_x, new_y)
rooms.append(new_room)
num_rooms += 1

View File

@@ -2,6 +2,7 @@ import tcod
from engine import Engine from engine import Engine
from entity import Entity from entity import Entity
from game_map import GameMap
from input_handlers import EventHandler from input_handlers import EventHandler
@@ -10,6 +11,9 @@ def main():
screen_width = 80 screen_width = 80
screen_height = 50 screen_height = 50
map_width = 80
map_height = 45
room_max_size = 10 room_max_size = 10
room_min_size = 6 room_min_size = 6
max_rooms = 30 max_rooms = 30
@@ -29,7 +33,9 @@ def main():
npc = Entity(int(screen_width/2), int(screen_height/2), '@', (255, 255, 0)) npc = Entity(int(screen_width/2), int(screen_height/2), '@', (255, 255, 0))
entities = {npc, player} entities = {npc, player}
engine = Engine(entities=entities, event_handler=event_handler, player=player) game_map = GameMap(map_width, map_height)
engine = Engine(entities=entities, event_handler=event_handler, game_map=game_map, player=player)
with tcod.context.new_terminal( with tcod.context.new_terminal(
screen_width, screen_width,

37
tile_types.py Normal file
View File

@@ -0,0 +1,37 @@
from typing import Tuple
import numpy as np
graphic_dt = np.dtype(
[
("ch", np.int32),
("fg", "3b"),
("bg", "3B"),
]
)
tile_dt = np.dtype(
[
("walkable", np.bool),
("transparent", np.bool),
("dark", graphic_dt),
]
)
def new_tile(
*,
walkable: int,
transparent: int,
dark: Tuple[int, Tuple[int, int, int], Tuple[int, int, int]],
) -> np.ndarray:
"""Helper function for defining individual tile types"""
return np.array((walkable, transparent, dark), dtype=tile_dt)
floor = new_tile(
walkable=True, transparent=True, dark=(ord(" "),(255,255,255), (50,50, 150)),
)
wall = new_tile(
walkable=False, transparent=True, dark=(ord(" "), (255,255,255), (0,0,100)),
)