Return to repo list

heart-of-gold

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

game.py (8767B)


      1 import pygame
      2 from . import subsystem, bus, camera, interface, manager, images, sound, board, entity, piece, turn, menu, scene, base
      3 from .constants import *
      4 
      5 ###########
      6 # game.py #
      7 ###########
      8 
      9 # TODO: There should be a method to call to change control mode as well as state mode
     10 
     11 # This file contains:
     12 #   1. The 'Game' class, which defines the overarching game object
     13 
     14 ###########################
     15 # Section 1 - Game object #
     16 ###########################
     17 
     18 class Game(object):
     19     """
     20     Game is an object that represents the entire running game
     21     instance. Everything is a sub-component of and subordinate
     22     to Game, and there is only a single instance of Game. It
     23     mostly acts as a container for the most basic PyGame obects,
     24     such as the screen, and for the GameSubsystem objects.
     25     """
     26 
     27     def __init__(self):
     28 
     29         # Basic values
     30         self.screen_dimensions = (SCREEN_WIDTH, SCREEN_HEIGHT)
     31         self.framerate = FRAMERATE
     32         self.on = True
     33         self.no_control_timer = 0
     34         self.return_control_mode = None
     35 
     36         # Mode management values
     37         self.state_mode = STATE_MODES.Main_Menu_Mode
     38         self.control_mode = CTRL_MODES.Main_Menu_Normal
     39 
     40         # PyGame objects
     41         self.screen = pygame.display.set_mode(self.screen_dimensions)
     42         self.frame_clock = pygame.time.Clock()
     43 
     44         # Subsystems
     45         self.manager_bus = bus.ManagerBus(self)
     46         self.camera = camera.GameCamera(self)
     47         self.object_oracle = subsystem.ObjectOracle(self)
     48         self.save_system = subsystem.SaveSystem(self)
     49         self.interface = interface.GameInterface(self, self.manager_bus, self.camera)
     50 
     51         # Managers
     52         self.sheet_manager = images.SheetManager(self, self.manager_bus, self.camera, "sheet_manager")
     53         self.sound_manager = sound.SoundManager(self, self.manager_bus, self.camera, "sound_manager")
     54         self.menu_manager = menu.MenuManager(self, self.manager_bus, self.camera, "menu_manager")
     55         self.board_manager = board.BoardManager(self, self.manager_bus, self.camera, "board_manager")
     56         self.piece_manager = piece.PieceManager(self, self.manager_bus, self.camera, "piece_manager")
     57         self.base_manager = base.BaseManager(self, self.manager_bus, self.camera, "base_manager")
     58         self.scene_manager = scene.SceneManager(self, self.manager_bus, self.camera, "scene_manager")
     59         self.turn_manager = turn.TurnManager(self, self.manager_bus, self.camera, "turn_manager")
     60 
     61         # Setup (This is WIP)
     62         self.sheet_manager.load_animations_from_json("anims.json")
     63         self.sheet_manager.load_sheets_from_json("sheets.json")
     64         self.sound_manager.load_sounds_from_json("sounds.json")
     65         
     66         # Switch to game control
     67         self.switch_mode(STATE_MODES.Main_Menu_Mode)
     68 
     69     def switch_mode(self, new_mode, data = None):
     70         """
     71         Change the current state_mode, as well as load up
     72         the elements of the new mode. This large method
     73         should take account of every possible mode in the
     74         game. Such a structure has no reason to exists e.g. 
     75         as a JSON file. The 'data' option contains the info
     76         needed as part of a mode switch. This method handles
     77         a change even if data is None.
     78         """
     79         if new_mode == None:
     80             return
     81         else:
     82             self.state_mode = new_mode
     83 
     84         if new_mode == STATE_MODES.Main_Menu_Mode:
     85             self.control_mode = CTRL_MODES.Main_Menu_Normal
     86             self.menu_manager.load_menu_from_file("mainmenu.json")
     87             self.camera.load_camera_surface((SCREEN_WIDTH, SCREEN_HEIGHT))
     88         elif new_mode == STATE_MODES.Base_Mode:
     89             self.control_mode = CTRL_MODES.Base_Normal
     90             self.board_manager.load_board(data)
     91             self.base_manager.load_base(data)
     92             self.base_manager.load_ui_elements()
     93             self.camera.load_camera_surface(self.board_manager.current_board.pixel_dimensions)
     94         elif new_mode == STATE_MODES.Battle_Mode:
     95             self.control_mode = CTRL_MODES.Turn_Normal
     96             self.board_manager.load_board(data)
     97             self.piece_manager.load_pieces_from_file(data)
     98             self.piece_manager.load_ui_elements()
     99             self.camera.load_camera_surface(self.board_manager.current_board.pixel_dimensions)
    100             # TODO: This maybe shouldn't happen here, probably not ideal in a more complex transition to battle
    101             self.turn_manager.initialize_turns(self.piece_manager.pieces, data)
    102         elif new_mode == STATE_MODES.Still_Scene_Mode:
    103             self.control_mode = CTRL_MODES.Still_Scene_Normal
    104             self.scene_manager.load_still_scene_from_file(data)
    105             self.camera.load_camera_surface((SCREEN_WIDTH, SCREEN_HEIGHT))
    106 
    107     def lose_control(self, time = -1, followup_mode = None):
    108         """
    109         Switch to no-control mode for a set period of time. If
    110         time is a negative number, automatic followup will not
    111         occur in the update loop, thus locking the game in
    112         No_Control mode.
    113         """
    114         if followup_mode != None:
    115             self.return_control_mode = followup_mode
    116         else:
    117             self.return_control_mode = self.control_mode
    118         self.control_mode = CTRL_MODES.No_Control
    119         self.no_control_timer = time
    120 
    121     def shift_frames(self):
    122         """
    123         Shift to the next frame using the PyGame Clock object.
    124         This must be the FIRST thing that happens in the mainloop.
    125         """
    126         self.frame_clock.tick(self.framerate)
    127 
    128     def update_game(self):
    129         """
    130         Update the entire game (screen, subsystems, internal
    131         values, etc.).
    132         """
    133 
    134         # First, fill the entire screen with black
    135         self.screen.fill((200, 200, 200))
    136 
    137         # Next, update all managers that are mode-agnostic
    138         self.sheet_manager.update(None)
    139         self.sound_manager.update(None)
    140 
    141         # Next, update all the subsurfaces/game objects and draw them
    142         self.interface.update_interface()
    143 
    144         # State_Mode-specific actions (can be further subdivided by Control_Mode)
    145         # Camera draw occurs in all these modes
    146         if self.state_mode == STATE_MODES.Main_Menu_Mode:
    147             self.menu_manager.update(self.camera.camera_surface)
    148             self.camera.update_camera(self.screen)
    149         elif self.state_mode == STATE_MODES.Base_Mode:
    150             self.board_manager.update(self.camera.camera_surface)
    151             self.base_manager.update(self.camera.camera_surface)
    152             self.camera.update_camera(self.screen)
    153             if self.control_mode == CTRL_MODES.Base_Dialog:
    154                 self.scene_manager.update(self.screen)
    155         elif self.state_mode == STATE_MODES.Battle_Mode:
    156             self.board_manager.update(self.camera.camera_surface)
    157             self.piece_manager.update(self.camera.camera_surface)
    158             # NOTE: This must happen here to avoid a very choppy rendering of the
    159             #       moving entity caused by the drawing order.
    160             if self.control_mode == CTRL_MODES.Turn_Watch_Move:
    161                 self.camera.snap_to_position(self.turn_manager.current_active_piece.rect.center)
    162             self.camera.update_camera(self.screen)
    163             if self.control_mode == CTRL_MODES.Battle_Dialog:
    164                 self.scene_manager.update(self.screen)
    165             else:
    166                 self.turn_manager.update(self.screen) # Draw to the screen since it manages UI elements
    167         elif self.state_mode == STATE_MODES.Still_Scene_Mode:
    168             self.scene_manager.update(self.camera.camera_surface)
    169             self.camera.update_camera(self.screen)
    170 
    171         # State_Mode agnostic, Control_Mode specific actions
    172         if self.control_mode == CTRL_MODES.No_Control:
    173             if self.no_control_timer > 0:
    174                 self.no_control_timer -= 1
    175             elif self.no_control_timer == 0:
    176                 self.control_mode = self.return_control_mode
    177                 self.return_control_mode = None
    178 
    179         # Last, update the screen
    180         pygame.display.update()
    181 
    182     def quit_game(self):
    183         """
    184         Turn off so the game stops in a clean way.
    185         """
    186         self.on = False
    187     
    188     def mainloop(self):
    189         """
    190         The loop where all game logic takes place. This
    191         method must be called once from somewhere after
    192         the Game object is initialized in order to start
    193         the game itself. This method cleans up after
    194         itself when the Game object is turned off.
    195         """
    196 
    197         # While we are on, run the loop
    198         while self.on:
    199             self.shift_frames()
    200             self.interface.handle_events(pygame.event.get())
    201             self.update_game()
    202 
    203         # When we turn off, cleanup and end
    204         pygame.quit()
    205