py_stepik/pygame-wasm/phantomcastle/game/hero.py

139 lines
4.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import pygame
from coords import Coords, Direction
from common import DrawableGameObject, EventHandler
class Hero(DrawableGameObject, EventHandler):
"""объект главного героя"""
def __init__(
self,
coords: Coords,
parent: DrawableGameObject,
assets: dict | None = None,
):
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
self._speed = 1
self.direction = Direction.RIGHT
self.mouse_active = False
# картинка изначально влево, а надо бы начинать со взгляда вправо
self.flip()
def draw(self):
self.parent.surface.blit(self.surface, self.rect)
def _check_collision(self, coords):
"""Проверка пересечения со стенами"""
new_rect = self.rect.copy()
new_rect.topleft = coords
return self.scene.walls.check_collision(new_rect, self.mask)
@property
def speed(self):
return max(self._speed, 1)
@speed.setter
def speed(self, value):
self._speed = min(value, 15)
def _reduce_step(self, coords):
"""Уменьшение шага движения, с целью подойти вплотную к стене"""
delta = coords - self.coords
dx, dy = 0, 0
if abs(delta.x) > 1:
dx = 1 * (delta.x < 0 or -1)
if abs(delta.y) > 1:
dy = 1 * (delta.y < 0 or -1)
return coords + Coords(dx, dy)
def set_coords(self, coords: Coords):
# проверка колизии
has_collision = self._check_collision(coords)
if not has_collision:
super().set_coords(coords)
self.scene.coins.collect(self)
return
# уменьшение шага
while has_collision and coords != self.coords:
coords_new = self._reduce_step(coords)
if coords_new == coords:
return # не могу уменьшить шаг
coords = coords_new
has_collision = self._check_collision(coords)
super().set_coords(coords)
self.scene.coins.collect(self)
def flip(self):
self.looking_right = not self.looking_right
self._surface = pygame.transform.flip(self.surface, flip_x=True, flip_y=False)
def update_direction(self, direction: Direction):
if direction in (Direction.LEFT, Direction.RIGHT):
going_right = direction == Direction.RIGHT
if self.looking_right != going_right:
self.flip()
if direction != self.direction:
self.speed = 0
self.direction = direction
else:
self.speed += 1
def move(self, direction: Direction, step: int = 1):
self.update_direction(direction)
self.coords += direction.as_coords() * step * self.speed // 3
def handle_mouse_event(self, event: pygame.event.Event):
if event.type not in (
pygame.MOUSEBUTTONDOWN,
pygame.MOUSEBUTTONUP,
pygame.MOUSEMOTION,
):
return
match event.type:
case pygame.MOUSEBUTTONDOWN:
self.mouse_active = self.rect.collidepoint(event.pos)
case pygame.MOUSEBUTTONUP:
self.mouse_active = False
case pygame.MOUSEMOTION if self.mouse_active:
rel = Coords(*event.rel)
direction = Direction.from_coords(rel)
if direction:
self.update_direction(direction)
self.coords += rel
def handle_event(self, event: pygame.event.Event):
if not self.active:
return
self.handle_mouse_event(event)
def handle_keys(self, keys_pressed):
if not self.active:
return
wide, short = 3, 1
if keys_pressed[pygame.K_UP]:
self.move(Direction.UP, wide)
if keys_pressed[pygame.K_DOWN]:
self.move(Direction.DOWN, wide)
if keys_pressed[pygame.K_LEFT]:
self.move(Direction.LEFT, wide)
if keys_pressed[pygame.K_RIGHT]:
self.move(Direction.RIGHT, wide)
if keys_pressed[pygame.K_w]:
self.move(Direction.UP, short)
if keys_pressed[pygame.K_s]:
self.move(Direction.DOWN, short)
if keys_pressed[pygame.K_a]:
self.move(Direction.LEFT, short)
if keys_pressed[pygame.K_d]:
self.move(Direction.RIGHT, short)