moveimg: add game title and remove pillow dependency

This commit is contained in:
Dmitry Belyaev 2024-03-30 23:28:23 +03:00
parent 1ddc649165
commit 512bd42572

View File

@ -10,7 +10,7 @@
Картинки берутся из папки assets, если их нет то автоматически скачиваются из репозитория.
Если скачать не получилось то будут нарисованы заглушки.
Зависимости: pygame pillow
Зависимости: pygame
"""
import os
@ -22,9 +22,7 @@ from contextlib import contextmanager
from random import choice, randrange, sample
from typing import NamedTuple, Optional
import PIL
import pygame
from PIL import ImageDraw
def download_asset(asset, path):
@ -45,13 +43,20 @@ def download_asset(asset, path):
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)
img = pygame.surface.Surface((200, 200), flags=pygame.SRCALPHA)
img.fill((255, 255, 255, 0))
pygame.draw.line(img, "#ff000065", (5, 5), (195, 195), 2)
pygame.draw.line(img, "#ff000065", (195, 5), (5, 195), 2)
rect = pygame.Rect(5, 5, 190, 190)
pygame.draw.rect(img, "black", rect, 3)
font = pygame.font.SysFont("Arial", 44)
text1 = font.render(name, True, "blue")
text1_rect = text1.get_rect()
text1_rect.center = img.get_rect().center
img.blit(text1, text1_rect)
pygame.image.save(img, path)
@contextmanager
@ -129,16 +134,6 @@ class Coords(NamedTuple):
return cls(0, 0)
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 копейка и т.д.
@ -281,6 +276,8 @@ class Hero(GameObject):
super().__init__(coords, parent, assets)
self._surface = pygame.image.load(self.assets["ghost.png"])
self.rect = self.surface.get_rect()
sf = Coords(0.8, 0.8)
self._surface, self.rect = self.scene.scale_box(self.surface, self.rect, sf)
self.rect.topleft = coords
self.active = True
self.looking_right = False
@ -324,7 +321,7 @@ class Hero(GameObject):
def flip(self):
self.looking_right = not self.looking_right
self._surface = pygame.transform.flip(self.surface, True, False)
def move(self, direction: Coords, step: int = 1):
if direction.x != 0:
going_right = direction.x > 0
@ -335,15 +332,15 @@ class Hero(GameObject):
def move_left(self, step: int = 1):
self.move(Coords(-1, 0), step)
def move_right(self, step: int = 1):
self.move(Coords(1, 0), step)
def move_up(self, step: int = 1):
self.move(Coords(0, -1), step)
def move_down(self, step: int = 1):
self.move(Coords(0, 1), step)
self.move(Coords(0, 1), step)
def handle_event(self, event: pygame.event.Event):
if not self.active:
@ -383,6 +380,9 @@ class WallBlock(GameObject):
self._surface = pygame.image.load(self.assets["brick.png"])
self.rect = self.surface.get_rect()
self.rect.topleft = coords
# уменьшаем размер монетки
sf = Coords(1, 1)
self._surface, self.rect = self.scene.scale_box(self.surface, self.rect, sf)
def draw(self):
self.parent.surface.blit(self.surface, self.rect)
@ -417,6 +417,7 @@ class Walls(GameObject):
return True
return False
class Coin(GameObject):
"""объект монетки"""
@ -431,13 +432,13 @@ class Coin(GameObject):
self.rect = self.surface.get_rect()
self.rect.topleft = coords
# уменьшаем размер монетки
new_rect = self.rect.scale_by(0.7, 0.7)
self._surface = pygame.transform.scale(self._surface, new_rect.size)
self.rect = new_rect
sf = Coords(0.7, 0.7)
self._surface, self.rect = self.scene.scale_box(self.surface, self.rect, sf)
def draw(self):
self.parent.surface.blit(self.surface, self.rect)
class Coins(GameObject):
"""объект коллекции монеток"""
@ -452,7 +453,7 @@ class Coins(GameObject):
super().__init__(Coords.zero(), parent, assets)
self.box_sz = box_sz
self._capacity = count
free_points = []
excluded = Coords(0, 1), get_maze_sz(maze) - Coords(1, 2)
for i, row in enumerate(maze):
@ -461,11 +462,10 @@ class Coins(GameObject):
if item < 1 and p not in excluded:
free_points.append(p)
continue
coin_points = sample(free_points, min(count, len(free_points)))
self.coins = [
Coin(point.transform(box_sz), self, self.assets)
for point in coin_points
Coin(point.transform(box_sz), self, self.assets) for point in coin_points
]
self.collected_coins = []
@ -475,11 +475,11 @@ class Coins(GameObject):
self.done_txt = font.render(text, 1, "#050366e3")
self.done_txt_rect = self.done_txt.get_rect()
self.done_txt_rect.topleft = Coords(10, 10)
@property
def capacity(self):
return self._capacity
@property
def coins_left(self):
return len(self.coins)
@ -487,7 +487,7 @@ class Coins(GameObject):
@property
def coins_collected(self):
return self.capacity - self.coins_left
@property
def all_collected(self):
return self.coins_left == 0
@ -514,6 +514,7 @@ class Coins(GameObject):
self.coins.remove(coin)
self.add_to_collected(coin)
class EndLevel(GameObject):
def __init__(self, scene: GameObject):
super().__init__(Coords.zero(), scene, scene.assets)
@ -566,30 +567,28 @@ class Scene(GameObject):
# кнопки для выхода из игры
exit_keys = (pygame.K_ESCAPE, pygame.K_q)
def __init__(self, assets: dict, screen_sz: Coords, maze_sz: Coords, coins_count: int):
def __init__(
self, assets: dict, screen_sz: Coords, maze_sz: Coords, coins_count: int
):
super().__init__(Coords.zero(), None, assets)
self.maze = maze_gen(*maze_sz)
maze_sz = get_maze_sz(self.maze)
box_sz = screen_sz // get_maze_sz(self.maze)
self.box_sz = box_sz
resize_img(self.assets, "brick.png", box_sz)
resize_img(self.assets, "coin.png", box_sz)
self._surface = pygame.display.set_mode(screen_sz)
self.surface.fill("white")
self.rect = self._surface.get_rect()
self.background = pygame.image.load(self.assets["bg1k.png"])
self.background = pygame.transform.scale(self.background, self.rect.size)
hero_sz = Coords(*map(int, box_sz * 0.8))
resize_img(self.assets, "ghost.png", hero_sz)
hero_y_offset = (box_sz.y - hero_sz.y) // 2 + box_sz.y
self._surface = pygame.display.set_mode(screen_sz)
self.rect = self._surface.get_rect()
self.hero = Hero(Coords(0, hero_y_offset), self)
resize_img(assets, "bg1k.png", screen_sz)
self.background = pygame.image.load(self.assets["bg1k.png"])
self.done = False
self.level_completed = False
self.maze = maze_gen(6, 6)
self.maze = maze_gen(6, 6)
self.walls = Walls(self, self.maze, box_sz)
self.coins = Coins(self, self.maze, box_sz, coins_count)
@ -622,6 +621,7 @@ class Scene(GameObject):
def draw(self):
if self.done:
return
self.surface.fill("white")
self.surface.blit(self.background, self.coords)
if self.level_completed:
self.end.draw()
@ -630,6 +630,14 @@ class Scene(GameObject):
self.walls.draw()
self.coins.draw()
def scale_box(
self, surface: pygame.Surface, rect: pygame.Rect, scale_factor: Coords
):
rect.size = self.box_sz
rect.scale_by_ip(*scale_factor)
surface = pygame.transform.scale(surface, rect.size)
return surface, rect
def handle_event(self, event: pygame.event.Event):
if self.done:
return
@ -653,11 +661,10 @@ class Scene(GameObject):
def game(assets):
pygame.init()
screen_sz = Coords(1000, 1000)
maze_sz = Coords(6, 6)
coins_count = 10
pygame.display.set_caption("Движение рисунка на Pygame")
pygame.display.set_caption("Призрачный лабиринт: сокровища небесного замка")
want_new_level = True
while want_new_level:
@ -669,6 +676,7 @@ def game(assets):
def main():
pygame.init()
assets = [
"bg1k.png",
"ghost.png",