sep-pm-platformer/project/main.py

204 lines
8.1 KiB
Python
Raw Permalink Normal View History

2023-03-29 15:11:17 +02:00
import sys
from typing import Optional
2023-03-24 17:41:48 +01:00
import pygame
from level.Level import Level
2023-03-25 15:41:32 +01:00
from level.LevelManager import LevelManager
from level.selection.LevelScreenManager import LevelScreenManager
from level.selection.LevelSelectionScreenManager import LevelSelectionScreenManager
from level.selection.MainMenuScreenManager import MainMenuScreenManager
from level.selection.OptionsScreenManager import OptionsScreenManager
from level.selection.ScreenManager import ScreenManager
2023-03-29 18:07:52 +02:00
from level.selection.WinScreenManager import WinScreenManager
2023-03-27 14:38:52 +02:00
from physics import ConstantsParser
from physics.SpriteManager import SpriteManager
from physics.TickData import TickData
2023-03-25 15:41:32 +01:00
from sprite.PositionScale import PositionScale
from sprite.SpritesheetManager import SpritesheetManager
from ui_elements.ClickEvent import ClickEvent
2023-03-26 15:01:58 +02:00
from ui_elements.KeyManager import KeyManager
2023-03-24 17:41:48 +01:00
2023-03-29 14:14:45 +02:00
BACKGROUND_IMAGES_UNSCALED = {
2023-03-30 09:29:18 +02:00
'grasslands': pygame.image.load('data/sprites/grasslands_bg.png'),
2023-03-29 14:14:45 +02:00
'castle': pygame.image.load('data/sprites/castle_bg.png'),
'cave': pygame.image.load('data/sprites/cave_bg.png'),
'menu': pygame.image.load('data/sprites/intro_bg.png'),
2023-03-29 17:52:46 +02:00
'level_select': pygame.image.load('data/sprites/level_select_bg.png'),
2023-03-29 18:07:52 +02:00
'win': pygame.image.load('data/sprites/win_bg.png'),
2023-03-29 14:14:45 +02:00
}
BACKGROUND_IMAGES_SCALED = {
2023-03-30 09:27:22 +02:00
'grasslands': pygame.transform.scale(BACKGROUND_IMAGES_UNSCALED['grasslands'], (1, 1)),
2023-03-29 14:14:45 +02:00
'castle': pygame.transform.scale(BACKGROUND_IMAGES_UNSCALED['castle'], (1, 1)),
'cave': pygame.transform.scale(BACKGROUND_IMAGES_UNSCALED['cave'], (1, 1)),
'menu': pygame.transform.scale(BACKGROUND_IMAGES_UNSCALED['menu'], (1, 1)),
2023-03-29 17:52:46 +02:00
'level_select': pygame.transform.scale(BACKGROUND_IMAGES_UNSCALED['level_select'], (1, 1)),
2023-03-29 18:07:52 +02:00
'win': pygame.transform.scale(BACKGROUND_IMAGES_UNSCALED['win'], (1, 1)),
2023-03-29 14:01:55 +02:00
}
def apply_frame_rate(number: float, frame_rate: float = 30):
2023-03-25 17:18:43 +01:00
"""
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
2023-03-25 17:18:43 +01:00
:param number: The number to scale by the factor
:return: The scaled number
"""
return number / (frame_rate / 30)
2023-03-24 17:41:48 +01:00
class MainLoop:
def __init__(self):
self.GAME_STATE_MENU = 'main_menu'
self.GAME_STATE_LEVEL_SELECTION = 'level_selection'
self.GAME_STATE_LEVEL = 'level'
self.GAME_STATE_OPTIONS = 'options'
2023-03-29 18:07:52 +02:00
self.GAME_STATE_WIN = 'win'
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("Don't Get Busted")
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_MENU)
2023-03-29 13:50:48 +02:00
self.level: Optional[Level] = None
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]))
2023-03-29 14:14:45 +02:00
for key in BACKGROUND_IMAGES_UNSCALED:
BACKGROUND_IMAGES_SCALED[key] = pygame.transform.scale(
BACKGROUND_IMAGES_UNSCALED[key], self.window_size
)
def select_level(self, level: Level):
2023-03-29 13:50:48 +02:00
self.level = level
self.set_game_state(self.GAME_STATE_LEVEL)
2023-03-30 09:27:22 +02:00
def select_level_selection(self, theme: str = 'grasslands'):
2023-03-29 13:50:48 +02:00
self.set_game_state(self.GAME_STATE_LEVEL_SELECTION)
if self.screen_manager is not None and isinstance(self.screen_manager, LevelSelectionScreenManager):
self.screen_manager.select_theme(theme)
2023-03-29 13:50:48 +02:00
def player_death(self, level: Level):
self.select_level(level)
2023-03-29 16:08:12 +02:00
def player_success(self, level: Level):
next_level = self.parsed_levels_manager.find_next_level(level)
2023-03-29 16:29:46 +02:00
if next_level is not None:
self.select_level(next_level)
else:
2023-03-29 18:07:52 +02:00
self.set_game_state(self.GAME_STATE_WIN)
2023-03-29 16:08:12 +02:00
def select_main_menu(self):
self.set_game_state(self.GAME_STATE_MENU)
def select_options(self):
self.set_game_state(self.GAME_STATE_OPTIONS)
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(
2023-03-29 13:50:48 +02:00
self.sprite_manager, self.spritesheet_manager, self, self.level
)
elif self.game_state == self.GAME_STATE_LEVEL_SELECTION:
self.screen_manager = LevelSelectionScreenManager(
self.sprite_manager, self.spritesheet_manager, self, self.parsed_levels_manager
)
elif self.game_state == self.GAME_STATE_OPTIONS:
self.screen_manager = OptionsScreenManager(
self.sprite_manager, self.spritesheet_manager, self,
)
2023-03-29 18:07:52 +02:00
elif self.game_state == self.GAME_STATE_WIN:
self.screen_manager = WinScreenManager(
self.sprite_manager, self.spritesheet_manager, self,
)
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()
2023-03-29 15:06:18 +02:00
sys.exit()
self.screen.fill((0, 0, 0))
2023-03-29 13:50:48 +02:00
tick_data = TickData(apply_frame_rate(1, self.frame_rate),
pygame_events,
self.key_manager,
click_events,
self.screen_transform)
self.screen_manager.tick(tick_data)
self.sprite_manager.tick(tick_data)
2023-03-29 18:07:52 +02:00
if self.level is not None and self.game_state == self.GAME_STATE_LEVEL:
2023-03-29 14:14:45 +02:00
self.screen.blit(BACKGROUND_IMAGES_SCALED[self.level.theme], (0, 0))
elif self.game_state == self.GAME_STATE_MENU:
self.screen.blit(BACKGROUND_IMAGES_SCALED['menu'], (0, 0))
2023-03-29 18:07:52 +02:00
elif self.game_state == self.GAME_STATE_LEVEL_SELECTION or self.game_state == self.GAME_STATE_OPTIONS:
2023-03-29 17:52:46 +02:00
self.screen.blit(BACKGROUND_IMAGES_SCALED['level_select'], (0, 0))
2023-03-29 18:07:52 +02:00
elif self.game_state == self.GAME_STATE_WIN:
self.screen.blit(BACKGROUND_IMAGES_SCALED['win'], (0, 0))
self.sprite_manager.draw(self.screen, self.screen_transform)
pygame.display.update()
main_loop: MainLoop = MainLoop()
main_loop.main_loop()