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;
#[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,
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;
}
}