tzed

Simple story-driven open world 2D CRPG.
Log | Files | Refs | README | LICENSE

commit 97aa01927c376551006de3134a875ea450857e6f
parent 073889e774ef6fb9084515296c89e351bec55c9d
Author: Erik Letson <hmagellan@hmagellan.com>
Date:   Sat,  5 Jun 2021 14:02:56 -0500

engine working

Diffstat:
Msrc/bus.py | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
Msrc/camera.py | 13++++++++++++-
Msrc/entity.py | 2+-
Msrc/game.py | 45+++++++++++++++++++++++++++++++++++++++------
Msrc/images.py | 46++++++++++++++++++++++------------------------
Msrc/interface.py | 6+++++-
Msrc/sound.py | 12+++++++++++-
Msrc/subsystem.py | 12++++++++++++
8 files changed, 168 insertions(+), 51 deletions(-)

diff --git a/src/bus.py b/src/bus.py @@ -35,20 +35,22 @@ class Bus(subsystem.GameSubsystem): if element_name not in self.elements.keys(): self.elements[element_name] = {} # Initial value is empty dict else: - raise GameBusError(self.name + "BUS SAYS: " + element_name + " already in records!") + raise GameBusError(self.name + " BUS SAYS: " + element_name + " already in records!") def record(self, element_name, data): """ - Record some data about a given element, as long as it has - already been entered in the records. + Abstract record method to be overwritten. Different busses + maintain different data (and kinds of data) in their element + dicts. """ - if element_name in self.elements.keys(): - if type(data) == dict: - self.elements[element_name] = data - else: - raise GameBusError("BUS SAYS: Provided data: " + data + " from " + element_name + " not dict type!") - else: - raise GameBusError("BUS SAYS: " + element_name + " not in records! Unable to record data!") + pass + + def fetch(self, element_name, value): + """ + Abstract fetch method to be overwritten. Different busses + will handle fetches differently. + """ + pass ################################### # Section 2 - The SystemBus class # @@ -74,6 +76,36 @@ class SystemBus(Bus): # Collection of systems self.elements = {} + def record(self, element_name, data): + """ + Record an entire subsystem into this bus. + """ + if element_name in self.elements.keys(): + self.elements[element_name] = data + else: + raise GameBusError(self.name + " BUS SAYS: " + element_name + " not in records! Unable to record data!") + + def fetch(self, element_name, value): + """ + Fetch data from game subsystems. Subsystems do not + frequently update their fetch values. + """ + if element_name in self.elements.keys(): + if value in self.elements[element_name].fetch_data.keys(): + return self.elements[element_name].fetch_data[value] + else: + raise GameBusError(self.name + " BUS SAYS: " + value + " not in fetch data of " + element_name + "! Unable to fetch!") + else: + raise GameBusError(self.name + " BUS SAYS: " + element_name + " not in records! Unable to fetch data!") + + def update_system_fetch_data(self): + """ + Update the fetch data for each system in this bus's + records. + """ + for s in self.elements: + self.elements[s].update_fetch_data() + # Performs: All callable non-return behaviors of subsystems. #################################### @@ -102,20 +134,37 @@ class ManagerBus(Bus): # Collection of managers self.elements = {} - def fetch(self, element, value): + # Recording + if self.bus != None: + self.bus.record(self.name, self) + + def record(self, element_name, data): + """ + Record some data about a given element, as long as it has + already been entered in the records. + """ + if element_name in self.elements.keys(): + if type(data) == dict: + self.elements[element_name] = data + else: + raise GameBusError(self.name + " BUS SAYS: Provided data: " + data + " from " + element_name + " not dict type!") + else: + raise GameBusError(self.name + " BUS SAYS: " + element_name + " not in records! Unable to record data!") + + def fetch(self, element_name, value): """ Fetch a given value from a manager. Refers to the bus's internal records of current object values, updated by the manager itself via the "expose()" functionality of the manager - objects. + objects. These records are updated frequently. """ - if element in self.records.keys(): - if value in self.records[manager].keys(): - return self.records[manager][value] + if element_name in self.elements.keys(): + if value in self.elements[element_name].keys(): + return self.elements[element_name][value] else: - raise GameBusError("BUS SAYS: " + value + " not in " + manager + " data record!") + raise GameBusError(self.name + " BUS SAYS: " + value + " not in " + element_name + " data record!") else: - raise GameBusError("BUS SAYS: " + manager + " not in records! Unable to fetch data!") + raise GameBusError(self.name + " BUS SAYS: " + element_name + " not in records! Unable to fetch data!") # Checks: Computes & returns handled partially by Bus itself. # Checks are basically the halfway between fetches and performs, diff --git a/src/camera.py b/src/camera.py @@ -1,6 +1,6 @@ import pygame from . import subsystem -from .envvar import * +from .envvars import * ############# # camera.py # @@ -31,6 +31,10 @@ class GameCamera(subsystem.GameSubsystem): self.camera_surface_rect = self.camera_surface.get_rect() self.camera_surface_offset = (0, 0) # The rect topleft is never changed; rather, this value is used by game to draw the camera surface at an offset + # Recording + if self.bus != None: + self.bus.record(self.name, self) + def load_camera_surface(self, dimensions, init_offset = (0, 0)): """ Load up the camera surface as a new PyGame @@ -76,3 +80,10 @@ class GameCamera(subsystem.GameSubsystem): if surface != None: surface.blit(self.camera_surface, self.camera_surface_offset) + def update_fetch_data(self): + """ + Update available fetch data. + """ + self.fetch_data["camera_surface"] = self.camera_surface + self.fetch_data["camera_surface_rect"] = self.camera_surface_rect + self.fetch_data["camera_surface_offset"] = self.camera_surface_offset diff --git a/src/entity.py b/src/entity.py @@ -1,6 +1,6 @@ import pygame, json, os from . import manager -from .constants import * +from .envvars import * ############# # entity.py # diff --git a/src/game.py b/src/game.py @@ -1,5 +1,5 @@ import pygame -from . import interface, bus, camera +from . import interface, bus, camera, sound, images from .envvars import * ########### @@ -31,10 +31,40 @@ class Game(object): self.frame_clock = pygame.time.Clock() # Subsystem objects - self.subsystem_bus = bus.SystemBus(self) - self.manager_bus = bus.ManagerBus(self) - self.camera = camera.Camera(self) - self.interface = interface.GameInterface(self, self.manager_bus, self.subsystem_bus) + self.subsystem_bus = bus.SystemBus(self, "subsystem_bus", None) + self.manager_bus = bus.ManagerBus(self, "manager_bus", self.subsystem_bus) + self.camera = camera.GameCamera(self, "camera", self.subsystem_bus) + self.sound_system = sound.SoundSystem(self, "sound_system", self.subsystem_bus) + self.sheet_system = images.SheetSystem(self, "sheet_system", self.subsystem_bus) + self.interface = interface.GameInterface(self, "interface", self.subsystem_bus, self.manager_bus) + + # Managers + + # Setup (This is WIP) + #self.sheet_system.load_animations_from_json("anims.json") + #self.sheet_system.load_sheets_from_json("sheets.json") + #self.sound_system.load_sounds_from_json("sounds.json") + self.subsystem_bus.update_system_fetch_data() + + # Switch to game control + self.switch_mode(STATE_MODES.Main_Menu_Mode) + + def switch_mode(self, new_mode, data = None): + """ + Change the current state_mode, as well as load up + the elements of the new mode. This large method + should take account of every possible mode in the + game. Such a structure has no reason to exists e.g. + as a JSON file. The 'data' option contains the info + needed as part of a mode switch. This method handles + a change even if data is None. + """ + if new_mode == None: + return + else: + self.state_mode = new_mode + + # TODO: Mode-specific switch logic def shift_frames(self, framerate = FRAMERATE): """ @@ -48,10 +78,12 @@ class Game(object): Update the game elements, the screen, and any other objects. """ - # First, fill the screen self.screen.fill((0, 0, 0)) + # Next, update the interface + self.interface.update_interface() + # Last, update the screen pygame.display.update() @@ -68,5 +100,6 @@ class Game(object): """ while self.on: self.shift_frames() + self.interface.handle_events(pygame.event.get()) self.update_game() pygame.quit() diff --git a/src/images.py b/src/images.py @@ -1,5 +1,5 @@ import pygame, os, json -from . import manager +from . import subsystem from .envvars import * ############# @@ -7,24 +7,24 @@ from .envvars import * ############# # This file contains: -# 1. The 'SheetManager' class, which is a Manager object that handles sheets (e.g. loading) -# 2. The 'Sheet' class, which is used to represent enumerated spritesheets +# 1. The SheetSystem class, which is a Manager object that handles sheets (e.g. loading) +# 2. The Sheet class, which is used to represent enumerated spritesheets -################################### -# Section 2 - SheetManager Object # -################################### +###################################### +# Section 1 - The SheetSystem Object # +###################################### -class SheetManager(manager.Manager): +class SheetSystem(subsystem.GameSubsystem): """ - SheetManager handles loading and managing sheets. It is - talked to in order to get loaded sheets. SheetManager also + SheetSystem handles loading and managing sheets. It is + talked to in order to get loaded sheets. Sheetsystem also knows all animations and is talked to to get info about them. """ - def __init__(self, game, bus, camera, name): + def __init__(self, game, name, bus): - super().__init__(game, bus, camera, name) + super().__init__(game, name, bus) # Important values self.sheets_def = {} @@ -32,8 +32,9 @@ class SheetManager(manager.Manager): self.anims_def = {} self.animations = {} - # This manager should perform an initial update - self.update(None) + # Recording + if self.bus != None: + self.bus.record(self.name, self) def load_sheets_from_json(self, sheet_json): """ @@ -82,19 +83,16 @@ class SheetManager(manager.Manager): if name in self.loaded_sheets.keys(): return self.loaded_sheets[name] - def expose(self): + def update_fetch_data(self): """ - Expose sheet info to the ManagerBus. + Update available fetch data. """ - data = { - "sheets" : self.loaded_sheets, - "animations" : self.animations - } - self.bus.record(self.name, data) - -############################ -# Section 3 - Sheet Object # -############################ + self.fetch_data["sheets"] = self.loaded_sheets + self.fetch_data["animations"] = self.animations + +################################ +# Section 2 - The Sheet Object # +################################ class Sheet(object): """ diff --git a/src/interface.py b/src/interface.py @@ -39,8 +39,12 @@ class GameInterface(subsystem.GameSubsystem): self.right_double_click_timer = 0 self.right_double_click_mousepos = None self.old_mousepos = None - self.key_bools = [ False for k in range(0, 350) ] + self.key_bools = [False for k in range(0, 350)] + # Recording + if self.bus != None: + self.bus.record(self.name, self) + def handle_events(self, events): """ Handle any kind of PyGame event and react appropriately. diff --git a/src/sound.py b/src/sound.py @@ -1,6 +1,6 @@ import pygame, os, json from . import subsystem -from .constants import * +from .envvars import * ############ # sound.py # @@ -28,6 +28,10 @@ class SoundSystem(subsystem.GameSubsystem): self.sounds = {} self.channels = [pygame.mixer.Channel(x) for x in range(0, pygame.mixer.get_num_channels() - 1)] + # Recording + if self.bus != None: + self.bus.record(self.name, self) + def load_sounds_from_json(self, soundjson): """ Load up sounds from a definition JSON @@ -58,3 +62,9 @@ class SoundSystem(subsystem.GameSubsystem): elif concurrent or self.sounds[soundname].get_num_channels() == 0: self.sounds[soundname].play() + def update_fetch_data(self): + """ + Update available fetch data. + """ + self.fetch_data["sounds"] = self.sounds + self.fetch_data["channels"] = self.channels diff --git a/src/subsystem.py b/src/subsystem.py @@ -34,10 +34,13 @@ class GameSubsystem(object): def __init__(self, game, name, bus = None): + # Important values self.game = game self.name = name self.bus = bus + # Bus values + self.fetch_data = {} self.record_self(bus) def record_self(self, bus = None): @@ -48,6 +51,12 @@ class GameSubsystem(object): if bus != None: bus.enter_element(self.name) + def update_fetch_data(self): + """ + Abstract method to be overwritten in child objects. + """ + pass + #################################### # Section 2 - The SaveSystem class # #################################### @@ -71,6 +80,9 @@ class SaveSystem(GameSubsystem): # Environment self.active_save_env = {} + # Recording + self.record(self.name, self) + def save_to_file(self, filename): # TODO: Check if it exists and prompt to overwrite (maybe in a another object???) # TODO: Make cross-platform compatible