wrire up ammo and health in head_ui

This commit is contained in:
2025-04-01 23:47:51 +08:00
parent d9fad37e07
commit 8187eb58a9
3 changed files with 74 additions and 25 deletions

View File

@@ -153,6 +153,7 @@ fn sync(
new_state = Some(BackpackHead {
head: head.0,
health: hp.health(),
ammo: 1.,
});
}
}

View File

@@ -5,16 +5,29 @@ use bevy::prelude::*;
pub use backpack_ui::BackpackAction;
#[derive(Clone, Copy, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq, Reflect)]
pub struct BackpackHead {
pub head: usize,
pub health: f32,
pub ammo: f32,
}
impl BackpackHead {
pub fn new(head: usize) -> Self {
Self {
head,
health: 1.0,
ammo: 1.0,
}
}
pub fn damage(&self) -> f32 {
1. - self.health
}
pub fn ammo_used(&self) -> f32 {
1. - self.ammo
}
}
#[derive(Resource, Default)]
@@ -37,6 +50,7 @@ fn setup(mut commands: Commands) {
.map(|i| BackpackHead {
head: i,
health: 1.,
ammo: 1.,
})
.collect(),
});

View File

@@ -6,7 +6,7 @@ use crate::{
sounds::PlaySound,
};
use bevy::prelude::*;
use bevy_ui_gradients::{AngularColorStop, BackgroundGradient, ConicGradient, Position};
use bevy_ui_gradients::{AngularColorStop, BackgroundGradient, ConicGradient, Gradient, Position};
use std::f32::consts::PI;
pub static HEAD_COUNT: usize = 18;
@@ -35,9 +35,10 @@ pub struct HeadsImages {
pub heads: Vec<Handle<Image>>,
}
#[derive(Resource, Default)]
#[derive(Resource, Default, Reflect)]
#[reflect(Resource)]
pub struct ActiveHeads {
heads: [Option<usize>; 5],
heads: [Option<BackpackHead>; 5],
current_slot: usize,
}
@@ -46,8 +47,13 @@ pub struct HeadChanged(pub usize);
pub fn plugin(app: &mut App) {
app.register_type::<HeadDamage>();
app.register_type::<ActiveHeads>();
app.add_systems(OnEnter(GameState::Playing), setup);
app.add_systems(Update, update.run_if(in_state(GameState::Playing)));
app.add_systems(
Update,
(update, update_ammo, update_health).run_if(in_state(GameState::Playing)),
);
app.add_observer(on_select_active_head);
app.add_observer(on_swap_backpack);
}
@@ -82,7 +88,13 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, assets: Res<UIA
commands.insert_resource(HeadsImages { heads });
commands.insert_resource(ActiveHeads {
heads: [Some(0), Some(3), Some(6), Some(8), Some(9)],
heads: [
Some(BackpackHead::new(0)),
Some(BackpackHead::new(3)),
Some(BackpackHead::new(6)),
Some(BackpackHead::new(8)),
Some(BackpackHead::new(9)),
],
current_slot: 0,
});
}
@@ -117,6 +129,7 @@ fn spawn_head_ui(
ImageNode::new(selector),
HeadSelector(head_slot),
));
parent.spawn((
Node {
position_type: PositionType::Absolute,
@@ -125,12 +138,20 @@ fn spawn_head_ui(
ImageNode::new(bg),
));
parent.spawn((
Name::new("head-icon"),
Node {
position_type: PositionType::Absolute,
// width: Val::Px(66.0),
// height: Val::Px(66.0),
..default()
},
BorderRadius::all(Val::Px(9999.)),
BackgroundGradient::from(ConicGradient {
stops: vec![
AngularColorStop::new(Color::linear_rgba(0., 0., 0., 0.9), 0.),
AngularColorStop::new(Color::linear_rgba(0., 0., 0., 0.9), PI * 1.5),
AngularColorStop::new(Color::linear_rgba(0., 0., 0., 0.0), PI * 1.5),
],
position: Position::CENTER,
}),
ImageNode::default(),
Visibility::Hidden,
HeadImage(head_slot),
@@ -140,16 +161,7 @@ fn spawn_head_ui(
position_type: PositionType::Absolute,
..default()
},
BorderRadius::all(Val::Px(9999.)),
ImageNode::new(regular),
BackgroundGradient::from(ConicGradient {
stops: vec![
AngularColorStop::new(Color::linear_rgba(0., 0., 0., 0.9), 0.),
AngularColorStop::new(Color::linear_rgba(0., 0., 0., 0.9), PI * 1.5),
AngularColorStop::new(Color::linear_rgba(0., 0., 0., 0.0), PI * 1.5),
],
position: Position::CENTER,
}),
));
parent
.spawn((Node {
@@ -187,7 +199,7 @@ fn update(
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();
image.image = heads_images.heads[head.head].clone();
} else {
*vis = Visibility::Hidden;
}
@@ -202,6 +214,31 @@ fn update(
}
}
fn update_ammo(res: Res<ActiveHeads>, mut gradients: Query<(&mut BackgroundGradient, &HeadImage)>) {
if res.is_changed() {
for (mut gradient, HeadImage(head)) in gradients.iter_mut() {
if let Some(head) = res.heads[*head] {
let ammo_used = head.ammo_used();
let Gradient::Conic(gradient) = &mut gradient.0[0] else {
continue;
};
let angle = PI * 2. * ammo_used;
gradient.stops[1].angle = Some(angle);
gradient.stops[2].angle = Some(angle);
}
}
}
}
fn update_health(res: Res<ActiveHeads>, mut query: Query<(&mut Node, &HeadDamage)>) {
if res.is_changed() {
for (mut node, HeadDamage(head)) in query.iter_mut() {
node.height =
Val::Percent(res.heads[*head].map(|head| head.damage()).unwrap_or(0.) * 100.);
}
}
}
fn on_select_active_head(
trigger: Trigger<SelectActiveHead>,
mut commands: Commands,
@@ -217,7 +254,7 @@ fn on_select_active_head(
}
commands.trigger(PlaySound::Selection);
commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap()));
commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap().head));
}
fn on_swap_backpack(
@@ -233,16 +270,13 @@ fn on_swap_backpack(
let current_active_slot = res.current_slot;
let current_active_head = res.heads[current_active_slot];
res.heads[current_active_slot] = Some(head.head);
res.heads[current_active_slot] = Some(*head);
if let Some(old_active) = current_active_head {
backpack.heads[backpack_slot] = BackpackHead {
head: old_active,
health: 1.,
};
backpack.heads[backpack_slot] = old_active;
} else {
backpack.heads.remove(backpack_slot);
}
commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap()));
commands.trigger(HeadChanged(res.heads[res.current_slot].unwrap().head));
}