diff --git a/mod_pygame/moveimg.py b/mod_pygame/moveimg.py new file mode 100644 index 0000000..f8a994e --- /dev/null +++ b/mod_pygame/moveimg.py @@ -0,0 +1,193 @@ +""" + 3.5 Вставка рисунков. Управление рисунков + https://stepik.org/lesson/937437/step/2?unit=943412 + + Задача: + Попробуйте сделать управление объектом, который есть не просто прямоугольник, а, например, рисунок. + + Зависимости: pygame pillow +""" + +import pygame +import os +import shutil +import tempfile +import urllib.request +from contextlib import contextmanager +from typing import NamedTuple + +import PIL +from PIL import Image, ImageDraw + + +def download_asset(asset, path): + """ + Загрузка картинок из репозитория + """ + prefix = "https://gitea.b4tman.ru/temp/py_stepik/raw/branch/master/assets/" + print("Качаю картинку", asset, end=" ... ", flush=True) + try: + urllib.request.urlretrieve(prefix + asset, path) + except Exception: + print("не смог :(") + return False + print("скачал!") + return True + + +def make_stub_image(path, name): + """Создание пустой картинки, на случай если скачать не получилось""" + + img = PIL.Image.new("RGBA", (200, 200)) + draw = ImageDraw.Draw(img) + draw.rectangle([(50, 50), (150, 150)], outline="black", width=2) + draw.line((50, 50, 150, 150), fill="red", width=2) + draw.line((50, 150, 150, 50), fill="red", width=2) + draw.text((50, 170), name, fill="blue") + img.save(path) + + +@contextmanager +def get_assets(names): + """Получение соответствия с расположением файлов картинок + + Размер картинок нужно менять поэтому они всегда сохраняются во временные файлы. + """ + + assets_dir = "assets" + files = {} + # поиск файлов (загрузка если их нет) и создание временных + for asset in names: + _, ext = os.path.splitext(asset) + temppath = tempfile.mktemp(suffix=ext) + filepath = os.path.join(assets_dir, asset) + if os.path.isfile(filepath): + shutil.copyfile(filepath, temppath) + else: + if not download_asset(asset, temppath): + make_stub_image(temppath, asset) + files[asset] = temppath + + # передача управления + yield files + # очистка + for _, filename in files.items(): + try: + os.remove(filename) + except FileNotFoundError: + pass + + +class Coords(NamedTuple): + """ + Вспомогательный класс для упрощения работы с координатами + """ + + x: int | float + y: int | float + + def __add__(self, other): + if isinstance(other, self.__class__): + return self.__class__(self.x + other.x, self.y + other.y) + if isinstance(other, (int, float)): + return self.__class__(self.x + other, self.y + other) + return NotImplemented + + def __sub__(self, other): + if isinstance(other, self.__class__): + return self.__class__(self.x - other.x, self.y - other.y) + if isinstance(other, (int, float)): + return self.__class__(self.x - other, self.y - other) + return NotImplemented + + def __floordiv__(self, other): + if isinstance(other, self.__class__): + return self.__class__(self.x // other.x, self.y // other.y) + if isinstance(other, (int, float)): + return self.__class__(self.x // other, self.y // other) + return NotImplemented + + def __mul__(self, other): + if isinstance(other, self.__class__): + return self.__class__(self.x * other.x, self.y * other.y) + if isinstance(other, (int, float)): + return self.__class__(self.x * other, self.y * other) + return NotImplemented + + def transform(self, ref: "Coords"): + return self * ref + + +def resize_img(assets: dict, name: str, sz: Coords): + """ + Изменение размера картинки и сохранение в файл + """ + img = PIL.Image.open(assets[name]) + if img.size != sz: + img = img.resize(sz) + img.save(assets[name]) + + +def choose_plural(amount, declensions): + """Возвращает количество объектов в виде строки + например 5 копеек, 1 копейка и т.д. + """ + a = amount % 100 + i = 2 + if 10 < a < 20: + pass + elif a % 10 == 1: + i = 0 + elif 1 < a % 10 < 5: + i = 1 + return f"{amount} {declensions[i]}" + + +def draw_background_image(screen, filename): + background = pygame.image.load(filename) + screen.blit(background, (0, 0)) + + +def game(assets): + pygame.init() + width, height = screen_sz = Coords(1000, 1000) + screen = pygame.display.set_mode(screen_sz) + 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() + + pygame.quit() + + +def main(): + assets = [ + "bg1k.png", + "ghost.png", + ] + with get_assets(assets) as assets: + game(assets) + +main() \ No newline at end of file