""" 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()