use bevy::prelude::*; #[derive(Component, Default)] struct HeadSelector(pub usize); #[derive(Component, Default)] struct HeadImage(pub usize); #[derive(Resource, Default)] struct HeadsImages { heads: Vec>, } #[derive(Resource, Default)] struct ActiveHeads { heads: [Option; 5], current_slot: usize, } #[derive(Event)] pub struct HeadChanged(pub usize); pub fn plugin(app: &mut App) { app.add_systems(Startup, setup); app.add_systems(Update, (update, toggle_heads)); } fn setup(mut commands: Commands, asset_server: Res) { let bg = asset_server.load("ui/head_bg.png"); let regular = asset_server.load("ui/head_regular.png"); let selector = asset_server.load("ui/selector.png"); commands .spawn(Node { position_type: PositionType::Absolute, bottom: Val::Px(20.0), right: Val::Px(100.0), height: Val::Px(74.0), ..default() }) .with_children(|parent| { spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 0); spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 1); spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 2); spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 3); spawn_head_ui(parent, bg.clone(), regular.clone(), selector.clone(), 4); }); let head_01 = asset_server.load("ui/heads/angry demonstrator.png"); let head_02 = asset_server.load("ui/heads/commando.png"); let head_03 = asset_server.load("ui/heads/goblin.png"); let head_04 = asset_server.load("ui/heads/highland hammer thrower.png"); let head_05 = asset_server.load("ui/heads/legionnaire.png"); commands.insert_resource(HeadsImages { heads: vec![head_01, head_02, head_03, head_04, head_05], }); commands.insert_resource(ActiveHeads { heads: [Some(0), Some(1), Some(2), Some(3), Some(4)], current_slot: 0, }); } fn spawn_head_ui( parent: &mut ChildBuilder, bg: Handle, regular: Handle, selector: Handle, head: usize, ) { parent .spawn((Node { position_type: PositionType::Relative, justify_content: JustifyContent::Center, width: Val::Px(74.0), ..default() },)) .with_children(|parent| { parent.spawn(( Node { position_type: PositionType::Absolute, top: Val::Px(-20.0), ..default() }, Visibility::Hidden, ImageNode::new(selector), HeadSelector(head), )); parent.spawn(( Node { position_type: PositionType::Absolute, ..default() }, ImageNode::new(bg), )); parent.spawn(( Node { position_type: PositionType::Absolute, left: Val::Px(2.0), right: Val::Px(2.0), top: Val::Px(2.0), bottom: Val::Px(2.0), ..default() }, ImageNode::default(), Visibility::Hidden, HeadImage(head), )); parent.spawn(( Node { position_type: PositionType::Absolute, ..default() }, ImageNode::new(regular), )); }); } fn update( res: Res, heads_images: Res, mut head_image: Query<(&HeadImage, &mut Visibility, &mut ImageNode), Without>, mut head_selector: Query<(&HeadSelector, &mut Visibility), Without>, ) { if res.is_changed() { for (HeadImage(head), mut vis, mut image) in head_image.iter_mut() { if let Some(head) = res.heads[*head] { *vis = Visibility::Visible; image.image = heads_images.heads[head].clone(); } else { *vis = Visibility::Hidden; } } for (HeadSelector(head), mut vis) in head_selector.iter_mut() { *vis = if *head == res.current_slot { Visibility::Visible } else { Visibility::Hidden }; } } } fn toggle_heads( mut commands: Commands, mut res: ResMut, keys: Res>, ) { let changed = if keys.just_pressed(KeyCode::KeyE) { res.current_slot = (res.current_slot + 1) % 5; true } else if keys.just_pressed(KeyCode::KeyQ) { res.current_slot = (res.current_slot + 4) % 5; true } else { false }; if changed { commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap())); } }