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