~starkingdoms/starkingdoms

ref: 92b84cca379c046bc49547f68fede1599c9ac3b9 starkingdoms/crates/unified/src/client/starguide/orbit.rs -rw-r--r-- 4.5 KiB
92b84cca — core fix: dragging 16 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
use std::{f32::{self, consts::PI}, ops::Range};

use bevy::window::WindowResized;

use crate::{config::planet::Planet, ecs::{Me, StarguideCamera, StarguideGizmos, StarguideOrbit, StarguideOrbitImage}, prelude::*, world_config::WorldConfigResource};
use bevy::render::render_resource::Extent3d;

pub fn starguide_orbit_plugin(app: &mut App) {
    app
        .add_systems(Update, (update_orbits));
}

fn update_orbits(
    //orbit_image: Res<StarguideOrbitImage>,
    //mut images: ResMut<Assets<Image>>,
    camera: Single<(&Camera, &GlobalTransform, &Projection), With<StarguideCamera>>,
    me: Single<(&Transform, &LinearVelocity), (With<Me>, Without<StarguideCamera>)>,
    //orbit: Single<&Transform, (With<StarguideOrbit>, Without<Me>, Without<StarguideCamera>)>,
    mut gizmos: Gizmos<StarguideGizmos>,
    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 mut p_mass = None;
    let mut p_transform = None;
    let (sun_mass, _, sun_transform) = planets.iter().filter(|planet| planet.1.name == "Sun").next().unwrap();
    let mut closest = f32::INFINITY;
    for (mass, planet, transform) in planets {
        if planet.name == "Sun" { continue }

        let (other_mass, p, other_transform) = planets.iter().filter(|f_planet| f_planet.1.name == planet.orbit.clone().unwrap().orbiting).next().unwrap();
        let a = other_transform.translation - transform.translation;
        let hill_sphere = a.length()*(mass.0/(3.0*(other_mass.0+mass.0))).powf(1.0/3.0);

        gizmos.circle_2d(transform.translation.truncate(), hill_sphere, Color::linear_rgb(0.02, 0.02, 0.02));

        let rel_dist = (me.0.translation - transform.translation).length();
        if rel_dist < closest && hill_sphere > rel_dist {
            p_mass = Some(mass.0);
            p_transform = Some(*transform);
            closest = rel_dist;
        }
    }
    if p_mass.is_none()  {
        p_mass = Some(sun_mass.0);
        p_transform = Some(*sun_transform);
    }
    let p_mass = p_mass.unwrap();
    let p_transform = p_transform.unwrap();

    // 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
    let mut first_pos = None;
    let mut last_pos = None;
    for i in 0..200 {
        let theta = 2.0*PI*(i as f32)/200.0;
        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()));

        if r < 0.0 { continue }

        // convert r to image coords
        let pos = Vec2::new(r*theta.cos(), r*theta.sin()) + p_transform.translation.truncate();
        /*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;*/

        //if !(pos.x as u32 >= image.size().x || pos.y as u32 >= image.size().y) && i != 0 {
        if last_pos.is_some() {
            gizmos.line_2d(last_pos.unwrap(), pos, Color::linear_rgb(1.0, 0.0, 0.0));
        }
        if first_pos.is_none() { first_pos = Some(pos) }
        last_pos = Some(pos);
    }
    if first_pos.is_some() && last_pos.is_some() {
        gizmos.line_2d(first_pos.unwrap(), last_pos.unwrap(), Color::linear_rgb(1.0, 0.0, 0.0));
    }
}

/*fn window_resize(
    orbit_image: Res<StarguideOrbitImage>,
    mut images: ResMut<Assets<Image>>,
    mut resize_ev: MessageReader<WindowResized>,
    camera: Single<&Camera, With<StarguideCamera>>,
) {
    let Some(image) = images.get_mut(&orbit_image.0) else {
        error!("Orbit prediction image not found");
        return
    };
    for _ in resize_ev.read() {
        let Some(Vec2 {x: width, y: height}) = camera.logical_viewport_size() else {
            continue
        };
        image.resize(Extent3d {
            width: width as u32,
            height: height as u32,
            depth_or_array_layers: 1,
        });
    }
}*/