use super::AimState; use crate::{ GameState, backpack::UiHeadState, heads_ui::HeadsImages, loading_assets::UIAssets, npc::{Hitpoints, NpcHead}, }; use bevy::prelude::*; #[derive(Component, Reflect, Default)] #[reflect(Component)] struct HeadImage; #[derive(Component, Reflect, Default)] #[reflect(Component)] struct HeadDamage; #[derive(Resource, Default, PartialEq)] struct TargetUi { head: Option, } pub fn plugin(app: &mut App) { app.add_systems(OnEnter(GameState::Playing), setup); app.add_systems(Update, (sync, update).run_if(in_state(GameState::Playing))); } fn setup(mut commands: Commands, assets: Res) { commands .spawn(( Name::new("target-ui"), Node { position_type: PositionType::Absolute, top: Val::Px(150.0), left: Val::Px(20.0), height: Val::Px(74.0), ..default() }, )) .with_children(|parent| { spawn_head_ui( parent, assets.head_bg.clone(), assets.head_regular.clone(), assets.head_damage.clone(), ); }); commands.insert_resource(TargetUi::default()); } fn spawn_head_ui( parent: &mut ChildBuilder, bg: Handle, regular: Handle, damage: Handle, ) { const SIZE: f32 = 90.0; const DAMAGE_SIZE: f32 = 74.0; parent .spawn((Node { position_type: PositionType::Relative, justify_content: JustifyContent::Center, align_items: AlignItems::Center, width: Val::Px(SIZE), ..default() },)) .with_children(|parent| { parent.spawn(( Node { position_type: PositionType::Absolute, ..default() }, ImageNode::new(bg), )); parent.spawn(( Node { position_type: PositionType::Absolute, ..default() }, ImageNode::default(), Visibility::Hidden, HeadImage, )); parent.spawn(( Node { position_type: PositionType::Absolute, ..default() }, ImageNode::new(regular), )); parent .spawn((Node { height: Val::Px(DAMAGE_SIZE), width: Val::Px(DAMAGE_SIZE), ..default() },)) .with_children(|parent| { parent .spawn(( HeadDamage, Node { position_type: PositionType::Absolute, display: Display::Block, overflow: Overflow::clip(), top: Val::Px(0.), left: Val::Px(0.), right: Val::Px(0.), height: Val::Percent(25.), ..default() }, )) .with_child(ImageNode::new(damage)); }); }); } fn update( target: Res, heads_images: Res, mut head_image: Query< (&mut Visibility, &mut ImageNode), (Without, With), >, mut head_damage: Query<&mut Node, (With, Without)>, ) { if target.is_changed() { if let Ok((mut vis, mut image)) = head_image.get_single_mut() { if let Some(head) = target.head { *vis = Visibility::Visible; image.image = heads_images.heads[head.head].clone(); } else { *vis = Visibility::Hidden; } } if let Ok(mut node) = head_damage.get_single_mut() { node.height = Val::Percent(target.head.map(|head| head.damage()).unwrap_or(0.) * 100.); } } } fn sync( mut target: ResMut, aim: Res, target_data: Query<(&Hitpoints, &NpcHead)>, ) { let mut new_state = None; if let Some(e) = aim.target { if let Ok((hp, head)) = target_data.get(e) { new_state = Some(UiHeadState { head: head.0, health: hp.health(), ammo: 1., }); } } if new_state != target.head { target.head = new_state; } }