revised some code

This commit is contained in:
Suguivy 2023-03-13 19:46:29 +01:00
parent 5adde7b48d
commit 9fe7846f1b
6 changed files with 73 additions and 53 deletions

2
.gitignore vendored
View File

@ -1,3 +1,3 @@
log.txt *.log
ideas.md ideas.md
__pycache__/ __pycache__/

View File

@ -15,7 +15,7 @@ class NA:
Action = Move | Idle | NA Action = Move | Idle | NA
action_timing = { ACTION_TIMING = {
Move: 50, Move: 50,
Idle: 10, Idle: 10,
NA: 1 NA: 1

View File

@ -1,4 +1,3 @@
from enum import Enum
from actions import Action, Idle, NA from actions import Action, Idle, NA
class Entity(): class Entity():
@ -7,16 +6,16 @@ class Entity():
class Item(Entity): class Item(Entity):
pass pass
class Character(Entity): class Creature(Entity):
def __init__(self): def __init__(self):
self.speed = 1 self.speed = 1
self.action: Action = NA() self.action: Action = NA()
class Player(Character): class Player(Creature):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
class Enemy(Character): class Enemy(Creature):
def __init__(self): def __init__(self):
super().__init__() super().__init__()

View File

@ -1,35 +1,38 @@
from enum import Enum from enum import Enum
from typing import Tuple from typing import Tuple
from entity import Character, Entity, Item from entity import Creature, Item
class TileType(Enum): class TileType(Enum):
"""
An enum who has the different types of tiles
"""
WALL = 1 WALL = 1
AIR = 2 AIR = 2
class EntityMap: class EntityMap:
""" """
Class that stores entities in an special way in order to be able to reach in O(1) the values A class that stores entities in an special way in order to be able to reach in O(1) the values
""" """
def __init__(self): def __init__(self):
self.items = {} # K: Position V: List(Item) self.items = {} # K: Position V: List(Item)
self.pos_creatures = {} # K: Position V: Creature self.pos_creatures = {} # K: Position V: Creature
self.creatures_pos = {} # K: Creature V: Position self.creatures_pos = {} # K: Creature V: Position
def get_item(self, x, y): def get_item(self, x, y) -> Item | None:
return self.items.get((x, y)) return self.items.get((x, y))
def get_creature(self, x, y): def get_creature(self, x, y) -> Item | None:
return self.pos_creatures.get((x, y)) return self.pos_creatures.get((x, y))
def get_creature_position(self, creature: Character): def get_creature_position(self, creature: Creature) -> Tuple[int, int]:
return self.creatures_pos.get(creature) return self.creatures_pos[creature]
def add_item(self, x, y, item: Item): def add_item(self, x, y, item: Item) -> None:
if (x, y) not in self.items: if (x, y) not in self.items:
self.items[(x, y)] = [] self.items[(x, y)] = []
self.items[(x, y)].append(item) self.items[(x, y)].append(item)
def add_creature(self, x, y, creature: Character) -> bool: def add_creature(self, x, y, creature: Creature) -> bool:
if (x, y) in self.pos_creatures: if (x, y) in self.pos_creatures:
return False return False
else: else:
@ -37,24 +40,27 @@ class EntityMap:
self.creatures_pos[creature] = (x, y) self.creatures_pos[creature] = (x, y)
return True return True
def pop_creature_pos(self, x, y) -> Character | None: def pop_creature_pos(self, x, y) -> Creature | None:
if (x, y) in self.pos_creatures: if (x, y) in self.pos_creatures:
creature = self.pos_creatures.pop((x, y)) creature = self.pos_creatures.pop((x, y))
self.creatures_pos.pop(creature) self.creatures_pos.pop(creature)
return creature return creature
def pop_creature_ref(self, creature: Character) -> Tuple[int, int] | None: def pop_creature_ref(self, creature: Creature) -> Tuple[int, int] | None:
if creature in self.creatures_pos: if creature in self.creatures_pos:
pos = self.creatures_pos.pop(creature) pos = self.creatures_pos.pop(creature)
self.pos_creatures.pop(pos) self.pos_creatures.pop(pos)
return pos return pos
class Floor: class Floor:
"""
A class that represents a specific floor of the dungeon
"""
def __init__(self, width, height): def __init__(self, width, height):
self.width = width self.width = width
self.height = height self.height = height
self.grid = [[TileType.AIR] * height] * width self.grid = [[TileType.AIR] * height] * width
self.entities = EntityMap() self.entities = EntityMap()
def get_tile(self, x, y): def get_tile(self, x, y) -> TileType:
return self.grid[x][y] return self.grid[x][y]

87
game.py
View File

@ -1,7 +1,8 @@
from terminal import Terminal from terminal import Terminal
from entity import Character, Player, Item, Enemy from entity import Creature, Player, Enemy
from actions import * from actions import *
from floor import Floor, TileType from floor import Floor, TileType
import sys
TEXTURES = { TEXTURES = {
TileType.WALL: '#', TileType.WALL: '#',
@ -17,34 +18,52 @@ class Game:
self.should_exit = False self.should_exit = False
self.ticks = 0 self.ticks = 0
self.schedule = {} self.schedule = {}
self.redirect_io('prints.log', 'errors.log')
def __del__(self):
self.restore_io()
def restore_io(self) -> None:
sys.stdout = self.stdout_original
sys.stderr = self.stderr_original
self.stdout_file.close()
self.stderr_file.close()
def redirect_io(self, stdout_file, stderr_file) -> None:
self.stdout_original = sys.stdout
self.stderr_original = sys.stderr
self.stdout_file = open(stdout_file, 'w')
self.stderr_file = open(stderr_file, 'w')
sys.stdout = self.stdout_file
sys.stderr = self.stderr_file
def run(self): def run(self):
""" """
Runs the game Runs the game
""" """
self.instance_character(3, 3, self.player) self.instance_creature(3, 3, self.player)
self.render() self.render()
while not self.should_exit: while not self.should_exit:
action_was_performed = self.step() self.step()
if action_was_performed: if self.action_was_performed:
self.render() self.render()
def instance_character(self, x, y, character: Character): def instance_creature(self, x, y, creature: Creature):
""" """
Instances a character in space and time Instances a creature in space and time
""" """
self.floor.entities.add_creature(x, y, character) self.floor.entities.add_creature(x, y, creature)
self.reschedule(character) self.reschedule(creature)
def reschedule(self, character: Character): def reschedule(self, creature: Creature):
""" """
Calculates turns for the next avaliable ticks untill player turn Calculates the ticks in which the creature will perform its next action
""" """
time = (action_timing[character.action.__class__] // character.speed) + self.ticks time = (ACTION_TIMING[creature.action.__class__] // creature.speed) + self.ticks
if self.schedule.get(time): if self.schedule.get(time):
self.schedule[time].append(character) self.schedule[time].append(creature)
else: else:
self.schedule[time] = [character] self.schedule[time] = [creature]
def render(self): def render(self):
""" """
@ -61,38 +80,34 @@ class Game:
def step(self): def step(self):
""" """
Perfoms a step in the game. Returns True if any creature did an action, and False otherwise Perfoms a step in the game. Sets the `action_was_performed` attribute accordingly
""" """
creaturas = self.schedule.get(self.ticks) self.action_was_performed = False
if creaturas: creatures = self.schedule.get(self.ticks)
for creatura in creaturas: if creatures:
if isinstance(creatura, Player): for creature in creatures:
self.get_event() if isinstance(creature, Player):
elif isinstance(creatura, Enemy): self.input_event()
creatura.calculate_action() elif isinstance(creature, Enemy):
self.reschedule(creatura) creature.calculate_action()
self.perform(creatura) self.reschedule(creature)
self.perform(creature)
self.schedule.pop(self.ticks) self.schedule.pop(self.ticks)
self.ticks += 1 self.action_was_performed = True
return True self.ticks += 1
else:
self.ticks += 1
return False
def perform(self, creature: Creature):
def perform(self, character: Character):
""" """
Performs an action for a creature Performs an action for a creature
""" """
if isinstance(character.action, Move): if isinstance(creature.action, Move):
pos = self.floor.entities.pop_creature_ref(character) pos = self.floor.entities.pop_creature_ref(creature)
if pos: if pos:
self.floor.entities.add_creature(pos[0] + character.action.x, pos[1] + character.action.y, character) self.floor.entities.add_creature(pos[0] + creature.action.x, pos[1] + creature.action.y, creature)
def input_event(self):
def get_event(self):
""" """
Waits for a game event to happen Waits for a game event to happen, and behaves accordingly
""" """
keycode = self.term.get_key() keycode = self.term.get_key()
if keycode == "q": if keycode == "q":

View File