Skip to main content

ParticleSystem

Struct ParticleSystem 

Source
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

Source

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.

Source

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.

Source

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.

Source

pub fn add_emitter(&mut self, def: ParticleEmitterDef) -> EmitterId

Register an emitter. SpawnMode::Burst fires immediately.

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn particles(&self) -> &[Particle]

The live particles, unordered (the pool swap-removes).

Source

pub fn particle_count(&self) -> usize

Number of live particles.

Source

pub fn emitter_count(&self) -> usize

Number of active (non-retired) emitters.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn tick(&mut self, renderer: &mut SceneRenderer, dt: f64)

update + sync in one call — the per-frame default, named after the facade’s own tick.

Source

pub fn tick_with_scene( &mut self, renderer: &mut SceneRenderer, dt: f64, scene: &Scene, )

update_with_scene + synctick for hosts using CollisionMode emitters. Call before handing the same scene to render.

Source

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.

Source

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§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &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> Downcast<T> for T

Source§

fn downcast(&self) -> &T

Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, S> SimdFrom<T, S> for T
where S: Simd,

Source§

fn simd_from(value: T, _simd: S) -> T

Source§

impl<F, T, S> SimdInto<T, S> for F
where T: SimdFrom<F, S>, S: Simd,

Source§

fn simd_into(self, simd: S) -> T

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> Upcast<T> for T

Source§

fn upcast(&self) -> Option<&T>

Source§

impl<T> WasmNotSend for T
where T: Send,

Source§

impl<T> WasmNotSendSync for T

Source§

impl<T> WasmNotSync for T
where T: Sync,

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more