Bring in the ECS I wrote for later and phase_07.py now has a change the window display. If I have a border then the self.map coordinates don't fit the screen coordinates. Removing it makes them match which is easier. Also going to a smaller display makes it easier to work with and less intimidating.

master
Zed A. Shaw 7 days ago
parent 117748ae5d
commit 83eac4747f
  1. 62
      ecs.py
  2. 104
      phase_07.py

@ -0,0 +1,62 @@
class ECS:
def __init__(self):
self.entities = {}
self.facts = {}
self.id_counter = 0
def entity(self):
self.id_counter += 1
return self.id_counter
def set(self, entity_id, obj):
name = obj.__class__.__qualname__
target = self.entities.get(name, {})
target[entity_id] = obj
self.entities[name] = target
def query(self, cls):
return self.entities[cls.__qualname__].items()
class Systems:
def __init__(self, ecs):
self.ecs = ecs
def play_sounds(self):
for eid, entity in ecs.query(Sound):
print("TALKING: ", entity.text)
def combat(self):
for eid, entity in ecs.query(Combat):
print("FIGHT: ", entity.hp)
def movement(self):
for eid, entity in ecs.query(Position):
print("MOVE: ", entity.x, entity.y)
class Combat:
def __init__(self, hp):
self.hp = hp
class Sound:
def __init__(self, text):
self.text = text
class Position:
def __init__(self, x, y):
self.x = x
self.y = y
ecs = ECS()
systems = Systems(ecs)
troll = ecs.entity()
ecs.set(troll, Combat(100))
ecs.set(troll, Sound("ROAR!"))
ecs.set(troll, Position(1, 2))
systems.play_sounds()
systems.combat()
systems.movement()

@ -2,8 +2,8 @@ import curses
import sys
import random
WALL = 1
SPACE = 0
WALL = '#'
SPACE = '.'
class Map:
def __init__(self, width, height):
@ -15,6 +15,13 @@ class Map:
self.hunt_and_kill(grid)
self.render_map(grid)
def spawn(self):
while True:
y = random.randrange(0, self.height)
x = random.randrange(0, self.width)
if self.map[y][x] == SPACE:
return x, y
def sample_rooms(self, grid, dead_ends, size, count):
grid = self.make_grid()
for x, y in random.sample(dead_ends, count):
@ -39,7 +46,7 @@ class Map:
for x in range(1, self.width, 2):
if grid[y][x] != WALL: continue
found = self.neighborsAB(grid, x, y)
found = self.neighbors(grid, x, y)
for found_x, found_y in found:
if grid[found_y][found_x] == SPACE:
return [[x,y],[found_x, found_y]]
@ -49,7 +56,7 @@ class Map:
def inbounds(self, x, y):
return x >= 0 and x < self.width and y >= 0 and y < self.height
def neighborsAB(self, grid, x, y):
def neighbors(self, grid, x, y):
points = [[x, y - 2],
[x, y + 2],
[x - 2, y],
@ -61,15 +68,11 @@ class Map:
result.append([x,y])
return result
def neighbors(self, grid, x, y):
points = [[x, y - 2],
[x, y + 2],
[x - 2, y],
[x + 2, y]]
def neighbor_walls(self, grid, x, y):
neighbors = self.neighbors(grid, x, y)
result = []
for x,y in points:
if self.inbounds(x, y) and grid[y][x] == WALL:
for x,y in neighbors:
if grid[y][x] == WALL:
result.append([x,y])
return result
@ -79,7 +82,7 @@ class Map:
dead_ends = []
while True:
n = self.neighbors(grid, on_x, on_y)
n = self.neighbor_walls(grid, on_x, on_y)
if len(n) == 0:
dead_ends.append([on_x, on_y])
t = self.find_coord(grid)
@ -107,22 +110,19 @@ class Map:
cur_row = ""
for x, char in enumerate(y_line):
if char == 0:
cur_row += '.'
else:
cur_row += '#'
cur_row += char
self.map.append(cur_row)
def move_player(self, player, target_y, target_x):
if self.map[target_y - 1][target_x - 1] != '#':
def move_player(self, player, target_x, target_y):
if self.map[target_y][target_x] != '#':
player.y = target_y
player.x = target_x
def draw(self, win):
map_line = 1
map_line = 0
for line in self.map:
win.addstr(map_line, 1, line)
win.addstr(map_line, 0, line)
map_line += 1
class UI:
@ -134,7 +134,7 @@ class UI:
win = curses.newwin(height, width, begin_y, begin_x)
win.keypad(True)
status = win.subwin(status_height, width-2, height-status_height, begin_x+1)
status = win.subwin(status_height, width, height-status_height, begin_x)
# keep these for later by assigning to self
self.begin_x = 0
@ -149,23 +149,28 @@ class UI:
def set_map(self, the_map):
self.map = the_map
def update(self, player):
def update(self, actors):
assert self.map, "You forgot to call set_map()"
self.win.clear()
self.win.box()
self.status.hline(0,0, curses.ACS_HLINE, self.width - 2)
self.status.box()
self.map.draw(self.win)
self.draw_status()
self.draw_player(player)
# this assumes actors[0] is the player
self.draw_status(actors[0])
for actor in actors:
self.draw_actor(actor)
self.win.refresh()
def draw_status(self):
self.status.addstr(1, 1, "PLAYER STATS")
def draw_status(self, player):
self.status.addstr(1, 1, f"PLAYER AT {player.x},{player.y}")
def draw_actor(self, actor):
assert self.map.map[actor.y][actor.x] != '#', f"WHAT? actor at {actor.x},{actor.y} but that's a wall!"
def draw_player(self, player):
self.win.addstr(player.y, player.x, '@', curses.A_BOLD)
# actor has to be moved in by 1 for the border
self.win.addstr(actor.y, actor.x, actor.symbol, curses.A_BOLD)
def handle_input(self, y, x):
def handle_input(self, x, y):
ch = self.win.getch()
if ch == ord('q'):
@ -179,30 +184,49 @@ class UI:
elif ch == curses.KEY_LEFT:
x = (x - 1) % self.width
return y, x
return x, y
class Player:
def __init__(self, x, y):
self.x = x
self.y = y
self.symbol = '@'
class Enemy:
def __init__(self, x, y, symbol):
self.x = x
self.y = y
self.symbol = symbol
class GameEngine:
def __init__(self, ui):
self.ui = ui
self.player = Player(4, 4)
self.map = Map(77,19)
self.map = Map(ui.width, ui.height - ui.status_height)
self.ui = ui
ui.set_map(self.map)
def spawn_actors(self):
x, y = self.map.spawn()
self.player = Player(x, y)
x, y = self.map.spawn()
self.enemy = Enemy(x, y, '{')
self.actors = [self.player, self.enemy]
def run(self):
self.spawn_actors()
self.map.move_player(self.player, self.player.x, self.player.y)
while True:
self.ui.update(self.player)
new_y, new_x = self.ui.handle_input(self.player.y, self.player.x)
self.map.move_player(self.player, new_y, new_x)
# remember, first one has to be the player
self.ui.update(self.actors)
new_x, new_y = self.ui.handle_input(self.player.x, self.player.y)
self.map.move_player(self.player, new_x, new_y)
def main(stdscr):
width=80
height=26
width=27
height=16
ui = UI(stdscr, height, width, 5)
game = GameEngine(ui)
game.run()

Loading…
Cancel
Save