]> Untitled Git - axy/ft/pacman.git/commitdiff
oranised + collide_ghost added
authorThomas Rimelen <trimelen@k0r1p9.42mulhouse.fr>
Wed, 7 Oct 2026 14:26:05 +0000 (16:26 +0200)
committerThomas Rimelen <trimelen@k0r1p9.42mulhouse.fr>
Wed, 7 Oct 2026 14:26:05 +0000 (16:26 +0200)
src/pacman/game/__init__.py

index a621720486f99ed8b0c550b6627e5d309e71f1cf..830c98d6a910073b9a14e621e517126ef8fd5259 100644 (file)
@@ -25,6 +25,41 @@ from pacman.ecs.schedule import StartupSchedule, UpdateSchedule
 from pacman.ecs.update import PostUpdate, PreUpdate, Update
 from pacman.ecs.world import Component, Entity, Query, Resource, Systems, World
 
+_DIR_OFFSETS = [(0, -1), (1, 0), (0, 1), (-1, 0)]
+
+
+class GhostVariant(Enum):
+    A = auto()
+    B = auto()
+    C = auto()
+    D = auto()
+
+    def compute_target_tile(
+        self,
+        player: tuple[int, int],
+        player_dir: int,
+        pos: tuple[int, int],
+        slf: "Ghost",
+        blinky_pos: tuple[int, int],
+    ) -> tuple[int, int]:
+        match self:
+            case GhostVariant.A:
+                return player
+            case GhostVariant.B:
+                if Vector2(player).distance_squared_to(pos) >= 16:
+                    return player
+                return slf.home
+            case GhostVariant.C:
+                dx, dy = _DIR_OFFSETS[player_dir]
+                x, y = player
+                return (x + 2 * dx, y + 2 * dy)
+            case GhostVariant.D:
+                dx, dy = _DIR_OFFSETS[player_dir]
+                x, y = player
+                x_target, y_target = (x + 2 * dx, y + 2 * dy)
+                x_blinky, y_blinky = blinky_pos
+                return (x_target * 2 - x_blinky, y_target * 2 - y_blinky)
+
 
 @dataclass
 class Score(Resource):
@@ -40,6 +75,63 @@ class GameStatus(Resource):
     flee: bool = False
 
 
+@dataclass
+class Inputs(Resource):
+    inputs: dict[int, float]
+
+    def get_dir(self) -> int | None:
+        lookup = {K_w: 0, K_d: 1, K_s: 2, K_a: 3}
+        res = sorted(
+            ((k, v) for k, v in self.inputs.items() if k in lookup),
+            key=lambda e: e[1],
+            reverse=True,
+        )
+        if len(res) == 0:
+            return None
+        return lookup[res[0][0]]
+
+
+class PacGum(Component):
+    pass
+
+
+class SuperPacGum(Component):
+    pass
+
+
+@dataclass
+class Pacman(Component):
+    pass
+
+
+@dataclass
+class Ghost(Component):
+    variant: GhostVariant
+    home: tuple[int, int]
+
+
+@dataclass
+class TargetTile(Component):
+    pos: tuple[int, int]
+
+
+@dataclass
+class TilePos(Component):
+    pos: Entity
+
+
+@dataclass
+class InMotion(Component):
+    src: Entity
+    pos: Entity
+    direction: int
+
+
+@dataclass
+class MoveSpeed(Component):
+    pixels_per_frame: float
+
+
 class Maze(Component):
     def __init__(self, x: int, y: int) -> None:
         self._cells: dict[tuple[int, int], Entity] = {}
@@ -47,9 +139,6 @@ class Maze(Component):
         self._y = y
 
 
-_DIR_OFFSETS = [(0, -1), (1, 0), (0, 1), (-1, 0)]
-
-
 @dataclass
 class Cell(Component):
     n: int
@@ -63,14 +152,6 @@ class Cell(Component):
         return [(1 & (self.n >> i)) == 1 for i in range(4)]
 
 
-class PacGum(Component):
-    pass
-
-
-class SuperPacGum(Component):
-    pass
-
-
 def create_maze(
     world: World, assets: Assets[Sprite2D]
 ) -> Callable[[MazeGenerator], Entity]:
@@ -168,28 +249,6 @@ def setup_maze(world: World) -> None:
     world.add_system(create_maze)(MazeGenerator((12, 12)))
 
 
