From 0195960de3f5922ce6422442aec858e1c451d550 Mon Sep 17 00:00:00 2001 From: Valentin Popov Date: Sun, 18 Oct 2026 10:21:25 +0400 Subject: fix(fx): preserve rain tails on zero-time frames --- crates/fparkan-fx/src/environment.rs | 27 ++++++++++++++++++++++++++- docs/reference/environment-effects.md | 4 ++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/fparkan-fx/src/environment.rs b/crates/fparkan-fx/src/environment.rs index a298f24..a1f6c13 100644 --- a/crates/fparkan-fx/src/environment.rs +++ b/crates/fparkan-fx/src/environment.rs @@ -1695,7 +1695,9 @@ impl PrecipitationEmitter { let size = camera.precipitation_size_scalar() * size_factor; for index in 0..desired { let particle = &mut self.particles[index]; - particle.previous_position = particle.position; + if dt_seconds > 0.0 { + particle.previous_position = particle.position; + } particle.position[0] += velocity[0] * dt_seconds; particle.position[1] += velocity[1] * dt_seconds; particle.position[2] += velocity[2] * dt_seconds; @@ -2469,6 +2471,29 @@ mod tests { assert_eq!(update.sounds[0].volume, 0.5); } + #[test] + fn duplicate_zero_delta_keeps_rain_frame_and_tail_unchanged() { + let mut system = EnvironmentSystem::new(3); + let camera = Camera::new([10.0, 20.0, 30.0]); + let weather = WeatherInput { + rain: WeatherState::with_resources(true, 0.01, [1.0; 4], ["atm_rain1.wav"]), + ..WeatherInput::clear() + }; + let _ = system.update(0.0, weather.clone(), camera); + let advanced = system.update(0.001, weather.clone(), camera); + let time_seconds = system.time_seconds(); + let repeated = system.update(0.0, weather, camera); + + assert_eq!(system.time_seconds(), time_seconds); + assert_eq!(advanced, repeated); + assert!(advanced.primitives.iter().any(|primitive| match primitive { + EnvironmentPrimitive::Particle { screen, .. } => { + screen.world_head != screen.world_tail + } + EnvironmentPrimitive::Lightning(_) => false, + })); + } + #[test] fn precipitation_uses_native_volume_ratio_and_nearest_even_count() { let reference = PrecipitationVolume::native(); diff --git a/docs/reference/environment-effects.md b/docs/reference/environment-effects.md index 66ed052..0435a6a 100644 --- a/docs/reference/environment-effects.md +++ b/docs/reference/environment-effects.md @@ -104,6 +104,10 @@ N = round_even( координаты, и к каждой оси применяется floor-based wrap; 5. после wrap точка снова переводится в мир, а её хвост сбрасывается на голову. +Повторное обновление на том же времени имеет нулевой `dt`: позиция капли и +сохранённое начало хвоста остаются прежними. Хвост продвигается только при +положительном шаге; wrap по-прежнему сбрасывает его на голову. + Скорости не принадлежат системе координат камеры: ```text -- cgit v1.2.3