use bevy::app::AppExit;
use bevy::asset::UntypedAssetId;
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
use bevy::prelude::*;
use bevy_asset_loader::prelude::*;
use iyes_progress::{Progress, ProgressPlugin, ProgressReturningSystem, ProgressTracker};
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
ProgressPlugin::<MyStates>::new()
.with_state_transition(MyStates::AssetLoading, MyStates::Next),
FrameTimeDiagnosticsPlugin::default(),
))
.init_state::<MyStates>()
.add_loading_state(
LoadingState::new(MyStates::AssetLoading)
.load_collection::<TextureAssets>()
.load_collection::<AudioAssets>(),
)
.add_systems(OnEnter(MyStates::AssetLoading), render_description)
.add_systems(OnEnter(MyStates::Next), expect)
.add_systems(
Update,
(
track_fake_long_task.track_progress::<MyStates>(),
print_progress,
)
.chain()
.run_if(in_state(MyStates::AssetLoading))
.after(LoadingStateSet(MyStates::AssetLoading)),
)
.run();
}
const DURATION_LONG_TASK_IN_SECS: f64 = 4.0;
#[derive(AssetCollection, Resource)]
struct AudioAssets {
#[asset(path = "audio/background.ogg")]
background: Handle<AudioSource>,
#[asset(path = "audio/plop.ogg")]
plop: Handle<AudioSource>,
}
#[derive(AssetCollection, Resource)]
struct TextureAssets {
#[asset(path = "images/player.png")]
player: Handle<Image>,
#[asset(path = "images/tree.png")]
tree: Handle<Image>,
#[asset(path = "images/female_adventurer_sheet.png")]
female_adventurer: Handle<Image>,
#[asset(texture_atlas_layout(tile_size_x = 96, tile_size_y = 99, columns = 8, rows = 1))]
female_adventurer_layout: Handle<TextureAtlasLayout>,
}
fn render_description(mut commands: Commands) {
commands.spawn(Camera2d);
commands.spawn(Text::new(
r#"
See the console for progress output
This window will close when progress completes..."#,
));
}
fn track_fake_long_task(time: Res<Time>) -> Progress {
if time.elapsed_secs_f64() > DURATION_LONG_TASK_IN_SECS {
info!("Long fake task is completed");
true.into()
} else {
false.into()
}
}
fn expect(
audio_assets: Res<AudioAssets>,
texture_assets: Res<TextureAssets>,
asset_server: Res<AssetServer>,
texture_atlas_layouts: Res<Assets<TextureAtlasLayout>>,
mut quit: EventWriter<AppExit>,
) {
is_recursively_loaded(&audio_assets.background, &asset_server);
is_recursively_loaded(&audio_assets.plop, &asset_server);
texture_atlas_layouts
.get(&texture_assets.female_adventurer_layout)
.expect("Texture atlas should be added to its assets resource.");
is_recursively_loaded(&texture_assets.female_adventurer, &asset_server);
is_recursively_loaded(&texture_assets.player, &asset_server);
is_recursively_loaded(&texture_assets.tree, &asset_server);
info!("Everything looks good!");
info!("Quitting the application...");
quit.write(AppExit::Success);
}
fn print_progress(
progress: Res<ProgressTracker<MyStates>>,
diagnostics: Res<DiagnosticsStore>,
mut last_done: Local<u32>,
) {
let progress = progress.get_global_progress();
if progress.done > *last_done {
*last_done = progress.done;
info!(
"[Frame {}] Changed progress: {:?}",
diagnostics
.get(&FrameTimeDiagnosticsPlugin::FRAME_COUNT)
.map(|diagnostic| diagnostic.value().unwrap_or(0.))
.unwrap_or(0.),
progress
);
}
}
fn is_recursively_loaded(handle: impl Into<UntypedAssetId>, asset_server: &AssetServer) -> bool {
asset_server
.get_recursive_dependency_load_state(handle)
.map(|state| state.is_loaded())
.unwrap_or(false)
}
#[derive(Clone, Eq, PartialEq, Debug, Hash, Default, States)]
enum MyStates {
#[default]
AssetLoading,
Next,
}