~starkingdoms/starkingdoms

ref: f40e33203245891b3b000e1b35b417e6fd546876 starkingdoms/crates/unified/src/client/planet/indicators.rs -rw-r--r-- 3.4 KiB
f40e3320 — core chore(part): part fix #1 5 months 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
use crate::client::Me;
use crate::config::planet::Planet;
use crate::ecs::MainCamera;
use bevy::prelude::*;
use bevy::window::PrimaryWindow;

pub fn indicators_plugin(app: &mut App) {
    app.add_systems(PreUpdate, (add_indicators, update_indicators))
        .add_systems(PostUpdate, update_indicators_position);
}

#[derive(Component)]
struct PlanetIndicator(String);
#[derive(Component)]
struct HasIndicator(Entity);

fn add_indicators(
    planets_wo_indicators: Query<(Entity, &Planet), Without<HasIndicator>>,
    player: Query<Entity, With<Me>>,
    asset_server: Res<AssetServer>,
    mut commands: Commands,
) {
    let Ok(me) = player.single() else {
        return;
    };
    for (planet, planet_data) in &planets_wo_indicators {
        let Some(indicator_url) = &planet_data.indicator_sprite else {
            continue;
        };
        let mut sprite = Sprite::from_image(asset_server.load(indicator_url));
        sprite.custom_size = Some(Vec2::new(25.0, 25.0));
        let indicator = commands
            .spawn((
                ChildOf(me),
                PlanetIndicator(planet_data.name.clone()),
                sprite,
                Transform::from_xyz(0.0, 0.0, 0.0),
            ))
            .id();
        commands.entity(planet).insert(HasIndicator(indicator));
    }
}
fn update_indicators(
    changed_planets_w_indicators: Query<(&Planet, &HasIndicator), Changed<Planet>>,
    asset_server: Res<AssetServer>,
    mut commands: Commands,
) {
    for (planet_data, indicator) in changed_planets_w_indicators.iter() {
        let Some(indicator_sprite) = &planet_data.indicator_sprite else {
            continue;
        };
        let mut sprite = Sprite::from_image(asset_server.load(indicator_sprite));
        sprite.custom_size = Some(Vec2::new(50.0, 50.0));
        commands
            .entity(indicator.0)
            .remove::<Sprite>()
            .insert(sprite);
    }
}
fn update_indicators_position(
    planets_w_indicator: Query<(&Transform, &HasIndicator), Without<PlanetIndicator>>,
    player: Query<&Transform, (With<Me>, Without<PlanetIndicator>)>,
    mut indicators: Query<
        (&mut Transform, &mut Sprite),
        (
            With<PlanetIndicator>,
            Without<HasIndicator>,
            Without<Me>,
            Without<MainCamera>,
        ),
    >,
    window: Query<&Window, With<PrimaryWindow>>,
    camera: Single<&Transform, (With<MainCamera>, Without<PlanetIndicator>)>,
) {
    let Ok(player_position) = player.single() else {
        return;
    };
    let Ok(window) = window.single() else { return };

    for (planet_position, indicator_id) in &planets_w_indicator {
        let mut offset = planet_position.translation - player_position.translation;

        let sprite_size = 25.0 * camera.scale.z;

        let half_window_height = window.height() * camera.scale.z / 2.0 - (sprite_size / 2.0);
        let half_window_width = window.width() * camera.scale.z / 2.0 - (sprite_size / 2.0);
        offset.x = offset.x.clamp(-half_window_width, half_window_width);
        offset.y = offset.y.clamp(-half_window_height, half_window_height);

        let Ok((mut this_indicator, mut this_sprite)) = indicators.get_mut(indicator_id.0) else {
            continue;
        };

        this_sprite.custom_size = Some(Vec2::splat(sprite_size));

        let inv_rot = player_position.rotation.inverse();
        this_indicator.translation = inv_rot.mul_vec3(Vec3::new(offset.x, offset.y, 0.0));
        this_indicator.rotation = inv_rot;
    }
}