import asyncio import pygame from maze import maze_gen, get_maze_sz from coords import Coords from common import DrawableGameObject, EventHandler, IS_WASM from game.hero import Hero from game.wall import Walls from game.coins import Coins from game.endlevelmenu import EndLevelMenu from sound import BackgroundSound class Scene(DrawableGameObject, EventHandler): """основной игровой объект""" # кнопки для выхода из игры exit_keys = (pygame.K_ESCAPE, pygame.K_q) def __init__( self, assets: dict, screen_sz: Coords, maze_sz: Coords, coins_count: int, fps: int, ): super().__init__(Coords.zero(), None, assets) self.maze = maze_gen(*maze_sz) maze_sz = get_maze_sz(self.maze) box_sz = screen_sz // get_maze_sz(self.maze) self.box_sz = box_sz self._surface = pygame.display.set_mode(screen_sz) self.surface.fill("white") self.rect = self.surface.get_rect() self.background = pygame.image.load(self.assets["bg1k.png"]).convert_alpha() self.background = pygame.transform.scale(self.background, self.rect.size) double_bg = pygame.Surface((screen_sz.x * 2, screen_sz.y)) double_bg.blit(self.background, (0, 0)) double_bg.blit(self.background, (screen_sz.x, 0)) self.background = double_bg self.bg_shift = 0 self.total_levels, self.total_coins = 0, 0 hero_sz = Coords(*map(int, box_sz * 0.8)) hero_y_offset = (box_sz.y - hero_sz.y) // 2 + box_sz.y self.hero = Hero(Coords(0, hero_y_offset), self) self.done = False self.level_completed = False self.maze = maze_gen(6, 6) self.walls = Walls(self, self.maze, box_sz) self.coins = Coins(self, self.maze, box_sz, coins_count) self.end = EndLevelMenu(self) self.end.active = False self.want_new_level = False self.exit_rect = self.get_exit_rect() self.fps = fps self.sound = BackgroundSound(self.assets["bg.ogg"]) def get_exit_rect(self) -> pygame.Rect: # находим клетку в которой будет выход с карты maze_sz = get_maze_sz(self.maze) coords = (maze_sz - Coords(1, 2)) * self.box_sz rect = pygame.Rect(coords, coords) rect.width, rect.height = 1, self.box_sz.y return rect.move((self.box_sz.x, 0)) def check_level_completed(self): level_completed = self.exit_rect.colliderect(self.hero.rect) if level_completed and not self.level_completed: self.total_coins += self.coins.coins_collected self.total_levels += 1 self.end.active = True self.hero.active = False self.level_completed = True def draw(self): if self.done: return self.surface.blit(self.background, (-self.bg_shift, 0)) if self.level_completed: self.end.draw() else: self.hero.draw() self.walls.draw() self.coins.draw() def scale_box( self, surface: pygame.Surface, rect: pygame.Rect, scale_factor: Coords ): rect.size = self.box_sz rect.scale_by_ip(*scale_factor) surface = pygame.transform.scale(surface, rect.size) return surface, rect def handle_keys(self, keys_pressed): if self.done: return if not self.done: self.hero.handle_keys(keys_pressed) self.check_level_completed() self.end.handle_keys(keys_pressed) def handle_exit(self, event: pygame.event.Event): if IS_WASM: return if ( event.type == pygame.QUIT or event.type == pygame.KEYDOWN and event.key in self.exit_keys ): self.done = True def handle_event(self, event: pygame.event.Event): self.handle_exit(event) if self.done: return if event.type == pygame.KEYDOWN and event.key == pygame.K_m: self.sound.toggle_mute() self.hero.handle_event(event) self.check_level_completed() self.end.handle_event(event) async def event_loop(self): self.sound.play() clock = pygame.time.Clock() while not self.done: for event in pygame.event.get(): self.handle_event(event) self.handle_keys(pygame.key.get_pressed()) self.draw() self.bg_shift = (self.bg_shift + 1) % self.rect.width pygame.display.flip() await asyncio.sleep(0) clock.tick(self.fps)