phantomcastle: universal version + split
This commit is contained in:
138
pygame-wasm/phantomcastle/game/hero.py
Normal file
138
pygame-wasm/phantomcastle/game/hero.py
Normal file
@@ -0,0 +1,138 @@
|
||||
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)
|
||||
Reference in New Issue
Block a user