phantomcastle: control by mouse

This commit is contained in:
Dmitry Belyaev 2024-04-04 22:45:34 +03:00
parent 6c55cc750e
commit 9482dd6c0d
1 changed files with 93 additions and 26 deletions

View File

@ -145,6 +145,21 @@ class Coords(NamedTuple):
def transform(self, ref: "Coords"):
return self * ref
def dir_norm(self):
"""нормализация вектора, но только для получения направления
x, y могут быть только -1, 0, 1
может быть только направление по горизонтали либо по вертикали
либо без направления
"""
src = self
if self.x and self.y:
src = (
self.__class__(self.x, 0)
if abs(self.x) > abs(self.y)
else self.__class__(0, self.y)
)
return self.__class__(*((n > 0) - (n < 0) for n in src))
@classmethod
def zero(cls):
return cls(0, 0)
@ -236,6 +251,18 @@ class Direction(Enum):
case Direction.DOWN:
return Coords(0, 1)
@staticmethod
def from_coords(coords: Coords) -> Optional["Direction"]:
match coords.dir_norm():
case Coords(-1, 0):
return Direction.LEFT
case Coords(1, 0):
return Direction.RIGHT
case Coords(0, -1):
return Direction.UP
case Coords(0, 1):
return Direction.DOWN
class SurfaceWithRect(NamedTuple):
surface: pygame.Surface
@ -331,6 +358,7 @@ class Hero(DrawableGameObject, EventHandler):
self.looking_right = False
self._speed = 1
self.direction = Direction.RIGHT
self.mouse_active = False
# картинка изначально влево, а надо бы начинать со взгляда вправо
self.flip()
@ -365,7 +393,9 @@ class Hero(DrawableGameObject, EventHandler):
# проверка колизии
has_collision = self._check_collision(coords)
if not has_collision:
return super().set_coords(coords)
super().set_coords(coords)
self.scene.coins.collect(self)
return
# уменьшение шага
while has_collision and coords != self.coords:
@ -375,6 +405,7 @@ class Hero(DrawableGameObject, EventHandler):
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
@ -395,31 +426,53 @@ class Hero(DrawableGameObject, EventHandler):
def move(self, direction: Direction, step: int = 1):
self.update_direction(direction)
self.coords += direction.as_coords() * step * self.speed // 3
self.scene.coins.collect(self)
def handle_keyboard_event(self, event: pygame.event.Event):
wide, short = 3, 1
if event.type != pygame.KEYDOWN:
return
match event.key:
case pygame.K_UP:
self.move(Direction.UP, wide)
case pygame.K_DOWN:
self.move(Direction.DOWN, wide)
case pygame.K_LEFT:
self.move(Direction.LEFT, wide)
case pygame.K_RIGHT:
self.move(Direction.RIGHT, wide)
case pygame.K_w:
self.move(Direction.UP, short)
case pygame.K_s:
self.move(Direction.DOWN, short)
case pygame.K_a:
self.move(Direction.LEFT, short)
case pygame.K_d:
self.move(Direction.RIGHT, short)
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
wide, short = 3, 1
if event.type == pygame.KEYDOWN:
match event.key:
case pygame.K_UP:
self.move(Direction.UP, wide)
case pygame.K_DOWN:
self.move(Direction.DOWN, wide)
case pygame.K_LEFT:
self.move(Direction.LEFT, wide)
case pygame.K_RIGHT:
self.move(Direction.RIGHT, wide)
case pygame.K_w:
self.move(Direction.UP, short)
case pygame.K_s:
self.move(Direction.DOWN, short)
case pygame.K_a:
self.move(Direction.LEFT, short)
case pygame.K_d:
self.move(Direction.RIGHT, short)
self.handle_keyboard_event(event)
self.handle_mouse_event(event)
class WallBlock(DrawableGameObject):
@ -438,6 +491,7 @@ class WallBlock(DrawableGameObject):
# уменьшаем размер монетки
sf = Coords(1, 1)
self._surface, self.rect = self.scene.scale_box(self.surface, self.rect, sf)
self._mask = pygame.mask.Mask(self.rect.size, fill=True)
def draw(self):
self.parent.surface.blit(self.surface, self.rect)
@ -646,13 +700,26 @@ class EndLevelMenu(DrawableGameObject, EventHandler):
self.stats_label = self._create_stats_label()
self.stats_label.draw_to(self.parent.surface)
def request_new_level(self):
self.scene.want_new_level = True
self.scene.done = True
def handle_keyboard_event(self, event: pygame.event.Event):
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_n:
self.request_new_level()
def handle_mouse_event(self, event: pygame.event.Event):
if event.type == pygame.MOUSEBUTTONDOWN and self.keys_hint.rect.collidepoint(
event.pos
):
self.request_new_level()
def handle_event(self, event: pygame.event.Event):
if not self.active:
return
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_n:
self.parent.want_new_level = True
self.parent.done = True
self.handle_keyboard_event(event)
self.handle_mouse_event(event)
class Scene(DrawableGameObject, EventHandler):