py_stepik/pygame-wasm/phantomcastle/common.py

101 lines
2.6 KiB
Python

from abc import ABC, abstractmethod
from typing import NamedTuple, Optional
FONT_NAME = "Arial"
from sys import platform
IS_WASM = platform == "emscripten"
import pygame
from coords import Coords
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(SingletonMeta, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class SurfaceWithRect(NamedTuple):
surface: pygame.Surface
rect: pygame.Rect
def draw_to(self, target: pygame.Surface):
target.blit(self.surface, self.rect)
class DrawableGameObject(ABC):
"""обобщение игрового элемента"""
coords = property(
lambda self: self.get_coords(), lambda self, c: self.set_coords(c)
)
def __init__(
self,
coords: Coords,
parent: Optional["DrawableGameObject"] = None,
assets: dict | None = None,
):
self.parent = parent
self.rect = pygame.Rect(coords, coords)
self.assets = assets or (parent.assets if parent else None)
self._surface = None
self._mask = None
def __str__(self):
return f"{self.__class__.__name__}({self.coords})"
@property
def surface(self) -> pygame.Surface | None:
return self._surface or (self.parent.surface if self.parent else None)
@property
def mask(self) -> pygame.Mask | None:
if not self._mask:
self._mask = pygame.mask.from_surface(self.surface.convert_alpha())
return self._mask
def overlap(self, rect: pygame.Rect, mask: pygame.Mask) -> bool:
if not self.rect.colliderect(rect):
return False
offset = Coords(*self.rect.topleft) - Coords(*rect.topleft)
overlap = mask.overlap(self.mask, offset)
return overlap is not None
@property
def scene(self):
return self.parent.scene if self.parent else self
def get_coords(self) -> Coords:
return Coords(*self.rect.topleft)
def set_coords(self, coords: Coords):
new_rect = self.rect.copy()
new_rect.topleft = coords
if self.parent:
if self.parent.rect:
if not self.parent.rect.contains(new_rect):
return
self.rect = new_rect
@abstractmethod
def draw(self):
pass
class EventHandler(ABC):
@abstractmethod
def handle_keys(self, keys_pressed):
pass
@abstractmethod
def handle_event(self):
pass