pub struct ParticleSystem {
pub particles: Vec<Particle>,
pub emitters: Vec<ParticleEmitter>,
pub gravity: Vec3Fix,
pub damping: Fix128,
pub max_particles: usize,
}Expand description
A particle system managing particles and emitters.
Fields§
§particles: Vec<Particle>All particles (alive and dead)
emitters: Vec<ParticleEmitter>Particle emitters
gravity: Vec3FixGravity vector
damping: Fix128Linear velocity damping (0 = full damping, 1 = no damping)
max_particles: usizeMaximum number of particles allowed
Implementations§
Source§impl ParticleSystem
impl ParticleSystem
Sourcepub fn new(max_particles: usize, gravity: Vec3Fix) -> Self
pub fn new(max_particles: usize, gravity: Vec3Fix) -> Self
Create a new particle system.
§Arguments
max_particles: Maximum number of live particlesgravity: Gravity vector applied to all particles
Sourcepub fn add_emitter(&mut self, emitter: ParticleEmitter) -> usize
pub fn add_emitter(&mut self, emitter: ParticleEmitter) -> usize
Add a particle emitter and return its index.
Sourcepub fn alive_count(&self) -> usize
pub fn alive_count(&self) -> usize
Count the number of alive particles.
Sourcepub fn step(&mut self, dt: Fix128, rng: &mut DeterministicRng)
pub fn step(&mut self, dt: Fix128, rng: &mut DeterministicRng)
Step the particle system by dt seconds.
- Emit new particles from each emitter
- Apply gravity and damping to all alive particles
- Integrate positions (Euler)
- Age particles and kill expired ones
The rng parameter ensures deterministic emission patterns.
Sourcepub fn step_with_landing(
&mut self,
dt: Fix128,
rng: &mut DeterministicRng,
targets: &[LandingTarget<'_>],
max_travel: Fix128,
respawn_emitter: usize,
) -> Vec<LandingEvent>
pub fn step_with_landing( &mut self, dt: Fix128, rng: &mut DeterministicRng, targets: &[LandingTarget<'_>], max_travel: Fix128, respawn_emitter: usize, ) -> Vec<LandingEvent>
Step like step, but stop each particle at the first
LandingTarget its path enters, report it and re-emit it from
emitters[respawn_emitter] (rain hitting shapes and falling again).
The velocity update is the same as step (v += g·dt, v *= damping). The
straight path x → x + v·dt is then sampled at n = ceil(|v·dt| / max_travel)
evenly spaced points (k/n for k = 1..=n, the last one is exactly the position
step would produce), and the targets are probed at each sample in order. The
first occupied sample produces a LandingEvent; the slot is then refilled with
a fresh particle from the respawn emitter (same position / velocity law as normal
emission, drawing from rng), so landing never changes the number of live
particles. Particles that land are not aged or expired in that step.
A target whose extent along the path is longer than max_travel cannot be
skipped, whatever dt is: consecutive samples are at most max_travel apart.
The cost is O(|v·dt| / max_travel) probes per particle per step. With no
targets the result is bit-identical to step.
§Panics
If max_travel <= 0, if respawn_emitter is not a valid emitter index, or if a
particle’s step would need more than 2^20 samples (|v·dt| / max_travel > 2^20).
§Example
use alice_physics::math::{Fix128, Vec3Fix};
use alice_physics::particle::{LandingTarget, ParticleEmitter, ParticleSystem};
use alice_physics::rng::DeterministicRng;
use alice_physics::sdf_collider::ClosureSdf;
// floor y = 0
let floor = ClosureSdf::new(|_, y, _| y, |_, _, _| (0.0, 1.0, 0.0));
let mut rain = ParticleSystem::new(64, Vec3Fix::from_int(0, -10, 0));
rain.damping = Fix128::ONE;
rain.add_emitter(ParticleEmitter::new(
Vec3Fix::from_int(0, 5, 0),
Vec3Fix::from_int(0, -1, 0),
Fix128::from_ratio(1, 4),
Fix128::from_int(120),
Fix128::ONE,
Fix128::from_int(100),
Fix128::ONE,
));
let mut rng = DeterministicRng::new(7);
let targets = [LandingTarget::Field(&floor)];
let mut landed = 0;
for _ in 0..240 {
let events = rain.step_with_landing(
Fix128::from_ratio(1, 60),
&mut rng,
&targets,
Fix128::from_ratio(1, 20),
0,
);
for e in &events {
assert!(e.normal.y > Fix128::ZERO);
}
landed += events.len();
}
assert!(landed > 0);Sourcepub fn apply_force_field(&mut self, field: &ForceField)
pub fn apply_force_field(&mut self, field: &ForceField)
Apply a force field to all alive particles.
The force is crate::force::field_force_at (the same laws as
crate::force::compute_force for rigid bodies), applied as a velocity
impulse: v += F/m * dt.
Uses a fixed dt of 1/60 for the impulse (since force fields are
typically applied once per frame).
Trait Implementations§
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
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