~starkingdoms/starkingdoms

a85763a0e59339d07d2589197fb2a3985e3f92d0 — ghostly_zsh 17 days ago ade2542
feat: orbit prediction
1 files changed, 43 insertions(+), 10 deletions(-)

M crates/unified/src/client/starguide/orbit.rs
M crates/unified/src/client/starguide/orbit.rs => crates/unified/src/client/starguide/orbit.rs +43 -10
@@ 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<StarguideOrbitImage>,
    mut images: ResMut<Assets<Image>>,
    camera: Single<(&Camera, &GlobalTransform, &Projection), With<StarguideCamera>>,
    me: Single<&Transform, (With<Me>, Without<StarguideCamera>)>,
    me: Single<(&Transform, &LinearVelocity), (With<Me>, Without<StarguideCamera>)>,
    orbit: Single<&Transform, (With<StarguideOrbit>, Without<Me>, Without<StarguideCamera>)>,
    world_config: Res<WorldConfigResource>,
    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();
        }
    }
}