mod common;
use std::time::Duration;
use bevy::prelude::*;
use bevy::time::TimeUpdateStrategy;
use bevy_elements::*;
use common::{ExampleHarness, camera};
const EXTENT_M: f32 = 1024.0;
const TIME_SCALE: f32 = 600.0;
fn main() {
let hour = std::env::var("ELEMENTS_HOUR")
.ok()
.and_then(|h| h.parse().ok())
.unwrap_or(10.0);
let mut app = App::new();
app.add_plugins((DefaultPlugins, ElementsPlugins, ExampleHarness))
.insert_resource(Climate::desert())
.insert_resource(WorldClock {
paused: true,
time_scale: TIME_SCALE,
..WorldClock::new(CivilDate::new(2026, 6, 21)).at_hour(hour)
})
.insert_resource(HydrologySettings {
time_scale: 0.0,
boundary: HydrologyBoundary::Closed,
evaporation: false,
..default()
})
.add_systems(Startup, setup)
.add_systems(Update, report.after(ElementsSystems::Readback));
if std::env::var("ELEMENTS_FRAMES").is_ok() {
app.insert_resource(TimeUpdateStrategy::ManualDuration(Duration::from_secs_f64(
1.0 / 60.0,
)));
}
app.run();
}
fn vec3_env(name: &str) -> Option<Vec3> {
let value = std::env::var(name).ok()?;
let mut parts = value.split(',').map(|p| p.trim().parse::<f32>());
Some(Vec3::new(
parts.next()?.ok()?,
parts.next()?.ok()?,
parts.next()?.ok()?,
))
}
fn setup(mut commands: Commands, mut director: ResMut<WeatherDirector>) {
commands.spawn(
Terrain::procedural(ProceduralTerrain::dunes(7))
.with_extent(Vec2::splat(EXTENT_M))
.with_resolution(UVec2::splat(512)),
);
let eye = vec3_env("ELEMENTS_EYE").unwrap_or(Vec3::new(-330.0, 70.0, -260.0));
let look = vec3_env("ELEMENTS_LOOK").unwrap_or(Vec3::new(-60.0, 12.0, 0.0));
commands.spawn(camera(eye, look));
director.force(WeatherPreset::DustStorm, Duration::ZERO);
}
fn report(
weather: Res<Weather>,
clock: Res<WorldClock>,
stats: Res<DustStats>,
settings: Res<DustSettings>,
time: Res<Time<Real>>,
precipitation: Option<Res<PrecipitationState>>,
mut last: Local<u64>,
) {
let second = time.elapsed_secs() as u64;
if second == *last {
return;
}
*last = second;
let u = weather.wind_speed_ms;
let flux = settings.flux_coefficient * u * u * (u - settings.threshold_ms).max(0.0);
let q_eff = flux * clock.time_scale;
println!(
"t = {:>4} s wind {u:.1} m/s dust {:.2} {} sprites {} transport steps ({:.0} s of bed time) predicted shift per minute {:.1} m for H = 4 m",
second,
weather.dust,
precipitation.map_or(0, |p| p.dust),
stats.steps,
stats.bed_time_s,
q_eff * 60.0 / 4.0,
);
}