sep-pm-platformer/project/main.py

147 lines
5.5 KiB
Python

from typing import Optional
import pygame
from level.Level import Level
from level.LevelManager import LevelManager
from level.elements.LoadedLevel import LoadedLevel
from level.selection.LevelScreenManager import LevelScreenManager
from level.selection.LevelSelectionScreenManager import LevelSelectionScreenManager
from level.selection.MainMenuScreenManager import MainMenuScreenManager
from level.selection.ScreenManager import ScreenManager
from physics import ConstantsParser
from physics.SpriteManager import SpriteManager
from physics.TickData import TickData
from sprite.PositionScale import PositionScale
from sprite.SpritesheetManager import SpritesheetManager
from ui_elements.ClickEvent import ClickEvent
from ui_elements.KeyManager import KeyManager
what_to_run = 'level'
DEPRECATED_WIDTH = 12 * 71 * 1.5
DEPRECATED_HEIGHT = 12 * 40 * 1.5
# Background to test for level design
test_background_castle = pygame.transform.scale(pygame.image.load('data/sprites/castle_bg.png'),
(DEPRECATED_WIDTH, DEPRECATED_HEIGHT))
# test_background_castle = pygame.transform.scale(pygame.image.load('data/sprites/cave_bg.png'), (DEPRECATED_WIDTH, DEPRECATED_WIDTH))
# test_background_tutorial = pygame.transform.scale(pygame.image.load('data/sprites/tutorial_bg.png'), (DEPRECATED_WIDTH, DEPRECATED_WIDTH))
def apply_frame_rate(number: float, frame_rate: float = 30):
"""
this function calculates a factor that will be multiplied with the
physics of the game to provide a constant speed
:param frame_rate: the frame rate of the game
:param number: The number to scale by the factor
:return: The scaled number
"""
return number / (frame_rate / 30)
class MainLoop:
def __init__(self):
self.GAME_STATE_MENU = 'main_menu'
self.GAME_STATE_LEVEL_SELECTION = 'level_selection'
self.GAME_STATE_LEVEL = 'level'
self.screen_transform: PositionScale = PositionScale((0, 0), (1.5, 1.5))
self.window_size: tuple[float, float] = (1, 1)
pygame.init()
pygame.display.set_caption("PM GAME")
self.update_position_scale(self.screen_transform)
self.screen = self.screen
self.clock = pygame.time.Clock()
self.frame_rate = 30
self.spritesheet_manager = SpritesheetManager("data/sprites", "data/sprites/sprites.json")
self.sprite_manager = SpriteManager()
self.key_manager = KeyManager()
self.parsed_levels_manager = LevelManager('data/levels')
self.parsed_levels_manager.load_from_config('data/levels/levels.json')
self.screen_manager: Optional[ScreenManager] = None
self.game_state = self.GAME_STATE_MENU
self.set_game_state(self.GAME_STATE_LEVEL_SELECTION)
def update_position_scale(self, position_scale: PositionScale):
self.screen_transform = position_scale
self.window_size = (
self.screen_transform.scale[0] * ConstantsParser.CONFIG.block_size[0] *
ConstantsParser.CONFIG.level_size[0],
self.screen_transform.scale[1] * ConstantsParser.CONFIG.block_size[1] *
ConstantsParser.CONFIG.level_size[1]
)
self.screen = pygame.display.set_mode((self.window_size[0], self.window_size[1]))
def select_level(self, level: Level):
print(level.name)
self.set_game_state(self.GAME_STATE_LEVEL)
def set_game_state(self, game_state: str):
self.game_state = game_state
if self.screen_manager is not None:
self.screen_manager.destroy()
if self.game_state == self.GAME_STATE_MENU:
self.screen_manager = MainMenuScreenManager(
self.sprite_manager, self.spritesheet_manager, self
)
elif self.game_state == self.GAME_STATE_LEVEL:
self.screen_manager = LevelScreenManager(
self.sprite_manager, self.spritesheet_manager, self
)
elif self.game_state == self.GAME_STATE_LEVEL_SELECTION:
self.screen_manager = LevelSelectionScreenManager(
self.sprite_manager, self.spritesheet_manager, self, self.parsed_levels_manager
)
else:
print('Invalid game state', self.game_state)
if self.screen_manager is not None:
self.screen_manager.initialize()
def main_loop(self):
while True:
self.clock.tick(self.frame_rate)
pygame_events: list[pygame.event.Event] = pygame.event.get()
self.key_manager.update_key_events(pygame_events)
click_events: list[ClickEvent] = ClickEvent.create_events(pygame_events, self.screen_transform)
for event in click_events:
for layer in self.sprite_manager.layers:
for sprite in self.sprite_manager.layers[layer]:
if sprite.get_bounding_box().contains_point(event.world_position):
sprite.click(event)
for event in pygame_events:
if event.type == pygame.QUIT:
pygame.quit()
quit()
self.screen.fill((0, 0, 0))
self.sprite_manager.tick(
TickData(apply_frame_rate(1, self.frame_rate),
pygame_events,
self.key_manager,
click_events,
self.screen_transform)
)
self.sprite_manager.draw(self.screen, self.screen_transform)
pygame.display.update()
main_loop: MainLoop = MainLoop()
main_loop.main_loop()