Skip to content

Instantly share code, notes, and snippets.

@gavxin
Created January 24, 2024 14:46
Show Gist options
  • Save gavxin/63bdd92e38de3033aee05aed5daa77bc to your computer and use it in GitHub Desktop.
Save gavxin/63bdd92e38de3033aee05aed5daa77bc to your computer and use it in GitHub Desktop.
bevy ui simple ProgressBar
use bevy::{ecs::system::Command, prelude::*};
pub struct ProgressBarPlugin;
impl Plugin for ProgressBarPlugin {
fn build(&self, app: &mut App) {
app.register_type::<ProgressBarValues>()
.add_systems(Update, progress_bar_system);
}
}
pub struct AddProgressBar {
pub background_image: Handle<Image>,
pub foreground_image: Handle<Image>,
pub right_to_left: bool,
pub values: ProgressBarValues,
pub style: Style,
pub entity: Entity,
}
impl Default for AddProgressBar {
fn default() -> Self {
Self {
background_image: Handle::default(),
foreground_image: Handle::default(),
right_to_left: false,
values: ProgressBarValues {
min: 0.,
max: 100.,
step: 1.,
value: 100.,
},
style: Default::default(),
entity: Entity::PLACEHOLDER,
}
}
}
impl Command for AddProgressBar {
fn apply(self, world: &mut World) {
let percent = self.values.as_percent();
let entity = if self.entity == Entity::PLACEHOLDER {
world.spawn_empty().id()
} else {
self.entity
};
world
.entity_mut(entity)
.insert((
self.values,
NodeBundle {
style: self.style,
..default()
},
))
.with_children(|builder| {
builder.spawn((
Name::new("progress_bar_bg"),
ImageBundle {
style: Style {
width: Val::Percent(100.),
height: Val::Percent(100.),
..default()
},
image: self.background_image.into(),
..default()
},
));
let right = if self.right_to_left {
Val::Px(0.)
} else {
Val::Auto
};
let justify_content = if self.right_to_left {
JustifyContent::FlexEnd
} else {
JustifyContent::FlexStart
};
builder
.spawn((
ProgressBarForeground,
Name::new("progress_bar_fg"),
NodeBundle {
style: Style {
width: Val::Percent(percent),
height: Val::Percent(100.),
right,
justify_content,
position_type: PositionType::Absolute,
overflow: Overflow::clip(),
..default()
},
..default()
},
))
.with_children(|builder| {
builder.spawn(ImageBundle {
image: self.foreground_image.into(),
..default()
});
});
});
}
}
#[derive(Component)]
pub struct ProgressBarForeground;
#[derive(Component, Debug, Reflect)]
pub struct ProgressBarValues {
pub min: f32,
pub max: f32,
pub step: f32,
value: f32,
}
impl ProgressBarValues {
pub fn as_percent(&self) -> f32 {
100. * ((self.value - self.min) / self.step).round() * self.step / (self.max - self.min)
}
pub fn value(&self) -> f32 {
self.value
}
pub fn set_value(&mut self, value: f32) {
self.value = ((value.clamp(self.min, self.max) - self.min) / self.step).round() * self.step
+ self.min;
}
}
fn progress_bar_system(
mut query: Query<(&Children, &mut ProgressBarValues), Changed<ProgressBarValues>>,
mut foreground_query: Query<&mut Style, With<ProgressBarForeground>>,
) {
for (children, mut bar) in query.iter_mut() {
let value = bar.value();
bar.set_value(value);
let width: Val = Val::Percent(bar.as_percent());
for child in children.iter() {
if let Ok(mut style) = foreground_query.get_mut(*child) {
style.width = width;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment