use std::time::Duration; use bevy::prelude::*; use iyes_loopless::prelude::{AppLooplessStateExt, ConditionSet}; use crate::system::flow::AppState; #[derive(Debug)] pub struct GlobalTimer { internal: Duration, } impl Default for GlobalTimer { fn default() -> Self { GlobalTimer { internal: Duration::ZERO, } } } impl GlobalTimer { const GOAL: Duration = Duration::from_secs(10); pub fn tick(&mut self, dt: Duration) { self.internal += dt; } pub fn is_triggered(&self) -> bool { self.internal >= Self::GOAL } pub fn settle(&mut self) { while self.internal >= Self::GOAL { self.internal -= Self::GOAL } } pub fn percent_complete(&self) -> f32 { self.internal.as_secs_f32() / Self::GOAL.as_secs_f32() } } pub fn tick_global_timer(time: Res<Time>, mut timer: ResMut<GlobalTimer>) { timer.settle(); timer.tick(time.delta()); } #[derive(Copy, Clone, Default, Component)] pub struct GlobalTimerUi; pub fn spawn_global_timer_ui(mut commands: Commands, timer: Res<GlobalTimer>) { commands .spawn_bundle(NodeBundle { style: Style { size: Size::new(Val::Auto, Val::Px(25.0)), position_type: PositionType::Absolute, position: UiRect::new( Val::Px(0.0), Val::Percent((1.0 - timer.percent_complete()) * 100.0), Val::Auto, Val::Px(0.0), ), ..Default::default() }, color: Color::ALICE_BLUE.into(), ..Default::default() }) .insert(GlobalTimerUi); } pub fn update_global_timer_ui( timer: Res<GlobalTimer>, mut query: Query<&mut Style, With<GlobalTimerUi>>, ) { for mut style in &mut query { style.position.right = Val::Percent((1.0 - timer.percent_complete()) * 100.0); } } pub fn remove_global_timer_ui(mut commands: Commands, query: Query<Entity, With<GlobalTimerUi>>) { for entity in &query { commands.entity(entity).despawn_recursive(); } } pub struct TimingPlugin; impl Plugin for TimingPlugin { fn build(&self, app: &mut App) { app.init_resource::<GlobalTimer>() .add_system_to_stage(CoreStage::First, tick_global_timer) .add_enter_system(AppState::InGame, spawn_global_timer_ui) .add_system_set( ConditionSet::new() .run_in_state(AppState::InGame) .with_system(update_global_timer_ui) .into(), ) .add_exit_system(AppState::InGame, remove_global_timer_ui); } }