moveimg: add game title and remove pillow dependency
This commit is contained in:
parent
1ddc649165
commit
512bd42572
@ -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",
|
||||||
|
Loading…
Reference in New Issue
Block a user