commit 8c25b9759cf05f1d77cab1a3ddec66a9460d49ee
parent 68de58157df92d177f66cfdde80f4acac6ca7570
Author: Erik Letson <hmagellan@hmagellan.com>
Date: Mon, 14 Jun 2021 15:19:10 -0500
camera and overlays
Diffstat:
13 files changed, 95 insertions(+), 46 deletions(-)
diff --git a/data/boards/test_town/test_ow.tmx b/data/boards/test_ow/test_ow.tmx
diff --git a/data/boards/test_town/overlay.json b/data/boards/test_town/overlay.json
@@ -0,0 +1,7 @@
+{
+ "exits": {
+ "test_ow" : {
+ "north" : [ [3, 0], [4, 0], [5, 0] ]
+ }
+ }
+}
diff --git a/data/img/overlay.png b/data/img/overlay.png
Binary files differ.
diff --git a/data/json/sheets.json b/data/json/sheets.json
@@ -16,5 +16,17 @@
"dimensions" : [16, 16],
"anim_class" : null,
"alpha" : false
+ },
+ "locations1": {
+ "filename" : "locations1.png",
+ "dimensions" : [16, 16],
+ "anim_class" : null,
+ "alpha" : false
+ },
+ "overlay": {
+ "filename" : "overlay.png",
+ "dimensions" : [16, 16],
+ "anim_class" : null,
+ "alpha" : false
}
}
diff --git a/src/board.py b/src/board.py
@@ -26,32 +26,14 @@ class BoardManager(manager.Manager):
# Board values
self.current_board = None
- self.board_overlay = pygame.sprite.LayeredDirty()
def load_board(self, boardname):
"""
Load a given board.
"""
- # TODO: Bring this inline with loading in managers rather than in managed objects
self.current_board = Board(self, boardname)
- #self.load_overlay()
self.update(None)
- def load_overlay(self):
- """
- Derive an overlay from available loaded board. Calling
- this has the effect of refreshing the overlay.
- """
- self.board_overlay = pygame.sprite.LayeredDirty()
- for layer in self.current_board.tmx_data.visible_layers:
- if isinstance(layer, pytmx.TiledTileLayer):
- for x, y, gid in layer:
- if self.current_board.tmx_data.get_tile_properties_by_gid(gid)["Passable"] == 1:
- e = entity.Entity(self.system_bus.fetch("sheet_system", "sheets")["board_overlays_1"])
- e.set_position((x * self.current_board.tmx_data.tilewidth, y * self.current_board.tmx_data.tileheight))
- e.custom_flags = "OverlayGrid"
- self.board_overlay.add(e)
-
def get_tile_pos_at_position(self, pos):
"""
Return (x, y) tile_pos if there is a tile at 'pos', and
@@ -137,7 +119,6 @@ class BoardManager(manager.Manager):
"board_dimensions" : self.current_board.board_dimensions,
"board_pixel_dimensions" : self.current_board.pixel_dimensions,
"board_tile_layer" : { (x, y) : gid for layer in self.current_board.tmx_data.visible_layers for x, y, gid in layer if isinstance(layer, pytmx.TiledTileLayer) },
- "board_overlay" : self.board_overlay
}
self.bus.record(self.name, data)
@@ -147,7 +128,6 @@ class BoardManager(manager.Manager):
"""
if surface != None:
self.current_board.draw_board(surface)
- #self.board_overlay.update(surface)
############################
# Section 2 - Board Object #
diff --git a/src/bus.py b/src/bus.py
@@ -24,18 +24,20 @@ class Bus(subsystem.GameSubsystem):
# Collection of elements
self.elements = {}
+ self.collection = {}
- def enter_element(self, element_name):
+ def enter_element(self, element):
"""
Make an entry in the records for the given element. This
entry is checked for existence in many cases before doing
other things. This method should be called when an element
is created MOST OF THE TIME.
"""
- if element_name not in self.elements.keys():
- self.elements[element_name] = {} # Initial value is empty dict
+ if element.name not in self.elements.keys():
+ self.elements[element.name] = {} # Initial value is empty dict
+ self.collection[element.name] = element # Value is the element itself
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):
"""
@@ -73,9 +75,6 @@ class SystemBus(Bus):
# Parent init
super().__init__(game, name, bus)
- # Collection of systems
- self.elements = {}
-
def record(self, element_name, data):
"""
Record an entire subsystem into this bus.
@@ -107,6 +106,8 @@ class SystemBus(Bus):
self.elements[s].update_fetch_data()
# Performs: All callable non-return behaviors of subsystems.
+ def perform_camera_follow_entity(self, entity, force):
+ self.collection["camera"].follow_entity(entity, force)
####################################
# Section 3 - The ManagerBus class #
@@ -131,11 +132,6 @@ class ManagerBus(Bus):
# Parent init
super().__init__(game, name, bus)
- # Collection of managers
- self.elements = {}
- # TODO: Redundant? The wrong way to do this??
- self.managers = {}
-
# Recording
if self.bus != None:
self.bus.record(self.name, self)
@@ -177,11 +173,12 @@ class ManagerBus(Bus):
# check_for_* = return something else
# Performs: All callable non-return behaviors of managers.
+ # TODO: returning methods below need to be changed to checks
def perform_board_manager_get_tile_at_position(self, mousepos):
- return self.managers["board_manager"].get_tile_at_position(mousepos)
+ return self.collection["board_manager"].get_tile_at_position(mousepos)
def perform_board_manager_get_tile_at_tile_pos(self, tilepos):
- return self.managers["board_manager"].get_tile_at_tile_pos(tilepos)
+ return self.collection["board_manager"].get_tile_at_tile_pos(tilepos)
def perform_board_manager_get_board_tile_properties_by_tile_gid(self, gid):
- return self.managers["board_manager"].get_board_tile_properties_by_tile_gid(gid)
+ return self.collection["board_manager"].get_board_tile_properties_by_tile_gid(gid)
def perform_entity_manager_move_player(self, tile_offset):
- self.managers["entity_manager"].move_player_by_tile_offset(tile_offset)
+ self.collection["entity_manager"].move_player_by_tile_offset(tile_offset)
diff --git a/src/camera.py b/src/camera.py
@@ -31,21 +31,23 @@ 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
self.camera_surface_base_dimensions = (0, 0)
+ self.follow = False
# Recording
if self.bus != None:
self.bus.record(self.name, self)
- def load_camera_surface(self, dimensions, init_offset = (0, 0)):
+ def load_camera_surface(self, dimensions, follow = False, init_offset = (0, 0)):
"""
Load up the camera surface as a new PyGame
surface object of the necessary size. Also
resets the camera offset.
"""
- self.camera_surface = pygame.Surface(dimensions).convert()
+ self.camera_surface_base_dimensions = dimensions
+ self.camera_surface = pygame.Surface(self.camera_surface_base_dimensions).convert()
self.camera_surface_rect = self.camera_surface.get_rect()
self.camera_surface_offset = init_offset
- self.camera_surface_base_dimensions = dimensions
+ self.follow = follow
def move_offset(self, rel_offset, speed_multiple = 1):
"""
@@ -75,6 +77,16 @@ class GameCamera(subsystem.GameSubsystem):
"""
self.camera_surface_offset = ((SCREEN_WIDTH / 2) - position[0], (SCREEN_HEIGHT / 2) - position[1])
+ def follow_entity(self, entity, force = False):
+ """
+ Snap the camera to the location of a given
+ entity. The 'force' bool indicates whether
+ this snap should happen even if self.follow
+ is false.
+ """
+ if force or self.follow:
+ self.snap_to_position((entity.rect.center[0] * TILE_SCALE_FACTOR, entity.rect.center[1] * TILE_SCALE_FACTOR))
+
def update_camera(self, surface = None):
"""
Update and draw the camera contents.
diff --git a/src/entity.py b/src/entity.py
@@ -33,6 +33,7 @@ class EntityManager(manager.Manager):
# Other values
self.player = None
+ self.board_overlay = None
def load_board_entities_from_file(self, current_board_name):
"""
@@ -53,8 +54,29 @@ class EntityManager(manager.Manager):
self.player = PlayerEntity(sh["chars1"], (0, 0))
self.player.assign_tile(tuple(ent_def[e]["location"]), self.bus.perform_board_manager_get_tile_at_tile_pos(tuple(ent_def[e]["location"]))[2])
self.player.snap_to_tile()
+ self.system_bus.perform_camera_follow_entity(self.player, False)
self.draw_group.add(self.player)
+ def load_board_overlay_from_file(self, current_board_name):
+ """
+ Load an overlay from file.
+ """
+ # Load the overlay file
+ with open(os.path.join(BOARD_PATH, current_board_name, "overlay.json")) as f: overlay_data = json.load(f)
+
+ # Populate the overlay
+ self.board_overlay = pygame.sprite.LayeredDirty()
+ sh = self.system_bus.fetch("sheet_system", "sheets")
+ for oc in overlay_data:
+ if oc == "exits":
+ for t in overlay_data[oc]:
+ for o in overlay_data[oc][t]:
+ for oo in overlay_data[oc][t][o]:
+ noe = OverlayEntity(sh["overlay"], (0, 0), None, False, "exit_" + t)
+ noe.assign_tile(tuple(oo), self.bus.perform_board_manager_get_tile_at_tile_pos(tuple(oo)))
+ noe.snap_to_tile()
+ self.board_overlay.add(noe)
+
def move_player_by_tile_offset(self, tile_offset):
"""
Move a player entity by relative tile offset.
@@ -64,6 +86,7 @@ class EntityManager(manager.Manager):
if t != None and self.bus.perform_board_manager_get_board_tile_properties_by_tile_gid(t[2])["Passable"]:
self.player.assign_tile((t[0], t[1]), t[2])
self.player.snap_to_tile()
+ self.system_bus.perform_camera_follow_entity(self.player, False)
def update_managed(self, surface = None):
"""
@@ -71,6 +94,7 @@ class EntityManager(manager.Manager):
"""
if surface != None:
self.draw_group.update(surface)
+ self.board_overlay.update(surface)
############################
# Section 2 - Entity class #
@@ -276,3 +300,17 @@ class PlayerEntity(Entity):
# Parent initialization
super().__init__(sheet, sprite, animation, animated)
+
+class OverlayEntity(Entity):
+ """
+ Class representing the transparent overlay entities
+ that are drawn on the board to represent map exits
+ and other features.
+ """
+
+ def __init__(self, sheet, sprite = (0, 0), animation = None, animated = False, ov_type = None):
+
+ # Parent initialization
+ super().__init__(sheet, sprite, animation, animated)
+
+ self.overlay_type = ov_type
diff --git a/src/envvars.py b/src/envvars.py
@@ -47,6 +47,12 @@ CTRL_MODES = enum.Enum('CTRL_MODES', 'No_Control Main_Menu_Normal')
GAME_EFFECTS = enum.Enum('GAME_EFFECTS', 'ef_game_dummy ef_game_quit ef_game_switch_mode ef_game_switch_control')
TEAMS = enum.Enum('TEAMS', 'Player Ally Neutral Enemy Other')
+# Enum collections
+OVERHEAD_MODES = [
+ STATE_MODES.Overworld_Mode,
+ STATE_MODES.Location_Mode
+]
+
# Initial state
STARTING_STATE_MODE = STATE_MODES.Location_Mode
STARTING_BOARD = "test_town"
diff --git a/src/game.py b/src/game.py
@@ -70,8 +70,9 @@ class Game(object):
# State-specific logic
if new_mode == STATE_MODES.Location_Mode:
self.board_manager.load_board(data["boardname"])
+ self.camera.load_camera_surface(VIEWPORT_SIZE, True)
self.entity_manager.load_board_entities_from_file(data["boardname"])
- self.camera.load_camera_surface(VIEWPORT_SIZE)
+ self.entity_manager.load_board_overlay_from_file(data["boardname"])
def shift_frames(self, framerate = FRAMERATE):
"""
diff --git a/src/interface.py b/src/interface.py
@@ -81,7 +81,7 @@ class GameInterface(subsystem.GameSubsystem):
of keys on a mode-by-mode basis. Called during
update.
"""
- if self.game.state_mode == STATE_MODES.Location_Mode:
+ if self.game.state_mode in OVERHEAD_MODES:
if self.key_bools[pygame.K_w]:
self.manager_bus.perform_entity_manager_move_player((0, -1))
self.key_bools[pygame.K_w] = False
diff --git a/src/manager.py b/src/manager.py
@@ -54,10 +54,6 @@ class Manager(subsystem.GameSubsystem):
self._activated = True
self._effectual = False
- # Managers should record themselves in the manager bus for performs
- # TODO: Redundant? The wrong way to do this??
- self.bus.managers[self.name] = self
-
def expose(self):
"""
Expose info about this object to the ManagerBus
diff --git a/src/subsystem.py b/src/subsystem.py
@@ -49,7 +49,7 @@ class GameSubsystem(object):
purposes.
"""
if bus != None:
- bus.enter_element(self.name)
+ bus.enter_element(self)
def update_fetch_data(self):
"""