add coins and flip hero
This commit is contained in:
parent
6efab241a5
commit
1ddc649165
@ -11,8 +11,6 @@
|
|||||||
Если скачать не получилось то будут нарисованы заглушки.
|
Если скачать не получилось то будут нарисованы заглушки.
|
||||||
|
|
||||||
Зависимости: pygame pillow
|
Зависимости: pygame pillow
|
||||||
|
|
||||||
TODO: отбработка выхода из лабиринта
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@ -21,7 +19,7 @@ import tempfile
|
|||||||
import urllib.request
|
import urllib.request
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from random import choice, randrange
|
from random import choice, randrange, sample
|
||||||
from typing import NamedTuple, Optional
|
from typing import NamedTuple, Optional
|
||||||
|
|
||||||
import PIL
|
import PIL
|
||||||
@ -285,6 +283,9 @@ class Hero(GameObject):
|
|||||||
self.rect = self.surface.get_rect()
|
self.rect = self.surface.get_rect()
|
||||||
self.rect.topleft = coords
|
self.rect.topleft = coords
|
||||||
self.active = True
|
self.active = True
|
||||||
|
self.looking_right = False
|
||||||
|
# картинка изначально влево, а надо бы начинать со взгляда вправо
|
||||||
|
self.flip()
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
self.parent.surface.blit(self.surface, self.rect)
|
self.parent.surface.blit(self.surface, self.rect)
|
||||||
@ -320,36 +321,57 @@ class Hero(GameObject):
|
|||||||
has_collision = self._check_collision(coords)
|
has_collision = self._check_collision(coords)
|
||||||
super().set_coords(coords)
|
super().set_coords(coords)
|
||||||
|
|
||||||
|
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
|
||||||
|
if self.looking_right != going_right:
|
||||||
|
self.flip()
|
||||||
|
self.coords += direction * step
|
||||||
|
self.scene.coins.collect(self.rect)
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
def handle_event(self, event: pygame.event.Event):
|
def handle_event(self, event: pygame.event.Event):
|
||||||
if not self.active:
|
if not self.active:
|
||||||
return
|
return
|
||||||
|
|
||||||
up, down = Coords(0, -1), Coords(0, 1)
|
wide, short = 30, 5
|
||||||
left, right = Coords(-1, 0), Coords(1, 0)
|
|
||||||
|
|
||||||
da, db = 30, 5
|
|
||||||
if event.type == pygame.KEYDOWN:
|
if event.type == pygame.KEYDOWN:
|
||||||
match event.key:
|
match event.key:
|
||||||
case pygame.K_UP:
|
case pygame.K_UP:
|
||||||
self.coords += up * da
|
self.move_up(wide)
|
||||||
case pygame.K_DOWN:
|
case pygame.K_DOWN:
|
||||||
self.coords += down * da
|
self.move_down(wide)
|
||||||
case pygame.K_LEFT:
|
case pygame.K_LEFT:
|
||||||
self.coords += left * da
|
self.move_left(wide)
|
||||||
case pygame.K_RIGHT:
|
case pygame.K_RIGHT:
|
||||||
self.coords += right * da
|
self.move_right(wide)
|
||||||
case pygame.K_w:
|
case pygame.K_w:
|
||||||
self.coords += up * db
|
self.move_up(short)
|
||||||
case pygame.K_s:
|
case pygame.K_s:
|
||||||
self.coords += down * db
|
self.move_down(short)
|
||||||
case pygame.K_a:
|
case pygame.K_a:
|
||||||
self.coords += left * db
|
self.move_left(short)
|
||||||
case pygame.K_d:
|
case pygame.K_d:
|
||||||
self.coords += right * db
|
self.move_right(short)
|
||||||
|
|
||||||
|
|
||||||
class WallBlock(GameObject):
|
class WallBlock(GameObject):
|
||||||
"""объект елемента стены"""
|
"""объект элемента стены"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -395,6 +417,102 @@ class Walls(GameObject):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
class Coin(GameObject):
|
||||||
|
"""объект монетки"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
coords: Coords,
|
||||||
|
parent: GameObject,
|
||||||
|
assets: dict | None = None,
|
||||||
|
):
|
||||||
|
super().__init__(coords, parent, assets)
|
||||||
|
self._surface = pygame.image.load(self.assets["coin.png"])
|
||||||
|
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
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
self.parent.surface.blit(self.surface, self.rect)
|
||||||
|
|
||||||
|
class Coins(GameObject):
|
||||||
|
"""объект коллекции монеток"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
parent: GameObject,
|
||||||
|
maze: list[list[int]],
|
||||||
|
box_sz: Coords,
|
||||||
|
count: int,
|
||||||
|
assets: dict | None = None,
|
||||||
|
):
|
||||||
|
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):
|
||||||
|
for j, item in enumerate(row):
|
||||||
|
p = Coords(j, i)
|
||||||
|
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
|
||||||
|
]
|
||||||
|
self.collected_coins = []
|
||||||
|
|
||||||
|
# Надпись, если все монетки собраны
|
||||||
|
font = pygame.font.SysFont("Arial", 30)
|
||||||
|
text = "Все монетки собраны!"
|
||||||
|
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)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def coins_collected(self):
|
||||||
|
return self.capacity - self.coins_left
|
||||||
|
|
||||||
|
@property
|
||||||
|
def all_collected(self):
|
||||||
|
return self.coins_left == 0
|
||||||
|
|
||||||
|
def draw(self):
|
||||||
|
for coin in self.collected_coins:
|
||||||
|
coin.draw()
|
||||||
|
for coin in self.coins:
|
||||||
|
coin.draw()
|
||||||
|
if self.all_collected:
|
||||||
|
self.parent.surface.blit(self.done_txt, self.done_txt_rect)
|
||||||
|
|
||||||
|
def add_to_collected(self, coin: Coin):
|
||||||
|
last_pos = Coords(10, 10)
|
||||||
|
if self.collected_coins:
|
||||||
|
last_pos = Coords(*self.collected_coins[-1].rect.topright)
|
||||||
|
last_pos -= Coords(coin.rect.width // 2, 0)
|
||||||
|
coin.coords = last_pos
|
||||||
|
self.collected_coins.append(coin)
|
||||||
|
|
||||||
|
def collect(self, rect: pygame.Rect):
|
||||||
|
mined = [*filter(lambda coin: coin.rect.colliderect(rect), self.coins)]
|
||||||
|
for coin in mined:
|
||||||
|
self.coins.remove(coin)
|
||||||
|
self.add_to_collected(coin)
|
||||||
|
|
||||||
class EndLevel(GameObject):
|
class EndLevel(GameObject):
|
||||||
def __init__(self, scene: GameObject):
|
def __init__(self, scene: GameObject):
|
||||||
@ -417,10 +535,19 @@ class EndLevel(GameObject):
|
|||||||
self.hint_rect.center = self.parent.rect.center
|
self.hint_rect.center = self.parent.rect.center
|
||||||
self.hint_rect = self.hint_rect.move(Coords(0, 300))
|
self.hint_rect = self.hint_rect.move(Coords(0, 300))
|
||||||
|
|
||||||
|
# Надпись для хорошего финала
|
||||||
|
text = "Все монетки собраны!"
|
||||||
|
self.goodtxt = font_hint.render(text, 1, "#96081ba4")
|
||||||
|
self.goodtxt_rect = self.goodtxt.get_rect()
|
||||||
|
self.goodtxt_rect.center = self.parent.rect.center
|
||||||
|
self.goodtxt_rect = self.goodtxt_rect.move(Coords(0, -100))
|
||||||
|
|
||||||
def draw(self):
|
def draw(self):
|
||||||
if not self.active:
|
if not self.active:
|
||||||
return
|
return
|
||||||
self.parent.surface.blit(self.image, self.rect)
|
if self.scene.coins.all_collected:
|
||||||
|
self.parent.surface.blit(self.image, self.rect)
|
||||||
|
self.parent.surface.blit(self.goodtxt, self.goodtxt_rect)
|
||||||
self.parent.surface.blit(self.surface, self.rect)
|
self.parent.surface.blit(self.surface, self.rect)
|
||||||
self.parent.surface.blit(self.hint, self.hint_rect)
|
self.parent.surface.blit(self.hint, self.hint_rect)
|
||||||
|
|
||||||
@ -439,7 +566,7 @@ 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):
|
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)
|
||||||
@ -447,6 +574,7 @@ class Scene(GameObject):
|
|||||||
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)
|
resize_img(self.assets, "brick.png", box_sz)
|
||||||
|
resize_img(self.assets, "coin.png", box_sz)
|
||||||
|
|
||||||
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)
|
resize_img(self.assets, "ghost.png", hero_sz)
|
||||||
@ -461,12 +589,15 @@ class Scene(GameObject):
|
|||||||
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.end = EndLevel(self)
|
self.end = EndLevel(self)
|
||||||
self.end.active = False
|
self.end.active = False
|
||||||
self.want_new_level = False
|
self.want_new_level = False
|
||||||
self.exit_rect = self.get_exit_rect()
|
self.exit_rect = self.get_exit_rect()
|
||||||
# для тестирования экрана конца уровня
|
# #для тестирования экрана конца уровня
|
||||||
# self.hero.coords = Coords(*self.exit_rect.topleft) + Coords(
|
# self.hero.coords = Coords(*self.exit_rect.topleft) + Coords(
|
||||||
# -self.box_sz.x // 2, 5
|
# -self.box_sz.x // 2, 5
|
||||||
# )
|
# )
|
||||||
@ -495,9 +626,9 @@ class Scene(GameObject):
|
|||||||
if self.level_completed:
|
if self.level_completed:
|
||||||
self.end.draw()
|
self.end.draw()
|
||||||
else:
|
else:
|
||||||
# pygame.draw.rect(self._surface, pygame.Color("#42c53d25"), self.get_exit_rect())
|
|
||||||
self.hero.draw()
|
self.hero.draw()
|
||||||
self.walls.draw()
|
self.walls.draw()
|
||||||
|
self.coins.draw()
|
||||||
|
|
||||||
def handle_event(self, event: pygame.event.Event):
|
def handle_event(self, event: pygame.event.Event):
|
||||||
if self.done:
|
if self.done:
|
||||||
@ -525,11 +656,12 @@ def game(assets):
|
|||||||
pygame.init()
|
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
|
||||||
pygame.display.set_caption("Движение рисунка на Pygame")
|
pygame.display.set_caption("Движение рисунка на Pygame")
|
||||||
|
|
||||||
want_new_level = True
|
want_new_level = True
|
||||||
while want_new_level:
|
while want_new_level:
|
||||||
scene = Scene(assets, screen_sz, maze_sz)
|
scene = Scene(assets, screen_sz, maze_sz, coins_count)
|
||||||
scene.event_loop()
|
scene.event_loop()
|
||||||
want_new_level = scene.want_new_level
|
want_new_level = scene.want_new_level
|
||||||
|
|
||||||
@ -542,6 +674,7 @@ def main():
|
|||||||
"ghost.png",
|
"ghost.png",
|
||||||
"brick.png",
|
"brick.png",
|
||||||
"win.png",
|
"win.png",
|
||||||
|
"coin.png",
|
||||||
]
|
]
|
||||||
with get_assets(assets) as assets:
|
with get_assets(assets) as assets:
|
||||||
game(assets)
|
game(assets)
|
||||||
|
Loading…
Reference in New Issue
Block a user