From efa19e339867a5eb359a6b204504acad7f74aea4 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Fri, 29 Mar 2024 22:29:54 +0300 Subject: [PATCH] pygame moveimg objects --- mod_pygame/moveimg.py | 169 +++++++++++++++++++++++++++++++++--------- 1 file changed, 136 insertions(+), 33 deletions(-) diff --git a/mod_pygame/moveimg.py b/mod_pygame/moveimg.py index f8a994e..c7be425 100644 --- a/mod_pygame/moveimg.py +++ b/mod_pygame/moveimg.py @@ -8,16 +8,17 @@ Зависимости: pygame pillow """ -import pygame import os import shutil import tempfile import urllib.request +from abc import ABC, abstractmethod from contextlib import contextmanager -from typing import NamedTuple +from typing import NamedTuple, Optional import PIL -from PIL import Image, ImageDraw +import pygame +from PIL import ImageDraw def download_asset(asset, path): @@ -117,6 +118,10 @@ class Coords(NamedTuple): def transform(self, ref: "Coords"): return self * ref + @classmethod + def zero(cls): + return cls(0, 0) + def resize_img(assets: dict, name: str, sz: Coords): """ @@ -143,41 +148,138 @@ def choose_plural(amount, declensions): return f"{amount} {declensions[i]}" -def draw_background_image(screen, filename): - background = pygame.image.load(filename) - screen.blit(background, (0, 0)) +class GameObject(ABC): + """обобщение игрового элемента""" + + coords = property( + lambda self: self.get_coords(), lambda self, c: self.set_coords(c) + ) + + def __init__( + self, + coords: Coords, + parent: Optional["GameObject"] = None, + assets: dict | None = None, + ): + self.parent = parent + self._coords = coords + self.assets = assets or (parent.assets if parent else None) + self._surface = None + + @property + def surface(self) -> pygame.Surface | None: + return self._surface or (self.parent.surface if self.parent else None) + + def get_coords(self) -> Coords: + return self._coords + + def set_coords(self, coords: Coords): + if self.parent: + if self.parent.surface: + if not ( + coords.x >= 0 + and coords.x < self.parent.surface.get_width() + and coords.y >= 0 + and coords.y < self.parent.surface.get_height() + ): + return + self._coords = coords + + @abstractmethod + def draw(self): + pass + + @abstractmethod + def handle_event(self, event: pygame.event.Event): + pass + + +class Hero(GameObject): + """объект главного героя""" + + def __init__( + self, + coords: Coords, + parent: GameObject, + assets: dict | None = None, + ): + super().__init__(coords, parent, assets) + screen_sz = Coords(*parent.surface.get_size()) + ghost_sz = screen_sz // 10 + resize_img(self.assets, "ghost.png", ghost_sz) + + self._surface = pygame.image.load(self.assets["ghost.png"]) + self.rect = self.surface.get_rect() + self.coords = coords + + def set_coords(self, coords: Coords): + super().set_coords(coords) + self.rect.topleft = self.coords + + def draw(self): + self.parent.surface.blit(self.surface, self.rect) + + def handle_event(self, event: pygame.event.Event): + delta = 10 + if event.type == pygame.KEYDOWN: + match event.key: + case pygame.K_UP | pygame.K_w: + self.coords += Coords(0, -1) * delta + case pygame.K_DOWN | pygame.K_s: + self.coords += Coords(0, 1) * delta + case pygame.K_LEFT | pygame.K_a: + self.coords += Coords(-1, 0) * delta + case pygame.K_RIGHT | pygame.K_d: + self.coords += Coords(1, 0) * delta + + +class Scene(GameObject): + """основной игровой объект""" + + # кнопки для выхода из игры + exit_keys = (pygame.K_ESCAPE, pygame.K_q) + + def __init__(self, assets: dict, sz: Coords): + super().__init__(Coords.zero(), None, assets) + self._surface = pygame.display.set_mode(sz) + self.hero = Hero(Coords(100, 100), self) + resize_img(assets, "bg1k.png", sz) + self.background = pygame.image.load(self.assets["bg1k.png"]) + self.done = False + + def draw(self): + if self.done: + return + self.surface.blit(self.background, self.coords) + self.hero.draw() + + def handle_event(self, event: pygame.event.Event): + if self.done: + return + if ( + event.type == pygame.QUIT + or event.type == pygame.KEYDOWN + and event.key in self.exit_keys + ): + self.done = True + if not self.done: + self.hero.handle_event(event) + + def event_loop(self): + while not self.done: + event = pygame.event.wait() + self.handle_event(event) + self.draw() + pygame.display.flip() def game(assets): pygame.init() - width, height = screen_sz = Coords(1000, 1000) - screen = pygame.display.set_mode(screen_sz) + screen_sz = Coords(1000, 1000) pygame.display.set_caption("Движение рисунка на Pygame") - ghost_sz = screen_sz // 10 - - resize_img(assets, "bg1k.png", screen_sz) - speed = [2, 2] - - resize_img(assets, "ghost.png", ghost_sz) - ghost = pygame.image.load(assets["ghost.png"]) - ghostrect = ghost.get_rect() - - running = True - - while running: - for event in pygame.event.get(): - if event.type == pygame.QUIT: - running = False - ghostrect = ghostrect.move(speed) - if ghostrect.left < 0 or ghostrect.right > width: - speed[0] = -speed[0] - if ghostrect.top < 0 or ghostrect.bottom > height: - speed[1] = -speed[1] - - draw_background_image(screen, assets["bg1k.png"]) - screen.blit(ghost, ghostrect) - pygame.display.flip() + scene = Scene(assets, screen_sz) + scene.event_loop() pygame.quit() @@ -190,4 +292,5 @@ def main(): with get_assets(assets) as assets: game(assets) -main() \ No newline at end of file + +main()