use bevy::prelude::*; use bevy::window::PrimaryWindow; use crate::client::Me; use crate::config::planet::Planet; pub fn indicators_plugin(app: &mut App) { app.add_systems(PreUpdate, (add_indicators, update_indicators)) .add_systems(Update, update_indicators_position); } #[derive(Component)] struct PlanetIndicator(String); #[derive(Component)] struct HasIndicator(Entity); fn add_indicators(planets_wo_indicators: Query<(Entity, &Planet), Without>, player: Query>, asset_server: Res, 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(50.0, 50.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>, asset_server: Res, 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::() .insert(sprite); } } fn update_indicators_position( planets_w_indicator: Query<(&Transform, &HasIndicator), Without>, player: Query<&Transform, (With, Without)>, mut indicators: Query<(&mut Transform), (With, Without, Without)>, window: Query<&Window, With>, ) { let Ok(player_position) = player.single() else { return; }; let window = window.single().unwrap(); for (planet_position, indicator_id) in &planets_w_indicator { let mut offset = planet_position.translation - player_position.translation; let half_window_height = window.height() / 2.0 - 25.0; let half_window_width = window.width() / 2.0 - 25.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) = indicators.get_mut(indicator_id.0) else { continue; }; 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; } }