def add_components[T: Components](
self, ty: type[T], components: list[tuple["Entity", T]]
- ) -> None:
+ ) -> Callable[[], None]:
dst, comps_ty = self._compute_add(ty)
comps = [components_iter(e) for _, e in components]
positions = [self._positions[e] for e, _ in components]
dst._extend(cb)
self._discard(positions)
- for k, lst in moved_comps:
- hooks = self._world._components_cache[k][1]
- hooks._remove(
- zip((dst._entities[i] for i in itr), lst, strict=True)
- )
- for k in comps_ty:
- lst = dst._components[k]
- hooks = self._world._components_cache[k][1]
- hooks._insert((dst._entities[i], lst[i]) for i in itr)
+ def res() -> None:
+ for k, lst in moved_comps:
+ hooks = self._world._components_cache[k][1]
+ hooks._remove(
+ zip((dst._entities[i] for i in itr), lst, strict=True)
+ )
+ for k in comps_ty:
+ lst = dst._components[k]
+ hooks = self._world._components_cache[k][1]
+ hooks._insert((dst._entities[i], lst[i]) for i in itr)
+
+ return res
def remove_components[T: Components](
- self, ty: type[T], entities: Iterable["Entity"]
- ) -> None:
+ self, ty: type[T], entities: list["Entity"]
+ ) -> Callable[[], None]:
dst, comps_ty = self._compute_remove(ty)
positions = [self._positions[e] for e in entities]
]
dst._extend(cb)
self._discard(positions)
- for k, comp in zip(comps_ty, removed_comps, strict=True):
- hooks = self._world._components_cache[k][1]
- hooks._remove(zip(removed_ents, comp, strict=True))
- def remove(self, entities: list["Entity"]) -> None:
+ def res() -> None:
+ for k, comp in zip(comps_ty, removed_comps, strict=True):
+ hooks = self._world._components_cache[k][1]
+ hooks._remove(zip(removed_ents, comp, strict=True))
+
+ return res
+
+ def remove(self, entities: list["Entity"]) -> Callable[[], None]:
+ entities = [e for e in entities if e in self._positions]
positions = [self._positions[e] for e in entities]
comps = [
(
self._discard(positions)
for ent in entities:
del self._world._entities[ent]
- for hook, comp in comps:
- hook._remove(zip(entities, comp, strict=True))
+
+ def res() -> None:
+ for hook, comp in comps:
+ hook._remove(zip(entities, comp, strict=True))
+
+ return res
def _extend(
self,
self._base_archetype.add_components(
cast(type[Components], ty),
list(zip(ents, cast(list[Components], comps), strict=True)),
- )
+ )()
return ents
def despawn(self, ent: Entity) -> None:
if arch not in archs:
archs[arch] = []
archs[arch].append(ent)
- for arch, lst in archs.items():
- arch.remove(lst)
+ cbs = [arch.remove(lst) for arch, lst in archs.items()]
+ for cb in cbs:
+ cb()
def insert[T: Components](self, ty: type[T], ent: Entity, comp: T) -> None:
self.insert_many(ty, [(ent, comp)])
archs[arch] = []
archs[arch].append((ent, comp))
- for arch, lst in archs.items():
- arch.add_components(ty, lst)
+ cbs = [arch.add_components(ty, lst) for arch, lst in archs.items()]
+ for cb in cbs:
+ cb()
def remove[T: Components](self, ty: type[T], ent: Entity) -> None:
self.remove_many(ty, [ent])
) -> None:
archs: dict[Archetype, list[Entity]] = {}
for ent in comps:
+ if ent not in self._entities:
+ continue
arch = self._entities[ent]
if arch not in archs:
archs[arch] = []
archs[arch].append(ent)
- for arch, lst in archs.items():
- arch.remove_components(ty, lst)
+ cbs = [arch.remove_components(ty, lst) for arch, lst in archs.items()]
+ for cb in cbs:
+ cb()
def _sys_extractors[T](
self, system: System[T]
WindowEvents,
graphics_plugins,
)
-from pacman.ecs.hierarchy import ChildOf
+from pacman.ecs.hierarchy import ChildOf, Hierarchy
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
+from pacman.ecs.world import (
+ CommandQueue,
+ Component,
+ Entity,
+ Query,
+ Resource,
+ Systems,
+ World,
+)
_DIR_OFFSETS = [(0, -1), (1, 0), (0, 1), (-1, 0)]
def setup_maze(world: World) -> None:
- world.add_system(create_maze)(MazeGenerator((14, 14)))
+ world.add_system(create_maze)(MazeGenerator((5, 5)))
def move_in_motion(
def spawn_pacman(
- world: World, assets: Assets[Sprite2D], maze_q: Query[Maze]
+ world: World, assets: Assets[Sprite2D], maze_q: Query[tuple[Maze, Entity]]
) -> None:
- if (maze := maze_q.single()) is None:
+ if (maze_t := maze_q.single()) is None:
return
+ maze, maze_ent = maze_t
world.spawn(
tuple[
Coord2D,
InMotion,
MoveSpeed,
TilePos,
+ ChildOf,
],
(
Coord2D(3 * 64, 3 * 64, -10),
InMotion(maze._cells[(3, 3)], maze._cells[(3, 3)], 1),
MoveSpeed(3.0),
TilePos(maze._cells[(3, 3)]),
+ ChildOf(maze_ent),
),
)
def spawn_ghosts(
- world: World, assets: Assets[Sprite2D], maze_q: Query[Maze]
+ world: World, assets: Assets[Sprite2D], maze_q: Query[tuple[Maze, Entity]]
) -> None:
- if (maze := maze_q.single()) is None:
+ if (maze_t := maze_q.single()) is None:
return
+ maze, maze_ent = maze_t
world.spawn_many(
tuple[
Coord2D,
Ghost,
TargetTile,
GhostStatus,
+ ChildOf,
],
[
(
Ghost(variant, pos, maze._cells[pos]),
TargetTile(pos),
GhostStatus(),
+ ChildOf(maze_ent),
)
for variant, pos in [
(GhostVariant.A, (0, 0)),
def collide_ghost(
pacmans: Query[CoordAbs2D, Pacman],
ghosts: Query[
- tuple[CoordAbs2D, GhostStatus, Ghost, InMotion, Coord2D], Ghost
+ tuple[CoordAbs2D, GhostStatus, Ghost, InMotion, Coord2D],
+ Ghost,
],
+ score: Score,
) -> None:
for pacman_pos in pacmans:
for ghost_pos, status, ghost, motion, pos in ghosts:
case GhostState.wander | GhostState.chase:
# TODO: kill pacman
print("Pacman hit")
+
case GhostState.flee:
+ score.score += 100 # FIXME
status.state = GhostState.dead
status.tick = 0
motion.src = ghost.home_entity
del inputs.inputs[key]
-def victory() -> None:
- return
+def victory(
+ hierarchy: Hierarchy[tuple[()]],
+ mazes: Query[Entity, Maze],
+ queue: CommandQueue,
+) -> None:
+ for maze in mazes:
+ queue.queue(hierarchy.despawn_with_children(maze))
def run_game() -> None: