From ac4e25cf24f7467f433f7fd9c5f286d209b3d813 Mon Sep 17 00:00:00 2001 From: Jan W Date: Thu, 16 Nov 2023 21:08:03 +0800 Subject: [PATCH] feat: update bar when settings change (#29) --- src/configuration.rs | 34 +++++++++ src/plugin.rs | 169 ++++++++++++++++++++++++------------------- 2 files changed, 130 insertions(+), 73 deletions(-) diff --git a/src/configuration.rs b/src/configuration.rs index 5ec5422..7f90877 100644 --- a/src/configuration.rs +++ b/src/configuration.rs @@ -23,6 +23,40 @@ pub struct BarSettings { pub phantom_data: PhantomData, } +impl BarSettings { + 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 Default for BarSettings { fn default() -> Self { Self { diff --git a/src/plugin.rs b/src/plugin.rs index c16bf5e..e5f1ad5 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -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; @@ -39,7 +39,10 @@ impl Plugin for HealthBarPlugin { .init_resource::>() .register_type::>() .add_systems(PostUpdate, reset_rotation) - .add_systems(Update, (spawn::, remove::, update::)); + .add_systems( + Update, + (spawn::, remove::, update::, update_settings::), + ); } } @@ -61,81 +64,59 @@ fn spawn( color_scheme: Res>, query: Query<(Entity, &T, &BarSettings), Added>, ) { - 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::)) - .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::)) + .add_child(health_bar); + }); } -fn update( +fn update( mut materials: ResMut>, parent_query: Query<(&WithBar, &T), Changed>, bar_query: Query<&Handle>, @@ -149,6 +130,48 @@ fn update( }); } +#[allow(clippy::type_complexity)] +fn update_settings( + mut commands: Commands, + mut materials: ResMut>, + mut meshes: ResMut>, + mut mesh_handles: ResMut, + parent_query: Query<(&WithBar, &BarSettings), Changed>>, + bar_query: Query<(Entity, &Handle, &Handle)>, +) { + 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( mut commands: Commands, mut removals: RemovedComponents,