2024-04-06 10:30:07 +00:00
|
|
|
|
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
|
2024-04-06 19:50:23 +00:00
|
|
|
|
from sound import BackgroundSound
|
2024-04-06 10:30:07 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
2024-04-07 17:37:02 +00:00
|
|
|
|
self.background = pygame.image.load(self.assets["bg1k.png"]).convert_alpha()
|
2024-04-06 10:30:07 +00:00
|
|
|
|
self.background = pygame.transform.scale(self.background, self.rect.size)
|
|
|
|
|
|
2024-04-06 11:00:41 +00:00
|
|
|
|
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
|
|
|
|
|
|
2024-04-06 10:30:07 +00:00
|
|
|
|
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
|
|
|
|
|
|
2024-04-06 19:50:23 +00:00
|
|
|
|
self.sound = BackgroundSound(self.assets["bg.ogg"])
|
|
|
|
|
|
2024-04-06 10:30:07 +00:00
|
|
|
|
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
|
2024-04-06 11:00:41 +00:00
|
|
|
|
self.surface.blit(self.background, (-self.bg_shift, 0))
|
2024-04-06 10:30:07 +00:00
|
|
|
|
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
|
2024-04-06 19:50:23 +00:00
|
|
|
|
if event.type == pygame.KEYDOWN and event.key == pygame.K_m:
|
|
|
|
|
self.sound.toggle_mute()
|
2024-04-06 10:30:07 +00:00
|
|
|
|
self.hero.handle_event(event)
|
|
|
|
|
self.check_level_completed()
|
|
|
|
|
self.end.handle_event(event)
|
|
|
|
|
|
|
|
|
|
async def event_loop(self):
|
2024-04-06 19:50:23 +00:00
|
|
|
|
self.sound.play()
|
2024-04-06 10:30:07 +00:00
|
|
|
|
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()
|
2024-04-06 11:00:41 +00:00
|
|
|
|
|
|
|
|
|
self.bg_shift = (self.bg_shift + 1) % self.rect.width
|
2024-04-06 10:30:07 +00:00
|
|
|
|
pygame.display.flip()
|
|
|
|
|
await asyncio.sleep(0)
|
|
|
|
|
clock.tick(self.fps)
|