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,9 +1,27 @@
class Action:
pass
from __future__ import annotations
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):
pass
def perform(self, engine: Engine, entity: Entity) -> None:
raise SystemExit()
class MovementAction(Action):
def __init__(self, dx: int, dy: int):
@@ -11,3 +29,14 @@ class MovementAction(Action):
self.dx = dx
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 entity import Entity
from game_map import GameMap
from input_handlers import EventHandler
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.event_handler = event_handler
self.game_map = game_map
self.player = player
def handle_events(self, events: Iterable[Any]) -> None:
@@ -20,12 +23,11 @@ class Engine:
if action is None:
continue
if isinstance(action, MovementAction):
self.player.move(dx=action.dx, dy=action.dy)
elif isinstance(action, EscapeAction):
raise SystemExit()
action.perform(self, self.player)
def render(self, console: Console, context: Context) -> None:
self.game_map.render(console)
for entity in self.entities:
console.print(entity.x, entity.y, entity.char, fg=entity.color)

View File

@@ -1,90 +1,18 @@
from map_objects import *
from random import randint
import numpy as np
from tcod.console import Console
import tile_types
class GameMap:
def __init__(self, width, height):
self.width = width
self.height = height
self.tiles = self.initialize_tiles()
def __init__(self, width: int, height: int):
self.width, self.height = width, height
self.tiles = np.full((width,height), fill_value=tile_types.floor, order="F")
def initialize_tiles(self):
tiles = [[Tile(True) for y in range(self.height)] for x in range(self.width)]
self.tiles[30:33, 22] = tile_types.wall
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):
if self.tiles[x][y].blocked:
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
def render(self, console: Console) -> None:
console.tiles_rgb[0:self.width, 0:self.height] = self.tiles["dark"]

View File

@@ -2,6 +2,7 @@ import tcod
from engine import Engine
from entity import Entity
from game_map import GameMap
from input_handlers import EventHandler
@@ -10,6 +11,9 @@ def main():
screen_width = 80
screen_height = 50
map_width = 80
map_height = 45
room_max_size = 10
room_min_size = 6
max_rooms = 30
@@ -29,7 +33,9 @@ def main():
npc = Entity(int(screen_width/2), int(screen_height/2), '@', (255, 255, 0))
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(
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)),
)