| @@ -1,52 +1,113 @@ | |||||
| from __future__ import annotations | from __future__ import annotations | ||||
| from abc import ABCMeta, abstractmethod | |||||
| import sys | |||||
| from enum import Enum, auto | |||||
| from typing import Callable, TypedDict | |||||
| import cv2 | |||||
| import pygame | import pygame | ||||
| from cv2 import VideoCapture | |||||
| from pygame import Surface | |||||
| from pygame.time import Clock | |||||
| def main ( | def main ( | ||||
| ) -> None: | ) -> None: | ||||
| pygame.init () | pygame.init () | ||||
| game = Game () | game = Game () | ||||
| deerjika = Deerjika (game, DeerjikaPattern.RELAXED) | |||||
| while True: | while True: | ||||
| deerjika = Deerjika (game) | |||||
| pass | |||||
| class Game: | class Game: | ||||
| clock: Clock | |||||
| frame: int | |||||
| redrawers: list[Redrawer] | |||||
| screen: Surface | |||||
| def __init__ ( | def __init__ ( | ||||
| self, | self, | ||||
| ): | ): | ||||
| self.screen = pygame.display.set_mode ((CWindow.WIDTH, CWindow.HEIGHT)) | self.screen = pygame.display.set_mode ((CWindow.WIDTH, CWindow.HEIGHT)) | ||||
| self.clock = pygame.time.Clock () | |||||
| self.clock = Clock () | |||||
| self.frame = 0 | |||||
| def redraw ( | |||||
| self, | |||||
| ) -> None: | |||||
| for redrawer in sorted (self.redrawers, key = lambda x: x['layer']): | |||||
| redrawer['func'] () | |||||
| class GameObject: | |||||
| frame: int | |||||
| game: Game | |||||
| width: int | |||||
| height: int | |||||
| x: float | |||||
| y: float | |||||
| vx: float | |||||
| vy: float | |||||
| ax: float | |||||
| ay: float | |||||
| arg: float | |||||
| class GameObject (metaclass = ABCMeta): | |||||
| def __init__ ( | def __init__ ( | ||||
| self, | self, | ||||
| game: Game, | game: Game, | ||||
| layer: int | None = None, | |||||
| ): | ): | ||||
| self.game = game | self.game = game | ||||
| self.redrawer.append (self.redraw) | |||||
| self.frame = 0 | |||||
| if layer is None: | |||||
| if self.game.redrawers: | |||||
| layer = max (r['layer'] for r in self.game.redrawers) + 10 | |||||
| else: | |||||
| layer = 0 | |||||
| self.game.redrawers.append ({ 'layer': layer, 'func': self.redraw }) | |||||
| @abstractmethod | |||||
| def redraw ( | def redraw ( | ||||
| self, | self, | ||||
| ) -> None: | ) -> None: | ||||
| raise NotImplementedError () | |||||
| self.x += self.vx | |||||
| self.y += self.vy | |||||
| self.vx += self.ax | |||||
| self.vy += self.ay | |||||
| self.frame += 1 | |||||
| class Deerjika (GameObject): | class Deerjika (GameObject): | ||||
| surfaces: list[Surface] | |||||
| size: int | |||||
| def __init__ ( | def __init__ ( | ||||
| self, | self, | ||||
| game: Game, | game: Game, | ||||
| pattern: DeerjikaPattern = DeerjikaPattern.NORMAL, | pattern: DeerjikaPattern = DeerjikaPattern.NORMAL, | ||||
| direction: Direction = Direction.LEFT, | direction: Direction = Direction.LEFT, | ||||
| layer: int | None = None, | |||||
| ): | ): | ||||
| super ().__init__ (self) | |||||
| self.game = game | |||||
| super ().__init__ (game, layer) | |||||
| self.pattern = pattern | self.pattern = pattern | ||||
| self.direction = direction | self.direction = direction | ||||
| match pattern: | |||||
| case DeerjikaPattern.NORMAL: | |||||
| ... | |||||
| case DeerjikaPattern.RELAXED: | |||||
| match direction: | |||||
| case Direction.LEFT: | |||||
| self.surfaces = get_surfaces_from_video ('deerjika_relax.mp4') | |||||
| case Direction.RIGHT: | |||||
| ... | |||||
| self.size = len (self.surfaces) | |||||
| def redraw ( | |||||
| self, | |||||
| ) -> None: | |||||
| surface: Surface = self.surfaces[self.frame % self.size] | |||||
| self.game.screen.blit (surface, surface.get_rect (center = (self.x, self.y))) | |||||
| super ().redraw () | |||||
| class DeerjikaPattern (Enum): | class DeerjikaPattern (Enum): | ||||
| @@ -64,5 +125,34 @@ class CWindow: | |||||
| HEIGHT = 768 | HEIGHT = 768 | ||||
| class Redrawer (TypedDict): | |||||
| layer: int | |||||
| func: Callable[[], None] | |||||
| def get_surfaces_from_video ( | |||||
| video_path: str, | |||||
| ) -> list[Surface]: | |||||
| cap = VideoCapture (video_path) | |||||
| if not cap.isOpened (): | |||||
| return [] | |||||
| fps = cap.get (cv2.CAP_PROP_FPS) | |||||
| surfaces: list[Surface] = [] | |||||
| while cap.isOpened (): | |||||
| (ret, frame) = cap.read () | |||||
| if not ret: | |||||
| break | |||||
| frame = cv2.cvtColor (frame, cv2.COLOR_BGR2RGB) | |||||
| frame_surface = pygame.surfarray.make_surface (frame) | |||||
| frame_surface = pygame.transform.rotate (frame_surface, -90) | |||||
| surfaces.append (pygame.transform.flip (frame_surface, True, False)) | |||||
| cap.release () | |||||
| return surfaces | |||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||
| main () | main () | ||||