Return to repo list

tzed

Simple story-driven open world 2D CRPG.
Return to HMagellan.com

commit 058bfaba5be555d04f8c47dea9791b01652908d2
parent 97aa01927c376551006de3134a875ea450857e6f
Author: Erik Letson <hmagellan@hmagellan.com>
Date:   Sat,  5 Jun 2021 22:51:57 -0500

added boards

Diffstat:
Asrc/board.py | 179+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/entity.py | 2+-
Msrc/envvars.py | 1+
Msrc/game.py | 3++-
4 files changed, 183 insertions(+), 2 deletions(-)

diff --git a/src/board.py b/src/board.py @@ -0,0 +1,179 @@ +import pygame, pytmx, os +from . import manager, entity +from .envvars import * + +############ +# board.py # +############ + +# This file contains: +# 1. The BoardManager class, which manages boards and swaps between them +# 2. The Board class, which represents a grid of Tile objects and is the play area + +################################### +# Section 1 - BoardManager Object # +################################### + +class BoardManager(manager.Manager): + """ + BoardManager handles loading and managing Board objects. It + is directly subordinate to Game. + """ + + def __init__(self, game, name, bus, system_bus): + + super().__init__(game, name, bus, system_bus) + + # 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.bus.fetch("sheet_manager", "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 + return None otherwise. + """ + w = self.current_board.tmx_data.tilewidth + h = self.current_board.tmx_data.tileheight + for layer in self.current_board.tmx_data.visible_layers: + if isinstance(layer, pytmx.TiledTileLayer): + for x, y, gid in layer: + if pos[0] >= x * w and pos[0] < (x + 1) * w and pos[1] >= y * w and pos[1] < (y + 1) * w: + return (x, y) + return None + + def get_tile_at_position(self, pos): + """ + Return (x, y, gid) if there is tile at 'pos', and return + None otherwise. + """ + w = self.current_board.tmx_data.tilewidth + h = self.current_board.tmx_data.tileheight + for layer in self.current_board.tmx_data.visible_layers: + if isinstance(layer, pytmx.TiledTileLayer): + for x, y, gid in layer: + if pos[0] >= x * w and pos[0] < (x + 1) * w and pos[1] >= y * w and pos[1] < (y + 1) * w: + return (x, y, gid) + return None + + def get_tile_at_tile_pos(self, tile_pos): + """ + Return (x, y, gid) if there is a tile at tile_pos 'tile_pos', + and return None otherwise. + """ + for layer in self.current_board.tmx_data.visible_layers: + if isinstance(layer, pytmx.TiledTileLayer): + for x, y, gid in layer: + if tile_pos == (x, y): + return (x, y, gid) + return None + + def get_adjacent_tiles_by_tile_pos(self, tile_pos): + """ + Return cardinal adjacent tiles of the given tile_pos. + Return value is a dict, the values of which are either + (x, y) tuples or None if the adjacent is outside of the + bounds of the board. + """ + adj = {(-1, 0) : None, (1, 0) : None, (0, -1) : None, (0, 1): None} + mx = 0 + my = 0 + for x in range(0, self.current_board.tmx_data.width): + for y in range(0, self.current_board.tmx_data.height): + mx = tile_pos[0] - x + my = tile_pos[1] - y + if (mx, my) in adj.keys(): + adj[(mx, my)] = (x, y) + return adj + + def get_adjacency_list(self, tiles): + """ + Return an adjaceny list of all the tiles included + in 'tiles'. Tiles should be a list or tuple. The + return value is a dict. + """ + adj_list = {} + for t in tiles: + adj_list[t] = self.get_adjacent_tiles_by_tile_pos(t) + return adj_list + + def expose(self): + """ + Expose info about the board to the ManagerBus. + """ + data = { + "current_board" : self.current_board, + "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) + + def update_managed(self, surface = None): + """ + Update the current board. + """ + if surface != None: + self.current_board.draw_board(surface) + self.board_overlay.update(surface) + +############################ +# Section 2 - Board Object # +############################ + +class Board(object): + """ + Board is an object that consists of a Pytmx Tiled map and + some functions for drawing it. Board is managed by a + BoardManager object. + """ + + def __init__(self, manager, boardname): + + # Saved values + self.manager = manager + self.boardname = boardname + self.filename = boardname + ".tmx" + + # Pytmx values + self.tmx_data = pytmx.load_pygame(os.path.join(BOARD_PATH, self.boardname, self.filename)) + self.board_dimensions = (self.tmx_data.width, self.tmx_data.height) + self.pixel_dimensions = (self.tmx_data.width * TILE_WIDTH, self.tmx_data.height * TILE_HEIGHT) + + def draw_board(self, surface = None): + """ + Draw the tiles of the board onto the provided PyGame + surface object. + """ + for layer in self.tmx_data.visible_layers: + if isinstance(layer, pytmx.TiledTileLayer): + for x, y, gid in layer: + t = self.tmx_data.get_tile_image_by_gid(gid) + if t: + surface.blit(t, (x * TILE_HEIGHT, y * TILE_WIDTH)) + diff --git a/src/entity.py b/src/entity.py @@ -121,7 +121,7 @@ class Entity(pygame.sprite.DirtySprite): def set_flip(self, hz = None, vt = None): """ - Set the flip tuple valse to True or False. hz is for horizontal + Set the flip tuple values to True or False. hz is for horizontal flipping and vt is vertical. If either is None, that value will not be changed. """ diff --git a/src/envvars.py b/src/envvars.py @@ -30,6 +30,7 @@ IMAGE_PATH = os.path.join(DATA_PATH, "img") SOUND_PATH = os.path.join(DATA_PATH, "snd") FONT_PATH = os.path.join(DATA_PATH, "font") TILE_PATH = os.path.join(DATA_PATH, "tsx") +BOARD_PATH = os.path.join(DATA_PATH, "boards") JSON_PATH = os.path.join(DATA_PATH, "json") SAVE_PATH = os.path.join(str(pathlib.Path.home), ".local", "share", "heart-of-gold", "savegames") diff --git a/src/game.py b/src/game.py @@ -1,5 +1,5 @@ import pygame -from . import interface, bus, camera, sound, images +from . import interface, bus, camera, sound, images, board from .envvars import * ########### @@ -39,6 +39,7 @@ class Game(object): self.interface = interface.GameInterface(self, "interface", self.subsystem_bus, self.manager_bus) # Managers + self.board_manager = board.BoardManager(self, "board_manager", self.manager_bus, self.subsystem_bus) # Setup (This is WIP) #self.sheet_system.load_animations_from_json("anims.json")