From: Thomas Rimelen Date: Mon, 5 Oct 2026 13:52:47 +0000 (+0200) Subject: pacgum collision and chases added X-Git-Url: https://git.uwuaxy.net/Project%20Status.png?a=commitdiff_plain;h=178dbaaf77bc2e2952d58b1d24949ef0b928ae6b;p=axy%2Fft%2Fpacman.git pacgum collision and chases added --- diff --git a/src/pacman/game/__init__.py b/src/pacman/game/__init__.py index a21efe0..a621720 100644 --- a/src/pacman/game/__init__.py +++ b/src/pacman/game/__init__.py @@ -1,7 +1,7 @@ from collections.abc import Callable from dataclasses import dataclass from enum import Enum, auto -from random import random +from random import random, shuffle from time import time from mazegenerator import MazeGenerator # type: ignore[import-untyped] @@ -10,7 +10,7 @@ from pygame.math import clamp from pacman.ecs import minimal_plugins from pacman.ecs.assets import Assets -from pacman.ecs.coord import Coord2D, CoordAbs2D +from pacman.ecs.coord import Coord2D, CoordAbs2D, PropagateTransform from pacman.ecs.graphics import ( AnimationSet, GraphicsSystems, @@ -26,6 +26,20 @@ from pacman.ecs.update import PostUpdate, PreUpdate, Update from pacman.ecs.world import Component, Entity, Query, Resource, Systems, World +@dataclass +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 + + class Maze(Component): def __init__(self, x: int, y: int) -> None: self._cells: dict[tuple[int, int], Entity] = {} @@ -151,7 +165,7 @@ def spawn_pacgums( def setup_maze(world: World) -> None: - world.add_system(create_maze)(MazeGenerator()) + world.add_system(create_maze)(MazeGenerator((12, 12))) @dataclass @@ -206,6 +220,7 @@ def move_to_target( entities: Query[tuple[TargetTile, InMotion, Coord2D]], cells: Query[tuple[Cell, Coord2D]], maze_q: Query[Maze], + status: GameStatus ) -> None: if (maze := maze_q.single()) is None: return @@ -229,6 +244,10 @@ def move_to_target( ) ), ) + if status.flee: + lst = candidates[:-1] + shuffle(lst) + candidates = lst + [candidates[-1]] nxt, nxt_dir = candidates[0] motion.src = motion.pos motion.pos = nxt @@ -314,7 +333,7 @@ class GhostVariant(Enum): case GhostVariant.A: return player case GhostVariant.B: - if Vector2(player).distance_squared_to(pos) >= 64: + if Vector2(player).distance_squared_to(pos) >= 16: return player return slf.home case GhostVariant.C: @@ -326,7 +345,7 @@ class GhostVariant(Enum): x, y = player x_target, y_target = (x + 2 * dx, y + 2 * dy) x_blinky, y_blinky = blinky_pos - return ((x_target - x_blinky) * 2, (y_target - y_blinky) * 2) + return (x_target * 2 - x_blinky, y_target * 2 - y_blinky) @dataclass @@ -412,19 +431,56 @@ def move_pacman( motion.direction = direction -@dataclass -class ChaseStatus(Resource): - tick: int = 0 - cycle_chase: int = 60 * 10 - cycle_wander: int = 60 * 10 - chase: bool = False +def collect_pacgum( + world: World, + pacgums: Query[tuple[CoordAbs2D, Entity], PacGum], + pacmans: Query[CoordAbs2D, Pacman], + score: Score, +) -> None: + collided = [ + pacgum + for coord, pacgum in pacgums + for pos in pacmans + if pos._vec.xy.distance_squared_to(coord._vec.xy) < 100 + ] + score.score += len(collided) + world.despawn_many(collided) + + +def collect_superpacgum( + world: World, + pacgums: Query[tuple[CoordAbs2D, Entity], SuperPacGum], + pacmans: Query[CoordAbs2D, Pacman], + ghosts: Query[InMotion, Ghost], + score: Score, + status: GameStatus, +) -> None: + collided = [ + pacgum + for coord, pacgum in pacgums + for pos in pacmans + if pos._vec.xy.distance_squared_to(coord._vec.xy) < 100 + ] + score.score += len(collided * 10) + if len(collided) > 0: + status.flee = True + status.tick = 60 * 8 + for ghost in ghosts: + tmp = ghost.src + ghost.src = ghost.pos + ghost.pos = tmp + world.despawn_many(collided) + + +def level_is_finished(pacgums: Query[SuperPacGum | PacGum]) -> bool: + return next(iter(pacgums), None) is None def update_ghost_targets( ghosts: Query[tuple[Ghost, TilePos, TargetTile]], pacman_q: Query[tuple[InMotion, TilePos], Pacman], cells: Query[Cell], - chase: ChaseStatus, + chase: GameStatus, ) -> None: player = pacman_q.single() if player is None: @@ -446,16 +502,23 @@ def update_ghost_targets( ) -def update_chase_status(status: ChaseStatus) -> None: - status.tick += 1 - status.chase = status.tick > status.cycle_wander - if status.tick < (status.cycle_wander + status.cycle_chase): - return - 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_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 + + 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( @@ -474,7 +537,8 @@ def update_ghost_anim( def setup_resources(world: World) -> None: world.spawn_resource(Inputs({})) - world.spawn_resource(ChaseStatus()) + world.spawn_resource(GameStatus()) + world.spawn_resource(Score()) def update_inputs(inputs: Inputs, events: WindowEvents) -> None: @@ -485,6 +549,10 @@ def update_inputs(inputs: Inputs, events: WindowEvents) -> None: del inputs.inputs[key] +def victory() -> None: + return + + def run_game() -> None: World().with_plugins(graphics_plugins, minimal_plugins).with_systems( StartupSchedule, @@ -512,4 +580,6 @@ def run_game() -> None: Systems(update_pacman_anim, update_ghost_anim) .before(GraphicsSystems) .in_set(PostUpdate), + Systems(collect_pacgum, collect_superpacgum).after(PropagateTransform), + Systems(victory).run_if(level_is_finished), ).run_main()