pygame: add moveimg

This commit is contained in:
Dmitry Belyaev 2024-03-29 16:54:28 +03:00
parent 5bb3bb6213
commit 1eb9fa48fe

193
mod_pygame/moveimg.py Normal file
View File

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