diff --git a/Cargo.toml b/Cargo.toml index 15c508d..11e1552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,3 +47,9 @@ name = "error" path = "examples/error.rs" required-features = ["default"] doc-scrape-examples = true + +[[example]] +name = "solar_system" +path = "examples/solar_system.rs" +required-features = ["default"] +doc-scrape-examples = true diff --git a/examples/demo.rs b/examples/demo.rs index 7396c19..1ff8811 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -233,13 +233,12 @@ fn closest<'a>(diameter: f32) -> (f32, &'a str) { (1.9e-15, "diameter of a proton"), ]; - let mut min = items[0]; - for item in items.iter() { - if (item.0 - diameter).abs() < (min.0 - diameter).abs() { - min = item.to_owned(); + for &item in items.iter() { + if item.0 < diameter { + return item; } } - min + *items.last().unwrap() } fn cursor_grab_system( diff --git a/examples/solar_system.rs b/examples/solar_system.rs new file mode 100644 index 0000000..cf34807 --- /dev/null +++ b/examples/solar_system.rs @@ -0,0 +1,250 @@ +use bevy::{ + core_pipeline::bloom::BloomSettings, + prelude::*, + transform::TransformSystem, + window::{CursorGrabMode, PrimaryWindow, Window, WindowMode}, +}; +use big_space::{ + camera::{CameraController, CameraInput}, + world_query::GridTransformReadOnly, + FloatingOrigin, FloatingOriginSettings, GridCell, +}; + +fn main() { + App::new() + .add_plugins(( + DefaultPlugins.build().disable::(), + big_space::FloatingOriginPlugin::::default(), + big_space::debug::FloatingOriginDebugPlugin::::default(), + big_space::camera::CameraControllerPlugin::::default(), + bevy_framepace::FramepacePlugin, + )) + .insert_resource(ClearColor(Color::BLACK)) + .add_systems(Startup, (setup, ui_setup)) + .add_systems(Update, (cursor_grab_system, ui_text_system)) + .add_systems( + PostUpdate, + highlight_nearest_sphere.after(TransformSystem::TransformPropagate), + ) + .run() +} + +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, + space: Res, +) { + let mut sphere = |radius| meshes.add(Sphere::new(radius).mesh().ico(32).unwrap()); + let sun_mat = materials.add(StandardMaterial { + base_color: Color::WHITE, + emissive: Color::rgb_linear(100000., 100000., 100000.), + ..default() + }); + + let sun_radius_m = 695_508_000.0; + + commands + .spawn(( + GridCell::::ZERO, + PointLightBundle { + point_light: PointLight { + intensity: 35.73e27, + range: 1e20, + radius: sun_radius_m, + shadows_enabled: true, + ..default() + }, + ..default() + }, + )) + .with_children(|builder| { + builder.spawn(( + PbrBundle { + mesh: sphere(sun_radius_m), + material: sun_mat, + ..default() + }, + GridCell::::ZERO, + )); + }); + + let earth_orbit_radius_m = 149.60e9; + let earth_radius_m = 6.371e6; + + let earth_mat = materials.add(StandardMaterial { + base_color: Color::BLUE, + perceptual_roughness: 0.8, + reflectance: 1.0, + ..default() + }); + + let (earth_cell, earth_pos): (GridCell, _) = + space.imprecise_translation_to_grid(Vec3::X * earth_orbit_radius_m); + + commands + .spawn(( + PbrBundle { + mesh: sphere(earth_radius_m), + material: earth_mat, + transform: Transform::from_translation(earth_pos), + ..default() + }, + earth_cell, + )) + .with_children(|commands| { + let moon_orbit_radius_m = 385e6; + let moon_radius_m = 1.7375e6; + + let moon_mat = materials.add(StandardMaterial { + base_color: Color::DARK_GRAY, + perceptual_roughness: 1.0, + reflectance: 0.0, + ..default() + }); + + let (moon_cell, moon_pos): (GridCell, _) = + space.imprecise_translation_to_grid(Vec3::Z * moon_orbit_radius_m); + + commands.spawn(( + PbrBundle { + mesh: sphere(moon_radius_m), + material: moon_mat, + transform: Transform::from_translation(moon_pos), + ..default() + }, + moon_cell, + )); + }); + + // camera + commands.spawn(( + Camera3dBundle { + transform: Transform::from_xyz(686., -181., 80.) + .looking_to(-Vec3::Z * 0.6 - Vec3::X - Vec3::Y * 0.1, Vec3::Y), + camera: Camera { + hdr: true, + ..default() + }, + ..default() + }, + BloomSettings::default(), + GridCell::::new(74899712, 45839, 232106), + FloatingOrigin, // Important: marks the floating origin entity for rendering. + CameraController::default() // Built-in camera controller + .with_speed_bounds([10e-18, 10e35]) + .with_smoothness(0.9, 0.8) + .with_speed(1.0), + )); + + commands.insert_resource(AmbientLight { + color: Color::WHITE, + brightness: 0.05, + }); +} + +#[derive(Component, Reflect)] +pub struct BigSpaceDebugText; + +fn ui_setup(mut commands: Commands) { + commands.spawn(( + TextBundle::from_section( + "", + TextStyle { + font_size: 28.0, + color: Color::WHITE, + ..default() + }, + ) + .with_text_justify(JustifyText::Left) + .with_style(Style { + position_type: PositionType::Absolute, + top: Val::Px(10.0), + left: Val::Px(10.0), + ..default() + }), + BigSpaceDebugText, + )); +} + +fn highlight_nearest_sphere( + cameras: Query<&CameraController>, + objects: Query<&GlobalTransform>, + mut gizmos: Gizmos, +) { + let Some((entity, _)) = cameras.single().nearest_object() else { + return; + }; + let Ok(transform) = objects.get(entity) else { + return; + }; + let (scale, rotation, translation) = transform.to_scale_rotation_translation(); + gizmos + .sphere(translation, rotation, scale.x * 0.505, Color::RED) + .circle_segments(128); +} + +fn ui_text_system( + mut debug_text: Query<&mut Text, With>, + time: Res