commit 92e8b7ff43a46d685b01b3f7bb2829256f8b59c0
parent b228ff7994da8a1d0153836065223a3bc19de50d
Author: Erik Letson <hmagellan@hmagellan.com>
Date: Tue, 3 Nov 2020 17:59:15 -0600
Refactor checkpoint 1, as-of-yet non-functional
Diffstat:
5 files changed, 365 insertions(+), 346 deletions(-)
diff --git a/src/board.py b/src/board.py
@@ -41,7 +41,6 @@ class BoardManager(manager.Manager):
self.current_board_dimensions = (0, 0)
# Move values
- self.moving_entity = None
self.move_targets = {} # Keys = (x, y) of tiles, vals are a list of (x, y) tuples representing the path to be taken
self.previous_moves = {} # Keys = (x, y) of tiles, vals are the (x, y) of the previous node
@@ -134,22 +133,21 @@ class BoardManager(manager.Manager):
self.load_overlay()
# TEMP!!!!
- self.create_move_range(self.game.entity_manager.selected_entity)
+ self.create_move_range(self.game.piece_manager.selected_piece)
for t in self.move_targets:
v = vgo.VisibleGameObject(self.game.sheet_manager.loaded_sheets["board_overlays_1"], (1, 0))
v.set_position((t[0] * self.current_board.tmx_data.tilewidth, t[1] * self.current_board.tmx_data.tileheight))
v.custom_flags = ("OverlayMove", t)
self.board_overlay.add(v)
- def create_move_range(self, entity):
+ def create_move_range(self, piece):
"""
- Create a legal move range for the given entity
- and set that entity as the moving entity. This
- is mostly a subtractive process.
+ Create a legal move range for the given piece.
+ This is mostly a subtractive process.
"""
# Setup
self.empty_move_range()
- movemax = entity.unit.active_stats["MOVE"]
+ movemax = piece.active_stats["MOVE"]
mx = 0
my = 0
distances = {}
@@ -164,16 +162,16 @@ class BoardManager(manager.Manager):
for layer in self.current_board.tmx_data.visible_layers:
if isinstance(layer, pytmx.TiledTileLayer):
for x, y, gid in layer:
- mx = entity.tile_pos[0] - x
- my = entity.tile_pos[1] - y
+ mx = piece.tile_pos[0] - x
+ my = piece.tile_pos[1] - y
if (abs(mx) + abs(my)) <= movemax and self.current_board.tmx_data.get_tile_properties_by_gid(gid)["Passable"] == 1:
distances[(x, y)] = movemax + 1 # So we are always greater than the max move
# Next, calculate the move from the starting pos to each potential
# This implements Dijkstra's algorithm (kinda)
- distances[entity.tile_pos] = 0
+ distances[piece.tile_pos] = 0
adj_list = self.get_adjacency_list(list(distances.keys()))
- pq.put((entity.tile_pos, 0))
+ pq.put((piece.tile_pos, 0))
# While there are still potentials to check
while not pq.empty():
@@ -247,7 +245,6 @@ class BoardManager(manager.Manager):
"""
Reset to a default, non-moving state.
"""
- self.moving_entity = None
self.move_targets = {}
self.previous_moves = {}
diff --git a/src/game.py b/src/game.py
@@ -1,5 +1,5 @@
import pygame
-from . import subsystem, manager, images, sound, board, vgo, unit, menu, scene
+from . import subsystem, manager, images, sound, board, vgo, piece, unit, menu, scene
from .constants import *
###########
@@ -49,7 +49,8 @@ class Game(object):
self.sound_manager = sound.SoundManager(self, self.manager_bus)
self.menu_manager = menu.MenuManager(self, self.manager_bus)
self.board_manager = board.BoardManager(self, self.manager_bus)
- self.entity_manager = vgo.EntityManager(self, self.manager_bus)
+ #self.entity_manager = vgo.EntityManager(self, self.manager_bus)
+ self.piece_manager = piece.PieceManager(self, self.manager_bus)
self.unit_manager = unit.UnitManager(self, self.manager_bus)
self.scene_manager = scene.SceneManager(self, self.manager_bus)
@@ -134,7 +135,8 @@ class Game(object):
self.menu_manager.update_current_menu(self.camera.camera_surface)
elif self.state_mode == STATE_MODES.Battle_Mode:
self.board_manager.update_board(self.camera.camera_surface)
- self.entity_manager.update_entities(self.camera.camera_surface)
+ self.piece_manager.update_entities(self.camera.camera_surface)
+ self.piece_manager.update_tile_cursor(self.camera.camera_surface)
# NOTE: MenuManager should not be an overlay for the
# battle mode. In-battle menus should be handled
# by EntityManager most likely
diff --git a/src/piece.py b/src/piece.py
@@ -1,4 +1,4 @@
-import pygame, os
+import pygame, os, json
from . import manager, unit
from .constants import *
@@ -9,11 +9,316 @@ from .constants import *
# This file contains the following:
# 1. The PieceManager object, which manages pieces on the game board
# 2. The Piece entity child object, which represents a piece on the game board
+# 3. The TileCursor entity child object, which acts as a cursor on the board and is managed by PieceManager
######################################
# Section 1 - The PieceManager class #
######################################
+class PieceManager(manager.Manager):
+ """
+ PieceManager acts as a manager for all Pieces (Entities
+ representing playable characters on the game board), as
+ well as for the TileCursor object that is used to interact
+ with units and tiles.
+ """
+
+ def __init__(self, game, bus):
+
+ # Parent initialization
+ super().__init__(game, bus)
+
+ # Entity values
+ self.pieces = pygame.sprite.LayeredDirty()
+ self.selected_piece = None
+
+ # Cursor values
+ self.tile_cursor = None
+
+ def add_piece(self, piece):
+ """
+ Add an piece to the pieces group.
+ """
+ self.pieces.add(piece)
+
+ def load_pieces_from_def(self, definition):
+ """
+ Loaded one or more pieces from a definition
+ dictionary. A piece definition is a subcomponent
+ of a larger definition dict, likely loaded from
+ JSON.
+ """
+ # TODO: There could be some type-checking for a valid definition
+ # here. This should probably be so for all methods that load
+ # from definition.
+ for p in definition:
+ n_sheet = self.bus.fetch_sheet(definition[p]["sheet"])
+ n_sprite = tuple(definition[p]["sprite"])
+ n_anim = self.bus.fetch_animation(n_sheet, definition[p]["animation"])
+ n_animated = definition[p]["animated"]
+ n_name = definition[p]["name"]
+ n_passable = definition[p]["passable"]
+ n_nstats = definition[p]["normal_stats"]
+ n_astats = definition[p]["active_stats"]
+ n_team = definition[p]["team"]
+ # TODO: ID needs fixing
+ self.add_piece(Piece(n_sheet, n_sprite, n_anim, n_animated, n_name, n_passable, n_nstats, n_astats, n_team))
+
+ def load_tile_cursor(self, sheet):
+ """
+ Load a TileCursor object to highlight selected tiles.
+ """
+ self.tile_cursor = TileCursor("Tile_Cursor", self.total_entities, self.bus.fetch_sheet(sheet))
+ self.tile_cursor.set_animation(self.bus.fetch_animation("cursor1", "pulse"), True)
+
+ def get_piece_by_name(self, name):
+ """
+ Returns a piece matching name, or None if no such piece
+ is found.
+ """
+ piece = None
+ for p in self.pieces:
+ if p.name == name
+ piece = p
+ break
+ return piece
+
+ def get_piece_by_tile(self, tile_pos):
+ """
+ Return the first piece found that is located at tile_pos,
+ or None if no piece is found.
+ """
+ found_piece = None
+ for p in self.pieces:
+ if p.tile_pos == (tile_pos[0], tile_pos[1]):
+ found_piece = p
+ return found_piece
+
+ def position_tile_cursor(self, tile_pos):
+ """
+ Snap the TileCursor object's position to 'tile_pos' and set
+ the tile GID there as the current tile_cursor's selected tile.
+ """
+ self.tile_cursor.assign_tile(tile_pos)
+ self.tile_cursor.snap_to_tile()
+
+ def select_piece_with_tile_cursor(self):
+ """
+ Select the piece under the tile cursor right now. If
+ no piece is under the tile cursor, the selected piece
+ should become None.
+ """
+ # TODO: This could stand to be more robust
+ self.selected_piece = self.get_piece_by_tile(self.tile_cursor.tile_pos)
+
+ def update_tile_cursor(self, surface = None):
+ """
+ Update the tile cursor object.
+ """
+ if surface != None:
+ self.tile_cursor.update(surface)
+
+ def update_pieces(self, surface = None):
+ """
+ Update all pieces.
+ """
+ if surface != None:
+ self.pieces.update(surface)
+
+ #def load_pieces_from_json(self, entsjson):
+ # """
+ # Load one or more pieces from a JSON file.
+ # """
+ # j = json.load(open(os.path.join(ENTITY_JSON_PATH, entsjson)))
+ # for e in j:
+ # # TODO: type should be enum
+ # if j[e]["type"] == "Entity":
+ # ne = Entity(j[e]["name"], 0,
+ # self.game.sheet_manager.loaded_sheets[j[e]["sheet"]], tuple(j[e]["sprite"]),
+ # self.game.sheet_manager.animations[j[e]["sheet"]][j[e]["animation"]],
+ # j[e]["animated"], j[e]["passable"], unit.Unit(self, self.game.unit_manager.get_stats(j[e]["name"])))
+ # elif j[e]["type"] == "Piece":
+ # ne = Piece(j[e]["name"], 0,
+ # self.game.sheet_manager.loaded_sheets[j[e]["sheet"]], tuple(j[e]["sprite"]),
+ # self.game.sheet_manager.animations[j[e]["sheet"]][j[e]["animation"]],
+ # j[e]["animated"], j[e]["passable"], unit.Unit(self, self.game.unit_manager.get_stats(j[e]["name"])),
+ # j[e]["team"])
+ # self.pieces.append(ne)
+ # ne.assign_tile(self.game.board_manager.get_tile_at_tile_pos(tuple(j[e]["tile"])))
+ # ne.snap_to_tile()
+ # self.add_entity(ne)
+
+ #def set_entity_move_to_tile_path(self, entity, path):
+ # """
+ # Assigns a path to the selected entity.
+ # """
+ # if entity != None and path != None:
+ # entity.set_move_along_tile_path(path)
+ # return True
+ # else:
+ # return False
+
+ #def set_entity_move_to_tile_pos(self, entity, tile_pos):
+ # """
+ # Sets the entity to move to the given tile_pos. A 'move'
+ # is an assignment from the EntityManager. A 'motion' is
+ # a setting similar to an animation (but for spatial travel)
+ # for an entity.
+ # """
+ # # TODO: Set speed of motion somehow, maybe calculated from MOVE of entity
+ # if entity != None and tile_pos != None:
+ # entity.set_motion((tile_pos[0] * self.game.board_manager.current_board.tmx_data.tilewidth, tile_pos[1] * self.game.board_manager.current_board.tmx_data.tileheight), 6)
+ # entity.tile_pos = tile_pos
+ # return True
+ # else:
+ # return False
+
+ #def select_entities_with_tile_cursor(self, tile_def):
+ # """
+ # Select the current entity under the tile cursor by way
+ # of the tile_def. Returns True if an entity is selected,
+ # and False otherwise.
+ # """
+ # # TODO: Eventually this should return info about the team of the selected
+ # # entity so that GameInterface can make control mode decisions.
+ # e = self.get_entities_by_tile(tile_def)
+ # if e != [] and e[0].team == "Player":
+ # self.selected_entity = e[0] # Select only the topmost ent on this tile
+ # self.game.board_manager.display_as_move_range(self.get_entity_legal_move_tile_pos(self.selected_entity))
+ # return True
+ # else:
+ # self.selected_entity = None
+ # self.game.board_manager.load_overlay()
+ # return False
+
+ #def get_entity_legal_move_tile_pos(self, entity):
+ # """
+ # Calculate potential legal moves for entity. Note, this
+ # does not return tiles, but rather hypothetical legal
+ # tile_pos coordinate in the form (x, y). The return is
+ # a list of these coordinates. Uses the A* algorithm.
+ # """
+ # m = entity.unit.active_stats["MOVE"]
+ # legal_moves = []
+ # for x in range(0, self.game.board_manager.current_board.tmx_data.width):
+ # for y in range(0, self.game.board_manager.current_board.tmx_data.height):
+ # mx = entity.tile_pos[0] - x
+ # my = entity.tile_pos[1] - y
+ # if (abs(mx) + abs(my)) <= m:
+ # legal_moves.append((x, y))
+ # return legal_moves
+
###############################
# Section 2 - The Piece class #
###############################
+
+class Piece(vgo.Entity):
+ """
+ Object that represents a playable piece on the board. Mostly
+ only differs from entity in that it expects the standard
+ animation format to allow for facing, moving, etc. Has some
+ sligthly modified move_motion and set_motion methods.
+ """
+
+ def __init__(self, sheet, sprite = (0, 0), animation = None, animated = False,
+ name, passable = False, normal_stats = None, active_stats = None, team = None):
+
+ # Parent initialization
+ super().__init__(sheet, sprite, animation, animated)
+
+ # Face settings
+ self.facing = FACE_DIR.L
+
+ # Others
+ self.name = name
+ self.passable = passable
+ self.normal_stats = normal_stats
+ self.active_stats = active_stats
+ self.team = team # TODO: team maybe should be defined in unit
+ self.back_to_stand = False # TODO: This may not be the best way
+ self.current_tile_path = []
+ self.current_tile_path_index = 0
+ self.path_moving = False
+
+ def set_motion(self, target_pos, speed):
+ """
+ Overwrite of the basic Entity version to support facing and
+ animating automatically.
+ """
+ super().set_motion(target_pos, speed)
+
+ # Decide facing
+ # TODO: This should be determined by the last move in the path instead
+ mx = target_pos[0] - self.rect.topleft[0]
+ my = target_pos[1] - self.rect.topleft[1]
+ a = math.atan2(mx, my) * 180 / math.pi
+ if a >= -67.5 and a < 0:
+ self.facing = FACE_DIR.D
+ elif a >= 0 and a < 112.5:
+ self.facing = FACE_DIR.R
+ elif a > 112.5 or a < -112.5:
+ self.facing = FACE_DIR.U
+ else:
+ self.facing = FACE_DIR.L
+
+ # Set a movement animation
+ # TODO: It may be neccessary in the future to indicate whether or not this
+ # animation should be assigned according to whether or not a board move is
+ # actually taking place. Also, this is a very roundabout way to reference
+ # the sheet's animations. Maybe sheets should be aware of their anims?
+ self.set_animation(self.sheet.manager.animations[self.sheet.name]["walk_" + self.facing.name], True)
+
+ def set_move_along_tile_path(self, tile_seq):
+ """
+ Move along a sequence of tiles in order.
+ """
+ self.current_tile_path = tile_seq
+ self.current_tile_path_index = 0
+ self.path_moving = True
+
+ def execute_tile_path_move(self):
+ """
+ Execute a move along a tile path.
+ """
+ if self.current_tile_path != None and self.path_moving:
+ if self.motion == {} and self.current_tile_path_index < len(self.current_tile_path):
+ next_tar = (self.current_tile_path[self.current_tile_path_index][0] * TILE_WIDTH, self.current_tile_path[self.current_tile_path_index][1] * TILE_HEIGHT)
+ self.set_motion(next_tar, PIECE_MOVE_SPEED)
+ self.current_tile_path_index += 1
+ elif self.motion == {}:
+ self.tile_pos = self.current_tile_path[self.current_tile_path_index - 1]
+ self.path_moving = False
+ self.current_tile_path = []
+ self.back_to_stand = True
+
+ def act(self):
+ """
+ Overwriting basic act mode.
+ """
+ # TODO: Something else should be done so that this doesn't overwrite other
+ # legit non-walking, non-standing anims. THIS MAY NOT BE THE BEST.
+ self.execute_tile_path_move()
+ if self.back_to_stand:
+ self.set_animation(self.sheet.manager.animations[self.sheet.name]["stand_" + self.facing.name], True)
+ self.back_to_stand = False
+
+##########################
+# Section 3 - TileCursor #
+##########################
+
+class TileCursor(vgo.Entity):
+ """
+ Object that follows the cursor to indicate selected/highlighted
+ tiles.
+ """
+
+ def __init__(self, name, ent_id, sheet, sprite = (0, 0), animation = None, animated = False, passable = True, unit = None):
+
+ # Parent initialization
+ super().__init__(name, ent_id, sheet, sprite, animation, animated, passable, unit)
+
+ # VGO settings
+ self.custom_flags = "TileCursor"
+
+ # DirtySprite settings
+ self.layer = 1
diff --git a/src/subsystem.py b/src/subsystem.py
@@ -91,10 +91,14 @@ class GameInterface(GameSubsystem):
self.game.menu_manager.trigger_button_at_pos(mousepos)
elif self.game.state_mode == STATE_MODES.Battle_Mode:
if self.game.control_mode == CTRL_MODES.Turn_Normal:
- if self.game.entity_manager.select_entities_with_tile_cursor(self.game.board_manager.get_tile_at_position(mousepos)):
+ # TODO: Bussing
+ # NOTE: Functional change...
+ self.game.piece_manager.select_piece_with_tile_cursor()
+ if self.game.piece_manager.selected_piece != None:
self.game.control_mode = CTRL_MODES.Turn_Select_Move
elif self.game.control_mode == CTRL_MODES.Turn_Select_Move:
to_path = self.game.board_manager.get_path_by_previous_moves(self.game.entity_manager.selected_entity.tile_pos, self.game.board_manager.get_tile_pos_at_position(mousepos))
+ # TODO: Decouple this and make it work with the modifications
if self.game.entity_manager.set_entity_move_to_tile_path(self.game.entity_manager.selected_entity, to_path):
self.game.lose_control(len(to_path) * PIECE_MOVE_DELAY, CTRL_MODES.Turn_Normal)
self.game.board_manager.load_overlay()
@@ -150,8 +154,17 @@ class ManagerBus(GameSubsystem):
# Parent init
super().__init__(game)
- # Module references
- self.managers = {}
+ # Fetches: All return values from managers
+ def fetch_sheet(self, name):
+ return self.game.sheet_manager.loaded_sheets[name]
+ def fetch_animation(self, sheet, anim):
+ return self.game.sheet_manager.animations[sheet][anim]
+ def fetch_piece_by_name(self, name):
+ return self.game.piece_manager.get_piece_by_name(name)
+ def fetch_piece_by_tile(self, tile_pos):
+ return self.game.piece_manager.get_piece_by_tile(tile_pos)
+ def fetch_tile_by_screen_pos(self, position):
+ return self.game.board_manager.get_tile_by_position(position)
####################################
# Section 4 - The GameCamera class #
diff --git a/src/vgo.py b/src/vgo.py
@@ -51,23 +51,22 @@ from .constants import *
# to by the oracle.
# This file contains:
-# 1. The VisibleGameObject class that defines the abstract parent of all entities and other visible sprites
-# 2. The Entity class that defines the objects that represent non-UI-element game objects
-# 3. Various kinds of specialized entity classes
-# 4. Managers for VGO objects
+# 1. The Entity class that is the extension of pygame.Sprite used throughout the game
+# 2. Various kinds of specialized entity classes that don't fit in other source files
# TODO: This should eventually use LayeredDirty sprites for performance reasons
# TODO: Eventually need to add a UI-element class type (sub of entity? Should entity replace VGO entirely???)
-###################################
-# Section 1 - Visible Game Object #
-###################################
+############################
+# Section 1 - Entity class #
+############################
-class VisibleGameObject(pygame.sprite.DirtySprite):
+class Entity(pygame.sprite.DirtySprite):
"""
The parent of all visible objects. VisibleGameObject (VGO) is
essentially an extended, customised version of the PyGame Sprite
- object.
+ object. Entity supports animations, motions (movement over time),
+ and tile operations, but none of that is required.
"""
def __init__(self, sheet, sprite = (0, 0), animation = None, animated = False):
@@ -99,6 +98,10 @@ class VisibleGameObject(pygame.sprite.DirtySprite):
self.motion = {}
self.motion_timer = 0
+ # Tile values
+ self.tile_pos = (-1, -1)
+ self.tile_gid = None
+
def set_sprite(self, sprite_coord):
"""
Set the VGO's sprite to another one on the board. The
@@ -179,6 +182,21 @@ class VisibleGameObject(pygame.sprite.DirtySprite):
self.set_center_position(self.motion["target"]) # Make sure we end up in exactly the right spot
self.motion = {}
+ def snap_to_tile(self):
+ """
+ Snap the Entity to its current tile.
+ """
+ if self.tile_pos != (-1, -1):
+ self.set_position((self.tile_pos[0] * TILE_WIDTH, self.tile_pos[1] * TILE_HEIGHT))
+
+ def assign_tile(self, tile_def):
+ """
+ Assign a tile as this entity object's occupied tile.
+ Assume the values are legitimate.
+ """
+ self.tile_pos = (tile_def[0], tile_def[1])
+ self.tile_gid = tile_def[2]
+
def act(self):
"""
This method is called as part of update() and is meant
@@ -200,324 +218,8 @@ class VisibleGameObject(pygame.sprite.DirtySprite):
self.animate()
surface.blit(self.image, self.rect)
-#############################
-# Section 2 - Entity Object #
-#############################
-
-class Entity(VisibleGameObject):
- """
- Entities are VGOs that can occupy a tile. They are managed
- by an EntityManager and record tile x, y and gid values. An
- Entity does not have to occupy a tile but it can. Entities
- also have a name (human-readable string set in their definition)
- and a ent_id (number assigned by entity manager). Entities can
- also optionally have a Unit assigned to them to represent
- their statistics in gameplay.
- """
-
- def __init__(self, name, ent_id, sheet, sprite = (0, 0), animation = None, animated = False, passable = False, unit = None):
-
- # Parent initialization
- super().__init__(sheet, sprite, animation, animated)
-
- # Saved values
- self.name = name
- self.ent_id = ent_id
- self.passable = passable
- self.unit = unit
-
- # Tile values
- self.tile_pos = (-1, -1)
- self.tile_gid = None
-
- def snap_to_tile(self):
- """
- Snap the Entity to its current tile.
- """
- if self.tile_pos != (-1, -1):
- self.set_position((self.tile_pos[0] * TILE_WIDTH, self.tile_pos[1] * TILE_HEIGHT))
-
- def assign_tile(self, tile_def):
- """
- Assign a tile as this entity object's occupied tile.
- Assume the values are legitimate.
- """
- self.tile_pos = (tile_def[0], tile_def[1])
- self.tile_gid = tile_def[2]
-
#########################################
-# Section 3 - Various Entity subclasses #
+# Section 2 - Various Entity subclasses #
#########################################
-class TileCursor(Entity):
- """
- Object that follows the cursor to indicate selected/highlighted
- tiles.
- """
-
- def __init__(self, name, ent_id, sheet, sprite = (0, 0), animation = None, animated = False, passable = True, unit = None):
-
- # Parent initialization
- super().__init__(name, ent_id, sheet, sprite, animation, animated, passable, unit)
-
- # VGO settings
- self.custom_flags = "TileCursor"
-
- # DirtySprite settings
- self.layer = 1
-
-class Piece(Entity):
- """
- Object that represents a playable piece on the board. Mostly
- only differs from entity in that it expects the standard
- animation format to allow for facing, moving, etc. Has some
- sligthly modified move_motion and set_motion methods.
- """
-
- def __init__(self, name, ent_id, sheet, sprite = (0, 0), animation = None, animated = False, passable = False, unit = None, team = None):
-
- # Parent initialization
- super().__init__(name, ent_id, sheet, sprite, animation, animated, passable, unit)
-
- # Face settings
- self.facing = FACE_DIR.L
-
- # Others
- self.team = team # TODO: team maybe should be defined in unit
- self.back_to_stand = False # TODO: This may not be the best way
- self.current_tile_path = []
- self.current_tile_path_index = 0
- self.path_moving = False
-
- def set_motion(self, target_pos, speed):
- """
- Overwrite of the basic VGO version to support facing and
- animating automatically.
- """
- super().set_motion(target_pos, speed)
-
- # Decide facing
- mx = target_pos[0] - self.rect.topleft[0]
- my = target_pos[1] - self.rect.topleft[1]
- a = math.atan2(mx, my) * 180 / math.pi
- if a >= -67.5 and a < 0:
- self.facing = FACE_DIR.D
- elif a >= 0 and a < 112.5:
- self.facing = FACE_DIR.R
- elif a > 112.5 or a < -112.5:
- self.facing = FACE_DIR.U
- else:
- self.facing = FACE_DIR.L
-
- # Set a movement animation
- # TODO: It may be neccessary in the future to indicate whether or not this
- # animation should be assigned according to whether or not a board move is
- # actually taking place. Also, this is a very roundabout way to reference
- # the sheet's animations. Maybe sheets should be aware of their anims?
- self.set_animation(self.sheet.manager.animations[self.sheet.name]["walk_" + self.facing.name], True)
-
- def set_move_along_tile_path(self, tile_seq):
- """
- Move along a sequence of tiles in order.
- """
- self.current_tile_path = tile_seq
- self.current_tile_path_index = 0
- self.path_moving = True
-
- def execute_tile_path_move(self):
- """
- Execute a move along a tile path.
- """
- if self.current_tile_path != None and self.path_moving:
- if self.motion == {} and self.current_tile_path_index < len(self.current_tile_path):
- next_tar = (self.current_tile_path[self.current_tile_path_index][0] * TILE_WIDTH, self.current_tile_path[self.current_tile_path_index][1] * TILE_HEIGHT)
- self.set_motion(next_tar, PIECE_MOVE_SPEED)
- self.current_tile_path_index += 1
- elif self.motion == {}:
- self.tile_pos = self.current_tile_path[self.current_tile_path_index - 1]
- self.path_moving = False
- self.current_tile_path = []
- self.back_to_stand = True
-
- def act(self):
- """
- Overwriting basic act mode.
- """
- # TODO: Something else should be done so that this doesn't overwrite other
- # legit non-walking, non-standing anims. THIS MAY NOT BE THE BEST.
- self.execute_tile_path_move()
- if self.back_to_stand:
- self.set_animation(self.sheet.manager.animations[self.sheet.name]["stand_" + self.facing.name], True)
- self.back_to_stand = False
-
-##############################################
-# Section 4 - Managers for VGOs & Subclasses #
-##############################################
-
-class EntityManager(manager.Manager):
- """
- Manager for all entity objects. Handles creating them, placing
- them on the screen, managing their updates, disposing of them
- when need be, and transferring info to them for e.g. moving. It
- should be noted that EntityManager is only employed for in-battle
- entities. Menus manage their own entities in menu modes.
- """
- # TODO: EntityManager should eventually be managing menu entities as well.
- def __init__(self, game, bus):
-
- super().__init__(game, bus)
-
- # Entity values
- self.loaded_entities = pygame.sprite.LayeredDirty()
- self.tile_cursor = None
- self.selected_entity = None
- self.total_entities = 0 # total number of unique entities loaded
- self.pieces = []
-
- def add_entity(self, entity):
- """
- Add an entity to the loaded_entities group and increment
- the number of total_entities.
- """
- self.loaded_entities.add(entity)
- self.total_entities += 1
-
- def load_entities_from_json(self, entsjson):
- """
- Load one or more entities from a JSON file.
- """
- j = json.load(open(os.path.join(ENTITY_JSON_PATH, entsjson)))
-
- for e in j:
- # TODO: type should be enum
- if j[e]["type"] == "Entity":
- ne = Entity(j[e]["name"], self.total_entities,
- self.game.sheet_manager.loaded_sheets[j[e]["sheet"]], tuple(j[e]["sprite"]),
- self.game.sheet_manager.animations[j[e]["sheet"]][j[e]["animation"]],
- j[e]["animated"], j[e]["passable"], unit.Unit(self, self.game.unit_manager.get_stats(j[e]["name"])))
- elif j[e]["type"] == "Piece":
- ne = Piece(j[e]["name"], self.total_entities,
- self.game.sheet_manager.loaded_sheets[j[e]["sheet"]], tuple(j[e]["sprite"]),
- self.game.sheet_manager.animations[j[e]["sheet"]][j[e]["animation"]],
- j[e]["animated"], j[e]["passable"], unit.Unit(self, self.game.unit_manager.get_stats(j[e]["name"])),
- j[e]["team"])
- self.pieces.append(ne)
- ne.assign_tile(self.game.board_manager.get_tile_at_tile_pos(tuple(j[e]["tile"])))
- ne.snap_to_tile()
- self.add_entity(ne)
-
- def load_tile_cursor(self, sheet):
- """
- Load a TileCursor object to highlight selected tiles.
- """
- self.tile_cursor = TileCursor("Tile_Cursor", self.total_entities, self.game.sheet_manager.loaded_sheets[sheet])
- self.tile_cursor.set_animation(self.game.sheet_manager.animations["cursor1"]["pulse"], True)
- self.add_entity(self.tile_cursor)
-
- def get_entity_by_id(self, idnum):
- """
- Returns an entity by its id number.
- """
- ent = None
- for e in self.loaded_entities:
- if e.ent_id == idnum:
- ent = e
- break
- return ent
-
- def get_entity_by_name(self, name):
- """
- Returns an entity matching name.
- """
- ent = None
- for e in self.loaded_entities:
- if e.name == name
- ent = e
- break
- return ent
-
- def position_tile_cursor(self, tile_def):
- """
- Snap the TileCursor object's position to 'pos' and set the
- tile GID there as the current tile_cursor's selected tile.
- """
- self.tile_cursor.assign_tile(tile_def)
- self.tile_cursor.snap_to_tile()
-
- def get_entities_by_tile(self, tile_def):
- """
- Find if there are any loaded entities at the provided tile
- definition.
- """
- found_ents = []
- for e in self.loaded_entities:
- if e.tile_pos == (tile_def[0], tile_def[1]) and e.custom_flags != "TileCursor":
- found_ents.append(e)
- return found_ents
-
- def select_entities_with_tile_cursor(self, tile_def):
- """
- Select the current entity under the tile cursor by way
- of the tile_def. Returns True if an entity is selected,
- and False otherwise.
- """
- # TODO: Eventually this should return info about the team of the selected
- # entity so that GameInterface can make control mode decisions.
- e = self.get_entities_by_tile(tile_def)
- if e != [] and e[0].team == "Player":
- self.selected_entity = e[0] # Select only the topmost ent on this tile
- self.game.board_manager.display_as_move_range(self.get_entity_legal_move_tile_pos(self.selected_entity))
- return True
- else:
- self.selected_entity = None
- self.game.board_manager.load_overlay()
- return False
-
- def get_entity_legal_move_tile_pos(self, entity):
- """
- Calculate potential legal moves for entity. Note, this
- does not return tiles, but rather hypothetical legal
- tile_pos coordinate in the form (x, y). The return is
- a list of these coordinates. Uses the A* algorithm.
- """
- m = entity.unit.active_stats["MOVE"]
- legal_moves = []
- for x in range(0, self.game.board_manager.current_board.tmx_data.width):
- for y in range(0, self.game.board_manager.current_board.tmx_data.height):
- mx = entity.tile_pos[0] - x
- my = entity.tile_pos[1] - y
- if (abs(mx) + abs(my)) <= m:
- legal_moves.append((x, y))
- return legal_moves
-
- def set_entity_move_to_tile_pos(self, entity, tile_pos):
- """
- Sets the entity to move to the given tile_pos. A 'move'
- is an assignment from the EntityManager. A 'motion' is
- a setting similar to an animation (but for spatial travel)
- for an entity.
- """
- # TODO: Set speed of motion somehow, maybe calculated from MOVE of entity
- if entity != None and tile_pos != None:
- entity.set_motion((tile_pos[0] * self.game.board_manager.current_board.tmx_data.tilewidth, tile_pos[1] * self.game.board_manager.current_board.tmx_data.tileheight), 6)
- entity.tile_pos = tile_pos
- return True
- else:
- return False
-
- def set_entity_move_to_tile_path(self, entity, path):
- """
- Assigns a path to the selected entity.
- """
- if entity != None and path != None:
- entity.set_move_along_tile_path(path)
- return True
- else:
- return False
-
- def update_entities(self, surface = None):
- """
- Update all loaded entities.
- """
- if surface != None:
- self.loaded_entities.update(surface)
+# TODO: