From 758114e3a29438b3b2c6252dda0c33ac0b12ca79 Mon Sep 17 00:00:00 2001 From: yuni Date: Sat, 26 Oct 2024 21:22:03 +0200 Subject: [PATCH] add orbital clock (in menu) --- src/cmd.rs | 1 + src/menu.rs | 49 +++++++++++++++++++++++++++++++++++++++---------- src/nature.rs | 23 +++++++++++++++++++++++ 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/src/cmd.rs b/src/cmd.rs index f1fc61a..eda4695 100644 --- a/src/cmd.rs +++ b/src/cmd.rs @@ -18,6 +18,7 @@ use bevy_xpbd_3d::prelude::*; use regex::Regex; pub const ID_SPECIAL_PLAYERCAM: &str = "PLAYERCAMERA"; +pub const ID_PLAYER: &str = "player"; pub const ID_EARTH: &str = "earth"; pub const ID_SOL: &str = "sol"; pub const ID_JUPITER: &str = "jupiter"; diff --git a/src/menu.rs b/src/menu.rs index 44a9dff..ab5f9b6 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -49,6 +49,8 @@ pub struct MenuElement; #[derive(Component)] pub struct MenuTopLevel; #[derive(Component)] +pub struct FooterElement; +#[derive(Component)] pub struct MenuAchievements; #[derive(Component)] pub struct DeathScreenElement; @@ -349,17 +351,20 @@ pub fn setup( }, )) .with_children(|builder| { - builder.spawn((TextBundle { - text: Text { - sections: vec![TextSection::new( - format!("{} {}", GAME_NAME, settings.version.as_str()), - style_version, - )], - justify: JustifyText::Right, + builder.spawn(( + FooterElement, + TextBundle { + text: Text { + sections: vec![TextSection::new( + format!("{} {}", GAME_NAME, settings.version.as_str()), + style_version, + )], + justify: JustifyText::Right, + ..default() + }, ..default() }, - ..default() - },)); + )); }); } @@ -435,8 +440,17 @@ pub struct MenuState { pub fn update_menu( mut q_text: Query<&mut Text, With>, - mut q_achievement_text: Query<&mut Text, (With, Without)>, + mut q_footer: Query<&mut Text, (With, Without)>, + mut q_achievement_text: Query< + &mut Text, + ( + With, + Without, + Without, + ), + >, mut q_vis: Query<&mut Visibility, With>, + id2pos: Res, achievement_tracker: Res, menustate: Res, settings: Res, @@ -451,6 +465,21 @@ pub fn update_menu( let bools = achievement_tracker.to_bool_vec(); let rendered = achievement_tracker.to_textsections(); + if let (Ok(mut text), Some(player_pos), Some(jupiter_pos)) = ( + q_footer.get_single_mut(), + id2pos.0.get(cmd::ID_PLAYER), + id2pos.0.get(cmd::ID_JUPITER), + ) { + let (clock_max, clock_current) = + nature::pos_to_orbit_time(*player_pos, *jupiter_pos, nature::JUPITER_MASS); + text.sections[0].value = format!( + "Orbital Clock:\n{} of {}\n{} {}", + nature::format_seconds_to_hour_min(clock_current), + nature::format_seconds_to_hour_min(clock_max), + GAME_NAME, + settings.version.as_str() + ); + } if let Ok(mut text) = q_achievement_text.get_single_mut() { for i in 0..text.sections.len() - 1 { text.sections[i + 1].style.color = if bools[i] { diff --git a/src/nature.rs b/src/nature.rs index 087c7c9..8de51df 100644 --- a/src/nature.rs +++ b/src/nature.rs @@ -242,3 +242,26 @@ pub fn rotation_for_orbiting_body(orbit_distance: f64, mass: f64) -> f64 { 0.0 } } + +/// Assumes a circular 2D orbit in the invariable plane of the solar system +/// Returns (seconds for a single orbit, current seconds of orbit) +pub fn pos_to_orbit_time(pos: DVec3, orbited_pos: DVec3, orbited_mass: f64) -> (f64, f64) { + let rel_x = pos.x - orbited_pos.x; + let rel_z = pos.z - orbited_pos.z; + let orbit_distance = (rel_x * rel_x + rel_z * rel_z).sqrt(); + + // get total orbit seconds + let period = simple_orbital_period(orbited_mass, orbit_distance); + + // get current orbital phase + let angle_radians = (rel_z).atan2(-rel_x); + let mut fraction = angle_radians / (PI * 2.0); + if fraction < 0.0 { + fraction += 1.0; + } + return (period, period * fraction); +} + +pub fn format_seconds_to_hour_min(seconds: f64) -> String { + return format!("{:02.0}:{:02.0}", seconds / 3600.0, (seconds % 3600.0) / 60.0); +}