-@dataclass
-class TargetTile(Component):
-    pos: tuple[int, int]
-
-
-@dataclass
-class TilePos(Component):
-    pos: Entity
-
-
-@dataclass
-class InMotion(Component):
-    src: Entity
-    pos: Entity
-    direction: int
-
-
-@dataclass
-class MoveSpeed(Component):
-    pixels_per_frame: float
-
-
 def move_in_motion(
     entities: Query[tuple[InMotion, Coord2D, MoveSpeed]],
     positions: Query[Coord2D],
@@ -220,7 +279,7 @@ def move_to_target(
     entities: Query[tuple[TargetTile, InMotion, Coord2D]],
     cells: Query[tuple[Cell, Coord2D]],
     maze_q: Query[Maze],
-    status: GameStatus
+    status: GameStatus,
 ) -> None:
     if (maze := maze_q.single()) is None:
         return
@@ -254,27 +313,6 @@ def move_to_target(
         motion.direction = nxt_dir
 
 
-@dataclass
-class Inputs(Resource):
-    inputs: dict[int, float]
-
-    def get_dir(self) -> int | None:
-        lookup = {K_w: 0, K_d: 1, K_s: 2, K_a: 3}
-        res = sorted(
-            ((k, v) for k, v in self.inputs.items() if k in lookup),
-            key=lambda e: e[1],
-            reverse=True,
-        )
-        if len(res) == 0:
-            return None
-        return lookup[res[0][0]]
-
-
-@dataclass
-class Pacman(Component):
-    pass
-
-
 def spawn_pacman(
     world: World, assets: Assets[Sprite2D], maze_q: Query[Maze]
 ) -> None:
@@ -292,7 +330,7 @@ def spawn_pacman(
             TilePos,
         ],
         (
-            Coord2D(0, 0, -10),
+            Coord2D(3 * 64, 3 * 64, -10),
             CoordAbs2D(),
             AnimationSet(
                 [
@@ -308,52 +346,13 @@ def spawn_pacman(
             ),
             Pacman(),
             ShouldRender(),
-            InMotion(maze._cells[(0, 0)], maze._cells[(0, 0)], 1),
+            InMotion(maze._cells[(3, 3)], maze._cells[(3, 3)], 1),
             MoveSpeed(3.0),
-            TilePos(maze._cells[(0, 0)]),
+            TilePos(maze._cells[(3, 3)]),
         ),
     )
 
 
-class GhostVariant(Enum):
-    A = auto()
-    B = auto()
-    C = auto()
-    D = auto()
-
-    def compute_target_tile(
-        self,
-        player: tuple[int, int],
-        player_dir: int,
-        pos: tuple[int, int],
-        slf: "Ghost",
-        blinky_pos: tuple[int, int],
-    ) -> tuple[int, int]:
-        match self:
-            case GhostVariant.A:
-                return player
-            case GhostVariant.B:
-                if Vector2(player).distance_squared_to(pos) >= 16:
-                    return player
-                return slf.home
-            case GhostVariant.C:
-                dx, dy = _DIR_OFFSETS[player_dir]
-                x, y = player
-                return (x + 2 * dx, y + 2 * dy)
-            case GhostVariant.D:
-                dx, dy = _DIR_OFFSETS[player_dir]
-                x, y = player
-                x_target, y_target = (x + 2 * dx, y + 2 * dy)
-                x_blinky, y_blinky = blinky_pos
-                return (x_target * 2 - x_blinky, y_target * 2 - y_blinky)
-
-
-@dataclass
-class Ghost(Component):
-    variant: GhostVariant
-    home: tuple[int, int]
-
-
 def spawn_ghosts(
     world: World, assets: Assets[Sprite2D], maze_q: Query[Maze]
 ) -> None:
@@ -457,9 +456,9 @@ def collect_superpacgum(
 ) -> None:
     collided = [
         pacgum
-        for coord, pacgum in pacgums
-        for pos in pacmans
-        if pos._vec.xy.distance_squared_to(coord._vec.xy) < 100
+        for pacgum_pos, pacgum in pacgums
+        for pacman_pos in pacmans
+        if pacman_pos._vec.xy.distance_squared_to(pacgum_pos._vec.xy) < 100
     ]
     score.score += len(collided * 10)
     if len(collided) > 0:
@@ -472,6 +471,18 @@ def collect_superpacgum(
     world.despawn_many(collided)
 
 
+def collide_ghost(
+    pacmans: Query[CoordAbs2D, Pacman], ghosts: Query[CoordAbs2D, Ghost]
+) -> None:
+    for pacman_pos in pacmans:
+        for ghost_pos in ghosts:
+            if (
+                pacman_pos._vec.xy.distance_squared_to(ghost_pos._vec.xy)
+                < 3600
+            ):
+                pass
+
+
 def level_is_finished(pacgums: Query[SuperPacGum | PacGum]) -> bool:
     return next(iter(pacgums), None) is None
 
@@ -529,9 +540,9 @@ def update_pacman_anim(
 
 
 def update_ghost_anim(
-    pacman_q: Query[tuple[InMotion, AnimationSet], Ghost],
+    ghost_q: Query[tuple[InMotion, AnimationSet], Ghost],
 ) -> None:
-    for motion, anim in pacman_q:
+    for motion, anim in ghost_q:
         anim.idx = motion.direction
 
 
@@ -580,6 +591,8 @@ def run_game() -> None:
         Systems(update_pacman_anim, update_ghost_anim)
         .before(GraphicsSystems)
         .in_set(PostUpdate),
-        Systems(collect_pacgum, collect_superpacgum).after(PropagateTransform),
+        Systems(collect_pacgum, collect_superpacgum, collide_ghost).after(
+            PropagateTransform
+        ),
         Systems(victory).run_if(level_is_finished),
     ).run_main()