use bevy::{ color::palettes::css::*, ecs::{component::HookContext, world::DeferredWorld}, prelude::*, ui::Val::*, }; use crate::game::consumables::{Fuel, FuelChanged}; #[derive(Component)] #[require(Label)] #[component(on_add = FuelGauge::refresh_label)] pub struct FuelGauge(Entity); impl FuelGauge { /// Default bundle for a machine's fuel gauge widget. Give it the ID of the /// machine whose info it is displaying. pub fn bundle(target: Entity) -> impl Bundle { ( FuelGauge(target), Node { min_width: Px(20.0), min_height: Px(10.0), ..default() }, BackgroundColor(GREEN.into()), Text::new("Fuel: "), ) } /// Observer system to update the [`FuelGauge`] widget when a machine emits a /// [`FuelChanged`] event. pub fn detect_fuel_change( event: Trigger, fuel_levels: Query<&Fuel>, mut gauges: Query<(&FuelGauge, &mut Text)>, ) { // Find the FuelGauge that references the same Entity as the event target. // That gauge's `Text` is the one to update. let (_, mut label) = gauges .iter_mut() .find(|(gauge, _label)| gauge.0 == event.target()) .expect("Couldn't find any fuel gauges"); let fuel = fuel_levels.get(event.target()).expect( "Logic error: a `FuelChanged` event was targetted at an entity with no `Fuel` component.", ); label.0 = format!("Fuel: {}", fuel.0); } fn refresh_label(mut world: DeferredWorld, ctx: HookContext) { // Get the machine ID from the FuelGauge component. let Some(machine_id) = world.get::(ctx.entity).map(|fg| fg.0) else { panic!("Couldn't get a FuelGauge during it's on-add hook run!"); }; // and fuel level let Some(fuel) = world.get::(machine_id).map(|lvl| lvl.0) else { // TODO: Maybe don't panic and just emit a warning. panic!("Couldn't get a Fuel for a machine during a FuelGauge on-add hook."); }; // Get an excl ref to the Text component so we can redraw its text let Some(mut label) = world.get_mut::(ctx.entity) else { panic!() }; label.0 = format!("Fuel: {}", fuel); } }