pub struct ParticleSystem { /* private fields */ }Expand description
A self-contained particle simulation: emitters, a shared particle
pool with a budget, and a deterministic seeded RNG. Host-owned;
per frame call update (pure simulation, no
renderer) then — from PS.1 — sync(&mut SceneRenderer) to mirror
the pool into dynamic sprite instances.
Budget semantics: when the pool is full, spawns are dropped
(never evict a live particle — a visible pop);
dropped_spawns makes the cap observable
instead of silent.
Implementations§
Source§impl ParticleSystem
impl ParticleSystem
Sourcepub fn new(seed: u64) -> Self
pub fn new(seed: u64) -> Self
A system with the given RNG seed and the default budget
(DEFAULT_MAX_PARTICLES). Same seed + same call sequence ⇒
bit-identical simulation.
Sourcepub fn set_max_particles(&mut self, max: usize)
pub fn set_max_particles(&mut self, max: usize)
Set the particle budget. Lowering it below the current live count kills nothing — it only gates future spawns.
Sourcepub fn set_carve_debris_cap(&mut self, cap: usize)
pub fn set_carve_debris_cap(&mut self, cap: usize)
Tune how many debris particles one
carve_debris call may spawn (default
CARVE_DEBRIS_CAP) — the per-explosion load knob. Bigger
carves stride-sample an even spatial subset down to this;
clamped to ≥ 1.
Sourcepub fn add_emitter(&mut self, def: ParticleEmitterDef) -> EmitterId
pub fn add_emitter(&mut self, def: ParticleEmitterDef) -> EmitterId
Register an emitter. SpawnMode::Burst fires immediately.
Sourcepub fn remove_emitter(&mut self, id: EmitterId) -> bool
pub fn remove_emitter(&mut self, id: EmitterId) -> bool
Retire an emitter: it stops spawning immediately and its handle
goes stale, but particles already in flight live out their
lifetimes (the state drains away with the last one). Returns
false on a stale handle.
Sourcepub fn set_emitter_pos(&mut self, id: EmitterId, pos: [f32; 3]) -> bool
pub fn set_emitter_pos(&mut self, id: EmitterId, pos: [f32; 3]) -> bool
Move an emitter (attach effects to moving things). Returns
false on a stale handle.
Sourcepub fn burst(&mut self, id: EmitterId, n: u32) -> u32
pub fn burst(&mut self, id: EmitterId, n: u32) -> u32
Spawn n particles from id right now (any SpawnMode).
Returns how many actually spawned (budget may drop the rest);
0 on a stale handle.
Sourcepub fn update(&mut self, dt: f64)
pub fn update(&mut self, dt: f64)
Advance the simulation by dt seconds: integrate + age + fade
every particle, retire the dead (their facade instances queue
in drain_dead_instances), then
run SpawnMode::Rate emitters. Pure simulation — no facade
calls, unit-testable without a window or GPU. Never collides;
for CollisionMode emitters use
update_with_scene.
Sourcepub fn update_with_scene(&mut self, dt: f64, scene: &Scene)
pub fn update_with_scene(&mut self, dt: f64, scene: &Scene)
update + voxel collision (PS.3): emitters
with a non-None CollisionMode test
each particle’s post-step position against scene’s solid
voxels. See CollisionMode for the sampling caveats.
Sourcepub fn particle_count(&self) -> usize
pub fn particle_count(&self) -> usize
Number of live particles.
Sourcepub fn emitter_count(&self) -> usize
pub fn emitter_count(&self) -> usize
Number of active (non-retired) emitters.
Sourcepub fn dropped_spawns(&self) -> u64
pub fn dropped_spawns(&self) -> u64
Spawns dropped by the budget since construction. A steadily
climbing value means the effect design outruns
set_max_particles.
Sourcepub fn drain_dead_instances(
&mut self,
) -> impl Iterator<Item = SpriteInstanceId> + '_
pub fn drain_dead_instances( &mut self, ) -> impl Iterator<Item = SpriteInstanceId> + '_
Drain the facade instances of particles that died since the
last drain. sync removes each via
remove_sprite_instance;
hosts doing their own rendering can consume it directly.
Sourcepub fn stale_model_kills(&self) -> u64
pub fn stale_model_kills(&self) -> u64
Newborn spawns that failed because the emitter’s
SpriteModelId went stale (the model was removed / the
registry was reset). Each failure kills its particle — a
climbing value means an emitter outlived its model.
Sourcepub fn sync(&mut self, renderer: &mut SceneRenderer)
pub fn sync(&mut self, renderer: &mut SceneRenderer)
Mirror the simulation into renderer (PS.1): despawn the dead,
spawn newborns pre-posed (the documented streaming-spawn
path — no one-frame axis-aligned flash) with their one-time
material/lighting/shadow/tint setup, batch-move everything else
via one
set_sprite_instance_transforms,
and write alpha only for particles whose fade actually changed
(alpha has no batch API). Call after
update, before
render — or use
tick.
Sourcepub fn tick(&mut self, renderer: &mut SceneRenderer, dt: f64)
pub fn tick(&mut self, renderer: &mut SceneRenderer, dt: f64)
Sourcepub fn tick_with_scene(
&mut self,
renderer: &mut SceneRenderer,
dt: f64,
scene: &Scene,
)
pub fn tick_with_scene( &mut self, renderer: &mut SceneRenderer, dt: f64, scene: &Scene, )
update_with_scene +
sync — tick for hosts using
CollisionMode emitters. Call before handing the same scene
to render.
Sourcepub fn carve_debris(
&mut self,
scene: &mut Scene,
grid: GridId,
centre: IVec3,
radius: u32,
outward: Range<f32>,
def: &ParticleEmitterDef,
) -> u32
pub fn carve_debris( &mut self, scene: &mut Scene, grid: GridId, centre: IVec3, radius: u32, outward: Range<f32>, def: &ParticleEmitterDef, ) -> u32
Carve a sphere out of a grid and burst its actual voxel
colours as debris (PS.5) — the “shoot the wall, the wall’s
colours fly off” effect: sample the solid voxels inside the
ball, set_sphere(…, None) them away, then spawn one
def-driven debris particle per sampled voxel, positioned at its
voxel’s world centre (transform-correct for rotated grids),
tinted with its colour, and kicked radially away from the carve
centre at a speed from outward (on top of the def’s normal
velocity terms).
def supplies the model, physics, lifetime and curves;
its pos/shape/spawn/tint are ignored (position and tint
are per-voxel; nothing else auto-spawns — the transient emitter
retires immediately and drains with its last particle).
tint_end still applies, lerping from the voxel colour.
Big carves are stride-sampled down to the system’s debris cap
(CARVE_DEBRIS_CAP by default —
set_carve_debris_cap tunes it)
debris (an even spatial subset, not the first N); the pool
budget then applies on top, counting overflow in
dropped_spawns. Returns how many
debris actually spawned. A stale grid or an all-air ball
carves/spawns nothing.
Sourcepub fn voxel_debris(
&mut self,
sites: &[([f32; 3], Rgb)],
from: [f32; 3],
outward: Range<f32>,
def: &ParticleEmitterDef,
) -> u32
pub fn voxel_debris( &mut self, sites: &[([f32; 3], Rgb)], from: [f32; 3], outward: Range<f32>, def: &ParticleEmitterDef, ) -> u32
Burst a set of world-space voxel sites as debris — the
spawn half of carve_debris, factored
out (DT.3) so a landed island’s voxels can shatter without a
carve: one def-driven particle per site, positioned there,
tinted with the site’s colour, kicked radially away from
from at a speed from outward (a site at from itself
scatters in a random direction).
Same contract as carve_debris (which is now this on top of a
sphere sample+carve): def’s pos/shape/spawn/tint are
ignored, tint_end lerps from the site colour, big sets are
stride-sampled to the debris cap, the pool budget counts
overflow in dropped_spawns. Returns
how many debris actually spawned.
Auto Trait Implementations§
impl Freeze for ParticleSystem
impl RefUnwindSafe for ParticleSystem
impl Send for ParticleSystem
impl Sync for ParticleSystem
impl Unpin for ParticleSystem
impl UnsafeUnpin for ParticleSystem
impl UnwindSafe for ParticleSystem
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more