From a85763a0e59339d07d2589197fb2a3985e3f92d0 Mon Sep 17 00:00:00 2001 From: ghostly_zsh Date: Fri, 28 Nov 2025 18:05:21 -0600 Subject: [PATCH] feat: orbit prediction --- crates/unified/src/client/starguide/orbit.rs | 53 ++++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/crates/unified/src/client/starguide/orbit.rs b/crates/unified/src/client/starguide/orbit.rs index e40da6691c7f6642958b7e951028abccd409ac91..c4a46b77d60707056d30ee6d549d50192ad5cb96 100644 --- a/crates/unified/src/client/starguide/orbit.rs +++ b/crates/unified/src/client/starguide/orbit.rs @@ -1,6 +1,8 @@ +use std::{f32::consts::PI, ops::Range}; + use bevy::window::WindowResized; -use crate::{ecs::{Me, StarguideCamera, StarguideOrbit, StarguideOrbitImage}, prelude::*}; +use crate::{config::planet::Planet, ecs::{Me, StarguideCamera, StarguideOrbit, StarguideOrbitImage}, prelude::*, world_config::WorldConfigResource}; use bevy::render::render_resource::Extent3d; pub fn starguide_orbit_plugin(app: &mut App) { @@ -12,25 +14,56 @@ fn update_orbits( orbit_image: Res, mut images: ResMut>, camera: Single<(&Camera, &GlobalTransform, &Projection), With>, - me: Single<&Transform, (With, Without)>, + me: Single<(&Transform, &LinearVelocity), (With, Without)>, orbit: Single<&Transform, (With, Without, Without)>, + world_config: Res, + planets: Query<(&Mass, &Planet, &Transform)>, ) { let Some(image) = images.get_mut(&orbit_image.0) else { error!("Orbit prediction image not found"); return }; + let Some(world_config) = &world_config.config else { + return; + }; let Projection::Orthographic(ref projection) = camera.2.clone() else { return }; image.clear(&(Color::BLACK.to_srgba().to_u8_array())); - let player_pos = me.translation - orbit.translation; - let player_pos = Vec3::new(player_pos.x, -player_pos.y, player_pos.z); - let player_pos = (player_pos / projection.scale).truncate(); - let player_pos = player_pos + image.size_f32()/2.0; - let player_pos = player_pos.as_uvec2(); + let mut p_mass = 1.0; + let mut p_transform = Transform::default(); + for (mass, planet, transform) in planets { + if planet.name == "Earth" { + p_mass = mass.0; + p_transform = *transform; + } + } + + // orbit magic + let rel_pos = me.0.translation - p_transform.translation; + let u = world_config.world.gravity*p_mass; + let h = rel_pos.x*me.1.y - rel_pos.y*me.1.x; + let r = rel_pos.length(); + let a = (u*r) / (2.0*u - r*(me.1.x*me.1.x + me.1.y*me.1.y)); + let e_x = rel_pos.x/r - (h*me.1.y)/u; + let e_y = rel_pos.y/r + (h*me.1.x)/u; + let f_x = -2.0*a*e_x; + let f_y = -2.0*a*e_y; + + // 200 steps in the revolution + for i in 0..400 { + let theta = (i as f32) / 200.0 * 2.0*PI; + let r = (1.0/2.0) * ((f_x*f_x + f_y*f_y - 4.0*a*a) / (-2.0*a - f_x*theta.cos() - f_y*theta.sin())); + + // convert r to image coords + let pos = Vec2::new(r*theta.cos(), r*theta.sin()); + let pos = pos + p_transform.translation.truncate() - orbit.translation.truncate(); + let pos = Vec2::new(pos.x, -pos.y); + let pos = pos / projection.scale; + let pos = pos + image.size_f32()/2.0; + let pos = pos.as_uvec2(); - for i in (player_pos.x)..(player_pos.x+100) { - if !(i >= image.size().x || player_pos.y >= image.size().y) { - image.set_color_at(i, player_pos.y, Color::linear_rgb(1.0, 0.0, 0.0)).unwrap(); + if !(pos.x >= image.size().x || pos.y >= image.size().y) { + image.set_color_at(pos.x, pos.y, Color::linear_rgb(1.0, 0.0, 0.0)).unwrap(); } } }