Return to repo list

heart-of-gold

Tactical RPG written in python, using pygame.
Return to HMagellan.com

commit 52f21499b0b8e2318bf67d06c34d29983288b547
parent 0e3b34b5cbf9fda75fb4c0156f9ea2b0496066c1
Author: Erik Letson <hmagellan@hmagellan.com>
Date:   Fri, 30 Oct 2020 14:19:13 -0500

Camera implemented

Diffstat:
Mdata/json/stats/jisella_1.json | 7-------
Msrc/board.py | 2++
Msrc/constants.py | 2+-
Msrc/game.py | 22++++++++++++++++------
Msrc/subsystem.py | 54++++++++++++++++++++++++++++++++++++++++++++++++++----
5 files changed, 69 insertions(+), 18 deletions(-)

diff --git a/data/json/stats/jisella_1.json b/data/json/stats/jisella_1.json @@ -2,19 +2,12 @@ "name" : "Jisella", "LVL" : 1, "HP" : 100, - "HP_GR" : 100, "ATK" : 135, - "ATK_GR" : 110, "DEF" : 45, - "DEF_GR" : 100, "SPD" : 100, - "SPD_GR" : 100, "ACC" : 60, - "ACC_GR" : 100, "INT" : 50, - "INT_GR" : 90, "WIS" : 30, - "WIS_GR" : 90, "MOVE" : 8, "CRIT" : 10, "SKIL" : 4, diff --git a/src/board.py b/src/board.py @@ -38,6 +38,7 @@ class BoardManager(manager.Manager): self.current_board = None self.loaded_boards = {} self.board_overlay = pygame.sprite.LayeredDirty() + self.current_board_dimensions = (0, 0) # Move values self.moving_entity = None @@ -71,6 +72,7 @@ class BoardManager(manager.Manager): """ if boardname in self.loaded_boards.keys(): self.current_board = self.loaded_boards[boardname] + self.current_board_dimensions = (self.current_board.tmx_data.width * self.current_board.tmx_data.tilewidth, self.current_board.tmx_data.height * self.current_board.tmx_data.tileheight) self.load_overlay() def get_tile_pos_at_position(self, pos): diff --git a/src/constants.py b/src/constants.py @@ -25,7 +25,7 @@ COLORKEY = (255, 0, 255) # Other constants PIECE_MOVE_SPEED = 2 -PIECE_MOVE_DELAY = PIECE_MOVE_SPEED * 3 +PIECE_MOVE_DELAY = PIECE_MOVE_SPEED * 4 # File paths DATA_PATH = os.path.join(os.getcwd(), "data") diff --git a/src/game.py b/src/game.py @@ -42,6 +42,7 @@ class Game(object): # Subsystems self.interface = subsystem.GameInterface(self) self.manager_bus = subsystem.ManagerBus(self) + self.camera = subsystem.GameCamera(self) # Managers self.sheet_manager = images.SheetManager(self, self.manager_bus) @@ -77,6 +78,7 @@ class Game(object): self.control_mode = CTRL_MODES.Main_Menu_Normal self.menu_manager.load_menu_from_file("mainmenu.json") self.menu_manager.switch_to_menu("mainmenu.json") + self.camera.load_camera_surface((SCREEN_WIDTH, SCREEN_HEIGHT)) elif new_mode == STATE_MODES.Battle_Mode: self.control_mode = CTRL_MODES.Turn_Normal # TODO: Obv this must be made more generic. Currently only @@ -86,14 +88,19 @@ class Game(object): self.unit_manager.load_stats_from_json("jisella_1.json") self.entity_manager.load_entities_from_json("testmap1.json") self.entity_manager.load_tile_cursor("cursor1") + self.camera.load_camera_surface(self.board_manager.current_board_dimensions) elif new_mode == STATE_MODES.Still_Scene_Mode: self.control_mode = CTRL_MODES.Still_Scene_Normal # TODO: Generic-ify self.scene_manager.load_still_scene_from_file("testscene.json") + self.camera.load_camera_surface((SCREEN_WIDTH, SCREEN_HEIGHT)) def lose_control(self, time = -1, followup_mode = None): """ - Switch to no-control mode for a set period of time. + Switch to no-control mode for a set period of time. If + time is a negative number, automatic followup will not + occur in the update loop, thus locking the game in + No_Control mode. """ if followup_mode != None: self.return_control_mode = followup_mode @@ -116,7 +123,7 @@ class Game(object): """ # First, fill the entire screen with black - self.screen.fill((0, 0, 0)) + self.screen.fill((200, 200, 200)) # Next, update all the subsurfaces/game objects and draw them # TODO: This is WIP and will change @@ -124,16 +131,19 @@ class Game(object): # State_Mode-specific actions (can be further subdivided by Control_Mode) if self.state_mode == STATE_MODES.Main_Menu_Mode: - self.menu_manager.update_current_menu(self.screen) + self.menu_manager.update_current_menu(self.camera.camera_surface) elif self.state_mode == STATE_MODES.Battle_Mode: - self.board_manager.update_board(self.screen) - self.entity_manager.update_entities(self.screen) + self.board_manager.update_board(self.camera.camera_surface) + self.entity_manager.update_entities(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 #self.menu_manager.update_current_menu(self.screen) elif self.state_mode == STATE_MODES.Still_Scene_Mode: - self.scene_manager.update_scene(self.screen) + self.scene_manager.update_scene(self.camera.camera_surface) + + # Draw the camera to the screen + self.screen.blit(self.camera.camera_surface, self.camera.camera_surface_offset) # State_Mode agnostic, Control_Mode specific actions if self.control_mode == CTRL_MODES.No_Control: diff --git a/src/subsystem.py b/src/subsystem.py @@ -9,6 +9,7 @@ from .constants import * # 1. The generic GameSubsystem class, which abstract subsystems (like Interface) are children of, as well as all Managers # 2. The GameInterface class, which handles game events such as keyboard and mouse input # 3. The ManagerBus class, which is a communication mechanism used by Managers as well as other subsystems and ever game objects +# 4. The GameCamera class, which controls camera-oriented logic and drawing ####################################### # Section 1 - The GameSubsystem class # @@ -80,15 +81,17 @@ class GameInterface(GameSubsystem): """ # TODO: ManagerBus will have a field day here... if event.button == 1: + mousepos = pygame.mouse.get_pos() + mousepos = (mousepos[0] - self.game.camera.camera_surface_offset[0], mousepos[1] - self.game.camera.camera_surface_offset[1]) if self.game.state_mode == STATE_MODES.Main_Menu_Mode: if self.game.control_mode == CTRL_MODES.Main_Menu_Normal: - self.game.menu_manager.trigger_button_at_pos(pygame.mouse.get_pos()) + 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(pygame.mouse.get_pos())): + if self.game.entity_manager.select_entities_with_tile_cursor(self.game.board_manager.get_tile_at_position(mousepos)): 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(pygame.mouse.get_pos())) + 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)) if self.game.entity_manager.set_entity_move_to_tile_path(self.game.entity_manager.selected_entity, to_path): # TODO: The length of time shouldn't have magic numbers. Neither should unit visual movement speed. self.game.lose_control(len(to_path) * PIECE_MOVE_DELAY, CTRL_MODES.Turn_Normal) @@ -111,7 +114,11 @@ class GameInterface(GameSubsystem): """ # Update cursor position if self.game.state_mode == STATE_MODES.Battle_Mode: - self.game.entity_manager.position_tile_cursor(self.game.board_manager.get_tile_at_position(pygame.mouse.get_pos())) + mousepos = pygame.mouse.get_pos() + mousepos = (mousepos[0] - self.game.camera.camera_surface_offset[0], mousepos[1] - self.game.camera.camera_surface_offset[1]) + tilepos = self.game.board_manager.get_tile_at_position(mousepos) + if tilepos != None: + self.game.entity_manager.position_tile_cursor(tilepos) #################################### # Section 3 - The ManagerBus class # @@ -138,3 +145,42 @@ class ManagerBus(GameSubsystem): # Module references self.managers = {} + +#################################### +# Section 4 - The GameCamera class # +#################################### + +class GameCamera(GameSubsystem): + """ + Object that controls the camera surface and + moves it in relation to input. The camera + surface is then drawn onto the game's real + screen at an offset determined by input. + """ + + def __init__(self, game): + + # Parent init + super().__init__(game) + + # Camera surface values + self.camera_surface = pygame.Surface((0, 0)).convert() # This surface is initialized whenever a new map or other game area is loaded + 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 + + def load_camera_surface(self, dimensions, init_offset = (300, 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_rect = self.camera_surface.get_rect() + self.camera_surface_offset = init_offset + + def update_camera(self, surface = None): + """ + Update and draw the camera contents. + """ + if surface != None: + surface.blit(self.camera_surface, self.camera_surface_offset)