feat: load a project file and display a loading screen

This commit is contained in:
Christopher Willis-Ford 2022-12-09 20:20:27 -08:00
parent 044b13ad4f
commit 780dba67c0
4 changed files with 121 additions and 24 deletions

14
Cargo.lock generated
View file

@ -2484,6 +2484,8 @@ name = "scratch-bevy"
version = "0.1.0"
dependencies = [
"bevy",
"futures-lite",
"zip",
]
[[package]]
@ -3295,3 +3297,15 @@ name = "xi-unicode"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a67300977d3dc3f8034dae89778f502b6ba20b269527b3223ba59c0cf393bb8a"
[[package]]
name = "zip"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "537ce7411d25e54e8ae21a7ce0b15840e7bfcff15b51d697ec3266cc76bdf080"
dependencies = [
"byteorder",
"crc32fast",
"crossbeam-utils",
"flate2",
]

View file

@ -8,6 +8,8 @@ rust-version = "1.65"
[dependencies]
bevy = "0.9.1"
futures-lite = "1.12.0"
zip = { version = "0.6.3", default-features = false, features = ["deflate"] }
[features]
# remember to disable bevy's "dynamic" feature for release builds

Binary file not shown.

View file

@ -1,11 +1,20 @@
use bevy::{
prelude::*,
tasks::*,
time::FixedTimestep,
window::*,
};
use futures_lite::future;
const TIME_STEP: f64 = 1. / 30.;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
enum AppState {
Loading,
Running,
}
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin {
@ -20,12 +29,69 @@ fn main() {
},
..default()
}))
.add_plugin(ScratchLoadingScreenPlugin)
.add_plugin(ScratchStagePlugin)
.add_plugin(ScratchDemoProjectPlugin)
.add_system(close_on_esc)
.run();
}
//
// Loading screen
//
pub struct ScratchLoadingScreenPlugin;
#[derive(Component)]
struct LoadingScreen;
impl Plugin for ScratchLoadingScreenPlugin {
fn build(&self, app: &mut App) {
app
.add_state(AppState::Loading)
.add_system_set(
SystemSet::on_enter(AppState::Loading)
.with_system(ScratchLoadingScreenPlugin::start_loading_screen)
)
.add_system_set(
SystemSet::on_update(AppState::Loading)
.with_system(ScratchLoadingScreenPlugin::update_loading_screen)
)
.add_system_set(
SystemSet::on_exit(AppState::Loading)
.with_system(ScratchLoadingScreenPlugin::stop_loading_screen)
);
}
}
impl ScratchLoadingScreenPlugin {
fn start_loading_screen(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn((
SpriteBundle {
texture: asset_server.load("squirrel.png"),
..default()
},
LoadingScreen
));
}
fn update_loading_screen(mut loading_screen_query: Query<&mut Transform, With<LoadingScreen>>) {
let one_degree_in_radians: f32 = (1.0_f32).to_radians();
for mut transform in &mut loading_screen_query {
transform.rotate_z(-one_degree_in_radians);
}
}
fn stop_loading_screen(mut commands: Commands, mut loading_screen_query: Query<Entity, With<LoadingScreen>>) {
for loading_screen in &mut loading_screen_query {
commands.entity(loading_screen).despawn();
}
}
}
//
// Sprite
//
@ -109,31 +175,46 @@ pub struct ScratchDemoProjectPlugin;
impl Plugin for ScratchDemoProjectPlugin {
fn build(&self, app: &mut App) {
app
.add_startup_system(add_demo_project_sprites);
.add_startup_system(project_load)
.add_system_set(
SystemSet::on_update(AppState::Loading)
.with_system(project_check_load)
);
}
}
fn add_demo_project_sprites(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(
SpriteBundle {
texture: asset_server.load("squirrel.png"),
transform: Transform::from_scale(Vec3::new(0.5, 0.5, 1.)),
..default()
})
.insert(Name("Sprite 1".to_string()))
.insert(ScratchScripts(vec![
ScratchCode::MoveOneStep,
ScratchCode::TurnClockwise,
]));
commands.spawn(
SpriteBundle {
texture: asset_server.load("squirrel.png"),
transform: Transform::from_scale(Vec3::new(0.5, 0.5, 1.)),
..default()
})
.insert(Name("Sprite 2".to_string()))
.insert(ScratchScripts(vec![
ScratchCode::MoveTwoSteps,
ScratchCode::TurnCounterClockwise,
]));
#[derive(Resource)]
struct ProjectZip(HandleUntyped);
#[derive(Resource)]
struct ProjectLoadTask(Task<i32>);
fn project_load(mut commands: Commands, asset_server: Res<AssetServer>) {
info!("Starting project load");
let project_handle = asset_server.load_untyped("Infinite Toebeans.sb3");
commands.insert_resource(ProjectZip(project_handle))
}
fn project_check_load(mut commands: Commands, mut app_state: ResMut<State<AppState>>, project_zip: Option<Res<ProjectZip>>, mut project_task: Option<ResMut<ProjectLoadTask>>) {
if let Some(project_zip) = project_zip {
if project_zip.is_added() {
info!("Project archive is loaded. Time to unpack...");
let thread_pool = AsyncComputeTaskPool::get();
let load_task = thread_pool.spawn(async move {
let start_time = std::time::Instant::now();
while start_time.elapsed() < std::time::Duration::from_secs_f32(4.2)
{
// spin
}
42 // return hydrated project
});
commands.insert_resource(ProjectLoadTask(load_task));
}
else if let Some(project_task) = &mut project_task {
if let Some(project_data) = future::block_on(future::poll_once(&mut project_task.0)) {
info!("Project data is: {}", project_data);
app_state.set(AppState::Running).unwrap();
}
}
}
}