nodes/particles.pyΒΆ
Part of Clear Code Zelda.
1"""Particle effect node: plays a folder of frames once and self-destructs.
2
3Uses the same FolderSprite primitive as the player. Lifetime is computed
4from frame count and FPS.
5"""
6
7from __future__ import annotations
8
9from random import choice
10
11from support import import_folder
12
13from simvx.core import Node2D, Vec2
14
15from .anim_sprite import FolderSprite
16
17
18class ParticleEffect(Node2D):
19 """One-shot animated particle. Destroys itself when the animation finishes."""
20
21 def __init__(self, frames: list[str], position: Vec2, fps: float = 12.0, size: int = 64, **kwargs):
22 super().__init__(position=position, **kwargs)
23 self._frames = frames
24 self._fps = fps
25 self._size = size
26 self._sprite: FolderSprite | None = None
27
28 def on_ready(self):
29 self._sprite = self.add_child(
30 FolderSprite(
31 frames=self._frames,
32 fps=self._fps,
33 loop=False,
34 width=self._size,
35 height=self._size,
36 name="ParticleSprite",
37 )
38 )
39
40 def on_update(self, dt: float):
41 if self._sprite and self._sprite.finished:
42 self.destroy()
43
44
45class AnimationLibrary:
46 """Caches the per-effect frame lists. One instance lives on the level."""
47
48 def __init__(self):
49 self.frames: dict[str, list[str]] = {}
50 self._populate()
51
52 def _populate(self):
53 names = (
54 "flame",
55 "aura",
56 "heal",
57 "claw",
58 "slash",
59 "sparkle",
60 "leaf_attack",
61 "thunder",
62 "squid",
63 "raccoon",
64 "spirit",
65 "bamboo",
66 "leaf1",
67 "leaf2",
68 "leaf3",
69 "leaf4",
70 "leaf5",
71 "leaf6",
72 )
73 for n in names:
74 # Some effects live under a "frames" subfolder.
75 for sub in (f"{n}/frames", n):
76 fs = import_folder(sub)
77 if fs:
78 self.frames[n] = fs
79 break
80
81 def grass_leaf_frames(self) -> list[str]:
82 leaves = [self.frames[n] for n in ("leaf1", "leaf2", "leaf3", "leaf4", "leaf5", "leaf6") if n in self.frames]
83 return choice(leaves) if leaves else []
84
85 def get(self, name: str) -> list[str]:
86 return self.frames.get(name, [])