From: Thomas Rimelen Date: Thu, 8 Oct 2026 09:51:14 +0000 (+0200) Subject: Ghost chase animation and per ghost status X-Git-Url: https://git.uwuaxy.net/Project%20Management.png?a=commitdiff_plain;h=50b1d76baabb6e9ca0c3b2527e2ac183da61411f;p=axy%2Fft%2Fpacman.git Ghost chase animation and per ghost status --- diff --git a/src/pacman/game/__init__.py b/src/pacman/game/__init__.py index 830c98d..82ffc14 100644 --- a/src/pacman/game/__init__.py +++ b/src/pacman/game/__init__.py @@ -66,15 +66,6 @@ class Score(Resource): score: int = 0 -@dataclass -class GameStatus(Resource): - tick: int = 0 - cycle_chase: int = 60 * 10 - cycle_wander: int = 60 * 10 - chase: bool = False - flee: bool = False - - @dataclass class Inputs(Resource): inputs: dict[int, float] @@ -104,6 +95,15 @@ class Pacman(Component): pass +@dataclass +class GhostStatus(Component): + tick: int = 0 + cycle_chase: int = 60 * 10 + cycle_wander: int = 60 * 10 + chase: bool = False + flee: bool = False + + @dataclass class Ghost(Component): variant: GhostVariant @@ -246,7 +246,7 @@ def spawn_pacgums( def setup_maze(world: World) -> None: - world.add_system(create_maze)(MazeGenerator((12, 12))) + world.add_system(create_maze)(MazeGenerator((14, 14))) def move_in_motion( @@ -276,14 +276,13 @@ def update_tile_pos( def move_to_target( - entities: Query[tuple[TargetTile, InMotion, Coord2D]], + entities: Query[tuple[TargetTile, InMotion, Coord2D, GhostStatus]], cells: Query[tuple[Cell, Coord2D]], maze_q: Query[Maze], - status: GameStatus, ) -> None: if (maze := maze_q.single()) is None: return - for target, motion, pos in entities: + for target, motion, pos, status in entities: cell, cell_pos = cells[motion.pos] if cell_pos.xy.distance_squared_to(pos.xy) > 0.01: continue @@ -369,6 +368,7 @@ def spawn_ghosts( TilePos, Ghost, TargetTile, + GhostStatus, ], [ ( @@ -383,7 +383,7 @@ def spawn_ghosts( ) ] for direction in "URDL" - ], + ] + [[assets.load("./asset/enemy/ghost_blue.png")]], 6, ), ShouldRender(), @@ -392,6 +392,7 @@ def spawn_ghosts( TilePos(maze._cells[pos]), Ghost(variant, pos), TargetTile(pos), + GhostStatus(), ) for variant, pos in [ (GhostVariant.A, (0, 0)), @@ -450,9 +451,8 @@ def collect_superpacgum( world: World, pacgums: Query[tuple[CoordAbs2D, Entity], SuperPacGum], pacmans: Query[CoordAbs2D, Pacman], - ghosts: Query[InMotion, Ghost], + ghosts: Query[tuple[InMotion, GhostStatus], Ghost], score: Score, - status: GameStatus, ) -> None: collided = [ pacgum @@ -462,12 +462,12 @@ def collect_superpacgum( ] score.score += len(collided * 10) if len(collided) > 0: - status.flee = True - status.tick = 60 * 8 - for ghost in ghosts: + for ghost, status in ghosts: tmp = ghost.src ghost.src = ghost.pos ghost.pos = tmp + status.flee = True + status.tick = 60 * 8 world.despawn_many(collided) @@ -488,20 +488,21 @@ def level_is_finished(pacgums: Query[SuperPacGum | PacGum]) -> bool: def update_ghost_targets( - ghosts: Query[tuple[Ghost, TilePos, TargetTile]], + ghosts: Query[tuple[Ghost, TilePos, TargetTile, GhostStatus]], pacman_q: Query[tuple[InMotion, TilePos], Pacman], cells: Query[Cell], - chase: GameStatus, ) -> None: player = pacman_q.single() if player is None: return player_motion, player_pos = player blinky_pos = next( - pos.pos for ghost, pos, _ in ghosts if ghost.variant == GhostVariant.A + pos.pos + for ghost, pos, _, _ in ghosts + if ghost.variant == GhostVariant.A ) - for ghost, pos, target in ghosts: - if not chase.chase: + for ghost, pos, target, status in ghosts: + if not status.chase: target.pos = ghost.home continue target.pos = ghost.variant.compute_target_tile( @@ -513,23 +514,32 @@ def update_ghost_targets( ) -def update_chase_status(status: GameStatus) -> None: - if status.flee: - if status.tick == 0: - status.flee = False - return - status.tick -= 1 - else: - status.tick += 1 - status.chase = status.tick > status.cycle_wander - if status.tick < (status.cycle_wander + status.cycle_chase): - return +def update_chase_status(status_q: Query[GhostStatus]) -> None: + for status in status_q: + if status.flee: + if status.tick == 0: + status.flee = False + continue + status.tick -= 1 + else: + status.tick += 1 + status.chase = status.tick > status.cycle_wander + if status.tick < (status.cycle_wander + status.cycle_chase): + continue + + status.tick = 0 + if status.cycle_wander > 60 * 4: + status.cycle_wander -= 60 + if status.cycle_chase > 60 * 7: + status.cycle_chase -= 60 + + +def update_ghost_speed(ghost: Query[tuple[MoveSpeed, GhostStatus]]) -> None: + for speed, status in ghost: + speed.pixels_per_frame = 2.5 + if status.flee: + speed.pixels_per_frame = 1.5 - status.tick = 0 - if status.cycle_wander > 60 * 4: - status.cycle_wander -= 60 - if status.cycle_chase > 60 * 7: - status.cycle_chase -= 60 def update_pacman_anim( @@ -540,15 +550,14 @@ def update_pacman_anim( def update_ghost_anim( - ghost_q: Query[tuple[InMotion, AnimationSet], Ghost], + ghost_q: Query[tuple[InMotion, AnimationSet, GhostStatus], Ghost], ) -> None: - for motion, anim in ghost_q: - anim.idx = motion.direction + for motion, anim, status in ghost_q: + anim.idx = motion.direction if not status.flee else 4 def setup_resources(world: World) -> None: world.spawn_resource(Inputs({})) - world.spawn_resource(GameStatus()) world.spawn_resource(Score()) @@ -584,6 +593,7 @@ def run_game() -> None: move_to_target, move_in_motion, update_chase_status, + update_ghost_speed, ) .chain() .in_set(Update),