diff --git a/assets/sprites/speedometer.png b/assets/sprites/speedometer.png new file mode 100644 index 0000000..3ee1100 Binary files /dev/null and b/assets/sprites/speedometer.png differ diff --git a/media/speedometer.svg b/media/speedometer.svg new file mode 100644 index 0000000..3324dac --- /dev/null +++ b/media/speedometer.svg @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/media/speedometer2.svg b/media/speedometer2.svg new file mode 100644 index 0000000..2655e94 --- /dev/null +++ b/media/speedometer2.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/hud.rs b/src/hud.rs index 907e810..1aa4bfe 100644 --- a/src/hud.rs +++ b/src/hud.rs @@ -74,6 +74,7 @@ impl Plugin for HudPlugin { #[derive(Component)] struct NodeChoiceText; #[derive(Component)] struct NodeCurrentChatLine; #[derive(Component)] struct Reticule; +#[derive(Component)] struct Speedometer; #[derive(Component)] pub struct ToggleableHudElement; #[derive(Component)] pub struct ToggleableHudMapElement; #[derive(Component)] struct Selectagon; @@ -319,6 +320,36 @@ fn setup( )); }); + // Add Speedometer + let reticule_handle: Handle = asset_server.load("sprites/speedometer.png"); + commands.spawn(( + NodeBundle { + style: Style { + width: Val::VMin(10.0), + height: Val::Percent(100.0), + align_items: AlignItems::End, + overflow: Overflow::clip(), + ..default() + }, + visibility, + ..default() + }, + Speedometer, + ToggleableHudElement, + )).with_children(|builder| { + builder.spawn(( + ImageBundle { + image: UiImage::new(reticule_handle), + style: Style { + width: Val::VMin(50.0), + height: Val::VMin(10.0), + ..Default::default() + }, + ..Default::default() + }, + )); + }); + // Chat "subtitles" and choices commands.spawn(NodeBundle { style: Style { @@ -395,6 +426,7 @@ fn update_hud( mut q_node_currentline: Query<&mut Text, (With, Without, Without, Without)>, query_all_actors: Query<&actor::Actor>, settings: Res, + mut q_speedometer: Query<&mut Style, With>, q_target: Query<(&IsClickable, Option<&Position>, Option<&LinearVelocity>), With>, ) { // TODO only when hud is actually on @@ -494,6 +526,14 @@ fn update_hud( let speed_readable = nature::readable_distance(speed); text.sections[14].value = format!("\n{speed_readable}/s\n{gforce:.1}g{dev_speed}"); + if let Ok(mut speedometer) = q_speedometer.get_single_mut() { + let custom_c = nature::C / 1000.0; + let fraction = nature::lorenz_factor_custom_c(custom_c - speed, custom_c) as f32; + info!(fraction); + let wid = (fraction * 100.0).clamp(0.0, 100.0); + speedometer.width = Val::VMin(wid); + } + if target_multiple { text.sections[15].value = "\n\nERROR: MULTIPLE TARGETS".to_string(); } diff --git a/src/nature.rs b/src/nature.rs index 70fddf5..c9bccaa 100644 --- a/src/nature.rs +++ b/src/nature.rs @@ -19,6 +19,7 @@ pub const LIGHTYEAR2METER: f64 = 9_460_730_472_580_800.0; pub const PARSEC2METER: f64 = 3.0857e16; pub const DIST_JUPTER_SUN: f64 = 778479.0e6; pub const EARTH_GRAVITY: f32 = 9.81; +pub const C: f64 = 299792458.0; // m/s pub const SOL_RADIUS: f64 = 696_300_000.0; pub const JUPITER_RADIUS: f64 = 71_492_000.0; @@ -118,3 +119,11 @@ pub fn readable_distance(distance: f64) -> String { } return format!("{distance:.1}m"); } + +pub fn lorenz_factor(speed: f64) -> f64 { + (1.0 - (speed.powf(2.0) / C.powf(2.0))).sqrt() +} + +pub fn lorenz_factor_custom_c(speed: f64, c: f64) -> f64 { + (1.0 - (speed.powf(2.0) / c.powf(2.0))).sqrt() +}