use bevy::prelude::*;
use iyes_progress::prelude::*;
use std::time::Duration;
#[derive(States, Default, Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum MyStates {
#[default]
Loading,
Done,
}
fn mouse_clicks(
input: Res<ButtonInput<MouseButton>>,
mut n_clicks: Local<u32>,
) -> Progress {
const MAX_CLICKS: u32 = 5;
if input.just_pressed(MouseButton::Left) {
*n_clicks += 1;
}
Progress {
done: *n_clicks,
total: MAX_CLICKS,
}
}
fn hold_spacebar(
time: Res<Time>,
input: Res<ButtonInput<KeyCode>>,
mut total_held_time: Local<Duration>,
) -> Progress {
const TARGET_DURATION: Duration = Duration::from_secs(5);
if input.pressed(KeyCode::Space) {
*total_held_time += time.delta();
}
(*total_held_time > TARGET_DURATION).into()
}
fn hidden_timer(
time: Res<Time>,
mut timer: Local<Option<Timer>>,
) -> HiddenProgress {
if let Some(timer) = &mut *timer {
timer.tick(time.delta());
timer.is_finished().into()
} else {
*timer = Some(Timer::new(Duration::from_secs(10), TimerMode::Once));
false.into()
}
}
fn count_abc_keypresses(
progress_a: ProgressEntry<MyStates>,
progress_b: ProgressEntry<MyStates>,
progress_c: ProgressEntry<MyStates>,
input: Res<ButtonInput<KeyCode>>,
mut initted: Local<bool>,
) {
if !*initted {
progress_a.set_total(3);
progress_b.set_total(2);
progress_c.set_total(1);
*initted = true;
}
if input.just_pressed(KeyCode::KeyA) && !progress_a.is_ready() {
progress_a.add_done(1);
}
if input.just_pressed(KeyCode::KeyB) && !progress_b.is_ready() {
progress_b.add_done(1);
}
if input.just_pressed(KeyCode::KeyC) && !progress_c.is_ready() {
progress_c.add_done(1);
}
}
#[derive(Component)]
struct MyProgressyThing;
fn spawn_progress_entity(mut commands: Commands) {
commands.spawn((
MyProgressyThing,
DespawnOnExit(MyStates::Loading),
ProgressEntity::<MyStates>::default()
.with_progress(0, 1)
.with_hidden_progress(0, 1),
));
}
fn update_progress_entity(
mut q: Query<&mut ProgressEntity<MyStates>, With<MyProgressyThing>>,
) {
let Ok(mut p) = q.single_mut() else {
return;
};
p.visible.done = 1;
p.hidden.done = 1;
}
#[derive(Component)]
struct ProgressBarInner;
#[derive(Component)]
struct ProgressBarText;
fn update_progress_bar(
pt: Res<ProgressTracker<MyStates>>,
mut q_bar_inner: Query<&mut Node, With<ProgressBarInner>>,
mut q_bar_text: Query<&mut Text, With<ProgressBarText>>,
) {
let progress = pt.get_global_progress();
let ratio: f32 = progress.into();
for mut text in q_bar_text.iter_mut() {
*text = Text::new(format!("{}/{}", progress.done, progress.total));
}
for mut node in q_bar_inner.iter_mut() {
node.width = Val::Percent(ratio * 100.0);
}
}
fn setup_loading_ui(mut commands: Commands) {
commands.spawn((
Node {
position_type: PositionType::Absolute,
top: Val::Px(16.0),
left: Val::Px(16.0),
..Default::default()
},
Text::new(
"Surprise! In this \"loading\" screen,
YOU have to do things and the game waits for YOU!
To progress:
- Hold the spacebar for 5 seconds
- Press the A/B/C keys a few times
- Click the mouse a few times",
),
DespawnOnExit(MyStates::Loading),
));
let bar_outer = commands
.spawn((
BackgroundColor(Color::srgb(0.25, 0.25, 0.25)),
BorderColor::all(Color::srgb(1.0, 1.0, 1.0)),
Node {
position_type: PositionType::Absolute,
top: Val::Percent(69.0),
bottom: Val::Percent(24.0),
left: Val::Percent(12.0),
right: Val::Percent(12.0),
border: UiRect::all(Val::Px(1.0)),
border_radius: BorderRadius::all(Val::Px(6.0)),
..Default::default()
},
DespawnOnExit(MyStates::Loading),
))
.id();
let bar_inner = commands
.spawn((
BackgroundColor(Color::srgb(0.75, 0.75, 0.75)),
BorderColor::all(Color::srgb(0.5, 0.5, 0.5)),
Node {
height: Val::Percent(100.0),
width: Val::Percent(0.0),
padding: UiRect::left(Val::Px(16.0)),
align_items: AlignItems::Center,
border: UiRect::all(Val::Px(1.0)),
border_radius: BorderRadius::all(Val::Px(8.0)),
..Default::default()
},
ProgressBarInner,
))
.id();
let bar_text = commands
.spawn((
Text::new("0/0".to_owned()),
TextColor(Color::WHITE),
ProgressBarText,
))
.id();
commands.entity(bar_outer).add_child(bar_inner);
commands.entity(bar_inner).add_child(bar_text);
}
fn setup_done_ui(mut commands: Commands) {
commands.spawn((
Node {
position_type: PositionType::Absolute,
top: Val::Px(16.0),
left: Val::Px(16.0),
..Default::default()
},
Text::new("All done! You are the BEST!"),
));
}
fn setup_camera(mut commands: Commands) {
commands.spawn(Camera2d);
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_state::<MyStates>()
.add_plugins(
ProgressPlugin::<MyStates>::new()
.with_state_transition(MyStates::Loading, MyStates::Done),
)
.add_systems(
Update,
(
hold_spacebar.track_progress::<MyStates>(),
hidden_timer.track_progress::<MyStates>(),
mouse_clicks
.track_progress_and_stop::<MyStates>(),
count_abc_keypresses,
update_progress_entity,
)
.run_if(in_state(MyStates::Loading)),
)
.add_systems(OnEnter(MyStates::Loading), spawn_progress_entity)
.add_systems(Startup, setup_camera)
.add_systems(OnEnter(MyStates::Loading), setup_loading_ui)
.add_systems(OnEnter(MyStates::Done), setup_done_ui)
.add_systems(
Update,
update_progress_bar.run_if(in_state(MyStates::Loading)),
)
.run();
}