Skip to content

Commit

Permalink
feat: update bar when settings change (#29)
Browse files Browse the repository at this point in the history
  • Loading branch information
sparten11740 committed Nov 16, 2023
1 parent 287f5d4 commit ac4e25c
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 73 deletions.
34 changes: 34 additions & 0 deletions src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,40 @@ pub struct BarSettings<T: Percentage + Component + TypePath> {
pub phantom_data: PhantomData<T>,
}

impl<T: Percentage + Component + TypePath> BarSettings<T> {
fn absolute_height(&self) -> f32 {
match self.height {
BarHeight::Relative(pct) => pct * self.width,
BarHeight::Static(height) => height,
}
}

pub fn normalized_height(&self) -> f32 {
match self.orientation {
BarOrientation::Horizontal => self.absolute_height(),
BarOrientation::Vertical => self.width,
}
}

pub fn normalized_width(&self) -> f32 {
match self.orientation {
BarOrientation::Horizontal => self.width,
BarOrientation::Vertical => self.absolute_height(),
}
}

fn offset_axis(&self) -> Vec3 {
match self.orientation {
BarOrientation::Horizontal => Vec3::Y,
BarOrientation::Vertical => Vec3::X,
}
}

pub fn normalized_offset(&self) -> Vec3 {
self.offset * self.offset_axis()
}
}

impl<T: Percentage + Component + TypePath> Default for BarSettings<T> {
fn default() -> Self {
Self {
Expand Down
169 changes: 96 additions & 73 deletions src/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bevy::asset::load_internal_asset;
use bevy::pbr::{NotShadowCaster, NotShadowReceiver};
use bevy::prelude::*;

use crate::configuration::{BarHeight, ForegroundColor, Percentage};
use crate::configuration::{ForegroundColor, Percentage};
use crate::constants::BAR_SHADER_HANDLE;
use crate::material::BarMaterial;
use crate::mesh::MeshHandles;
Expand Down Expand Up @@ -39,7 +39,10 @@ impl<T: Percentage + Component + TypePath> Plugin for HealthBarPlugin<T> {
.init_resource::<ColorScheme<T>>()
.register_type::<BarSettings<T>>()
.add_systems(PostUpdate, reset_rotation)
.add_systems(Update, (spawn::<T>, remove::<T>, update::<T>));
.add_systems(
Update,
(spawn::<T>, remove::<T>, update::<T>, update_settings::<T>),
);
}
}

Expand All @@ -61,81 +64,59 @@ fn spawn<T: Percentage + Component + TypePath>(
color_scheme: Res<ColorScheme<T>>,
query: Query<(Entity, &T, &BarSettings<T>), Added<T>>,
) {
query.iter().for_each(
|(
entity,
percentage,
BarSettings {
query.iter().for_each(|(entity, percentage, settings)| {
let width = settings.normalized_width();
let height = settings.normalized_height();

let mesh = mesh_handles.get(width, height).cloned().unwrap_or_else(|| {
mesh_handles.insert(
width,
height,
offset,
border,
orientation,
..
},
)| {
let height = match height {
BarHeight::Relative(pct) => pct * width,
BarHeight::Static(height) => *height,
};

let (width, height, vertical, offset_axis) = match orientation {
BarOrientation::Horizontal => (*width, height, false, Vec3::Y),
BarOrientation::Vertical => (height, *width, true, Vec3::X),
};

let mesh = mesh_handles.get(width, height).cloned().unwrap_or_else(|| {
mesh_handles.insert(
width,
height,
meshes.add(Mesh::from(shape::Quad::new(Vec2::new(width, height)))),
)
});

let offset = *offset * offset_axis;

let (high, moderate, low) = match color_scheme.foreground_color {
ForegroundColor::Static(color) => (color, color, color),
ForegroundColor::TriSpectrum {
high,
moderate,
low,
} => (high, moderate, low),
};

let material = materials.add(BarMaterial {
value_and_dimensions: (percentage.value(), width, height, border.width).into(),
background_color: color_scheme.background_color,
high_color: high,
moderate_color: moderate,
low_color: low,
vertical,
offset: offset.extend(0.),
border_color: border.color,
});

let health_bar = commands
.spawn((
Name::new(format!("{}Bar", T::type_path())),
MaterialMeshBundle {
mesh,
material,
..default()
},
NotShadowCaster,
NotShadowReceiver,
))
.id();

commands
.entity(entity)
.insert(WithBar(health_bar, PhantomData::<T>))
.add_child(health_bar);
},
);
meshes.add(Mesh::from(shape::Quad::new(Vec2::new(width, height)))),
)
});

let (high, moderate, low) = match color_scheme.foreground_color {
ForegroundColor::Static(color) => (color, color, color),
ForegroundColor::TriSpectrum {
high,
moderate,
low,
} => (high, moderate, low),
};

let material = materials.add(BarMaterial {
value_and_dimensions: (percentage.value(), width, height, settings.border.width).into(),
background_color: color_scheme.background_color,
high_color: high,
moderate_color: moderate,
low_color: low,
vertical: settings.orientation == BarOrientation::Vertical,
offset: settings.normalized_offset().extend(0.),
border_color: settings.border.color,
});

let health_bar = commands
.spawn((
Name::new(format!("{}Bar", T::type_path())),
MaterialMeshBundle {
mesh,
material,
..default()
},
NotShadowCaster,
NotShadowReceiver,
))
.id();

commands
.entity(entity)
.insert(WithBar(health_bar, PhantomData::<T>))
.add_child(health_bar);
});
}

fn update<T: Percentage + Component>(
fn update<T: Percentage + Component + TypePath>(
mut materials: ResMut<Assets<BarMaterial>>,
parent_query: Query<(&WithBar<T>, &T), Changed<T>>,
bar_query: Query<&Handle<BarMaterial>>,
Expand All @@ -149,6 +130,48 @@ fn update<T: Percentage + Component>(
});
}

#[allow(clippy::type_complexity)]
fn update_settings<T: Percentage + Component + TypePath>(
mut commands: Commands,
mut materials: ResMut<Assets<BarMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
mut mesh_handles: ResMut<MeshHandles>,
parent_query: Query<(&WithBar<T>, &BarSettings<T>), Changed<BarSettings<T>>>,
bar_query: Query<(Entity, &Handle<BarMaterial>, &Handle<Mesh>)>,
) {
parent_query.iter().for_each(|(bar, settings)| {
let Ok((entity, material_handle, mesh_handle)) = bar_query.get(bar.get()) else {
return;
};

let material = materials.get_mut(material_handle).unwrap();
let offset = settings.normalized_offset().extend(0.);
let width = settings.normalized_width();
let height = settings.normalized_height();

let mesh_for_settings_dimensions = mesh_handles.get(width, height).cloned();
let mesh_changed = mesh_for_settings_dimensions
.clone()
.map_or(true, |handle| handle != *mesh_handle);

if mesh_changed {
let new_mesh = mesh_for_settings_dimensions.unwrap_or(mesh_handles.insert(
width,
height,
meshes.add(Mesh::from(shape::Quad::new(Vec2::new(width, height)))),
));
commands.entity(entity).insert(new_mesh);
material.value_and_dimensions.y = width;
material.value_and_dimensions.z = height;
}

material.offset = offset;
material.border_color = settings.border.color;
material.value_and_dimensions.w = settings.border.width;
material.vertical = settings.orientation == BarOrientation::Vertical;
});
}

fn remove<T: Percentage + Component>(
mut commands: Commands,
mut removals: RemovedComponents<T>,
Expand Down

0 comments on commit ac4e25c

Please sign in to comment.