use super::*;
use motion_core::{Shape, TimeLiteral};
#[test]
fn emitters_modifiers_paths_and_surfaces_share_fixed_step_protocol() -> motion_core::Result<()> {
let path = Arc::new(motion_core::Line::new(Point::ORIGIN, Point::new(10.0, 0.0)).path());
let emitters: Vec<Box<dyn ParticleEmitter>> = vec![
Box::new(PointEmitter::new(Point::ORIGIN)),
Box::new(DiskEmitter::new(Point::ORIGIN, 3.0)),
Box::new(RectEmitter::new(Rect::new(0.0, 0.0, 2.0, 4.0))),
Box::new(PathEmitter::new(path)),
];
for emitter in emitters {
let mut output = Vec::new();
emitter.emit(0, Time::ZERO, &mut Random::from_key(42u64), &mut output)?;
assert_eq!(output.len(), 1);
output[0].validate()?;
}
let simulation = ParticleSimulation::new(1)
.duration(100.milliseconds())
.emitter(BurstEmitter::new(10.milliseconds(), 2, Point::ORIGIN).speed(0.0))
.modifier(Gravity::new(Vector2::new(0.0, 10.0)))
.modifier(Drag::new(0.5))
.modifier(SizeOverLifetime {
start: 1.0,
end: 0.0,
});
assert!(simulation.sample(Time::ZERO)?.is_empty());
assert_eq!(simulation.sample(50.milliseconds())?.len(), 2);
assert!(simulation.sample(50.milliseconds())?[0].position[1] > 0.0);
let mut particle = Particle {
position: [0.5, 0.5],
velocity: [100.0, 0.0],
..Default::default()
};
BounceBox::new(Rect::new(0.0, 0.0, 1.0, 1.0)).apply(
&mut particle,
0.1,
Time::ZERO,
&mut Random::from_key(1u64),
)?;
particle.position[0] += particle.velocity[0] * 0.1;
assert!((particle.position[0] - 0.5).abs() < 0.0001);
Ok(())
}
#[test]
fn surface_animation_rates_and_all_modifier_callbacks_replay_without_hidden_state()
-> motion_core::Result<()> {
let tree = Arc::new(VectorTree::new(
Rect::new(0.0, 0.0, 4.0, 4.0),
crate::VectorGroup {
children: vec![crate::VectorItem::Path(crate::VectorPath::filled(
Path2D::from_rect(Rect::new(0.0, 0.0, 4.0, 4.0))?,
motion_core::Color::WHITE,
))],
..Default::default()
},
)?);
let simulation = ParticleSimulation::new(7)
.duration(200.milliseconds())
.emitter(
SurfaceEmitter::new(tree)
.rate_animation(motion_core::Constant::new(100.0))
.speed(0.0),
)
.modifier(Wind::new(Vector2::new(1.0, 0.0)))
.modifier(Vortex {
center: Point::ORIGIN,
strength: 1.0,
})
.modifier(Attractor {
center: Point::new(2.0, 2.0),
strength: 1.0,
})
.modifier(CurlNoise {
frequency: 0.1,
strength: 1.0,
seed: 0,
phase_speed: 1.0,
})
.modifier(Seek {
targets: Arc::from([Point::new(2.0, 2.0)]),
strength: 0.5,
})
.modifier(ColorOverLifetime::new(Arc::from([[1.0; 4], [0.0; 4]])));
let expected = simulation.sample(150.milliseconds())?;
assert!(!expected.is_empty());
simulation.sample(10.milliseconds())?;
assert_eq!(expected, simulation.sample(150.milliseconds())?);
assert!(
expected
.iter()
.filter(|particle| particle.age > 0.0)
.all(|particle| particle.color[3] < 1.0)
);
let emitter = PointEmitter::new(Point::ORIGIN).rate(100.0);
let mut output = Vec::new();
for step in 0..=100 {
emitter.emit(
step,
(step as i64 * 10).milliseconds(),
&mut Random::from_key(step),
&mut output,
)?;
}
assert_eq!(output.len(), 101);
Ok(())
}