From 4dbf524e3f42d477640078df34d566db83d293ec Mon Sep 17 00:00:00 2001 From: Elijah Voigt Date: Mon, 9 Oct 2023 20:10:53 -0700 Subject: [PATCH] load state actually blocks now --- Cargo.lock | 7 +++ Cargo.toml | 2 +- examples/models.rs | 35 ++++++++++++ src/debug.rs | 9 +++- src/display2d.rs | 69 ++++++++++++------------ src/display3d.rs | 130 +++++++++++++++++++++++++++++++++++---------- src/game.rs | 3 +- src/main.rs | 35 +++++++++--- src/menu.rs | 2 +- 9 files changed, 219 insertions(+), 73 deletions(-) create mode 100644 examples/models.rs diff --git a/Cargo.lock b/Cargo.lock index d5f04e2..4717c1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1904,6 +1904,7 @@ dependencies = [ "bytemuck", "byteorder", "color_quant", + "jpeg-decoder", "num-rational", "num-traits", "png", @@ -2026,6 +2027,12 @@ dependencies = [ "libc", ] +[[package]] +name = "jpeg-decoder" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" + [[package]] name = "js-sys" version = "0.3.64" diff --git a/Cargo.toml b/Cargo.toml index 0b3201e..928d0f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,4 @@ build = "build.rs" [dependencies] bevy_fmod = { version = "0.3", features = ["live-update"] } -bevy = "0.11" +bevy = { version = "0.11", features = ["jpeg", "hdr"] } diff --git a/examples/models.rs b/examples/models.rs new file mode 100644 index 0000000..1627361 --- /dev/null +++ b/examples/models.rs @@ -0,0 +1,35 @@ +//! This example demonstrates Bevy's immediate mode drawing API intended for visual debugging. + +use bevy::prelude::*; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_systems(Startup, setup) + .add_systems(Update, system) + .run(); +} + +fn setup(mut commands: Commands) { + commands.spawn(Camera3dBundle { + transform: Transform::from_xyz(0., 1.5, 6.).looking_at(Vec3::ZERO, Vec3::Y), + ..default() + }); + // light + commands.spawn(PointLightBundle { + point_light: PointLight { + intensity: 1500.0, + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }); +} + +fn system(mut gizmos: Gizmos) { + gizmos.cuboid( + Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.)), + Color::BLACK, + ); +} diff --git a/src/debug.rs b/src/debug.rs index d409261..562d2cd 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -79,7 +79,7 @@ fn toggle_debug_mode( } fn toggle_debug_ui( - mut visibility: Query<&mut Visibility, (With, Without)>, + mut visibility: Query<&mut Visibility, With>, enabled: Option>, ) { visibility.iter_mut().for_each(|mut vis| { @@ -94,7 +94,12 @@ fn init_debug_ui(mut commands: Commands) { commands .spawn(( NodeBundle { - style: Style { ..default() }, + style: Style { + padding: UiRect::all(Val::Px(10.0)), + ..default() + }, + background_color: Color::BLACK.with_a(0.6).into(), + visibility: Visibility::Hidden, ..default() }, DebugRoot, diff --git a/src/display2d.rs b/src/display2d.rs index a99228b..14e095c 100644 --- a/src/display2d.rs +++ b/src/display2d.rs @@ -23,38 +23,35 @@ pub(crate) struct Display2dPlugin; impl Plugin for Display2dPlugin { fn build(&self, app: &mut App) { - app.add_systems( - Startup, - (initialize_camera, load_spritesheet, set_background) - .run_if(in_state(GameState::Loading)), - ) - .add_systems( - Update, - ( - initialize_board.run_if(resource_added::()), - active_tile.run_if(in_state(GameState::Display2d)), - menu::exit_to_menu.run_if(in_state(GameState::Display2d)), - select_piece - .run_if(in_state(GameState::Display2d)) - .run_if(not(any_with_component::())), - move_piece - .run_if(in_state(GameState::Display2d)) - .run_if(any_with_component::()), - place_piece - .run_if(in_state(GameState::Display2d)) - .run_if(any_with_component::()), - cancel_place - .run_if(in_state(GameState::Display2d)) - .run_if(any_with_component::()), - update_background.run_if(on_event::()), - draw_board - .run_if(resource_exists::()) - .run_if(any_component_removed::()) // trigger if item was de-selected - .run_if(any_with_component::()), - ), - ) - .add_systems(OnEnter(GameState::Display2d), (activate, draw_board)) - .add_systems(OnExit(GameState::Display2d), deactivate); + app.add_systems(Startup, (initialize_camera, set_background)) + .add_systems(OnEnter(GameState::Loading), load_spritesheet) + .add_systems(OnExit(GameState::Loading), initialize_board) + .add_systems( + Update, + ( + active_tile.run_if(in_state(GameState::Display2d)), + menu::exit_to_menu.run_if(in_state(GameState::Display2d)), + select_piece + .run_if(in_state(GameState::Display2d)) + .run_if(not(any_with_component::())), + move_piece + .run_if(in_state(GameState::Display2d)) + .run_if(any_with_component::()), + place_piece + .run_if(in_state(GameState::Display2d)) + .run_if(any_with_component::()), + cancel_place + .run_if(in_state(GameState::Display2d)) + .run_if(any_with_component::()), + update_background.run_if(on_event::()), + draw_board + .run_if(resource_exists::()) + .run_if(any_component_removed::()) // trigger if item was de-selected + .run_if(any_with_component::()), + ), + ) + .add_systems(OnEnter(GameState::Display2d), (activate, draw_board)) + .add_systems(OnExit(GameState::Display2d), deactivate); } } @@ -100,7 +97,7 @@ fn load_spritesheet( mut commands: Commands, ) { let atlas = TextureAtlas::from_grid( - server.load("sprites.png"), + server.load("images/sprites.png"), Vec2::new(TILE_SIZE, TILE_SIZE), 5, 1, @@ -120,7 +117,7 @@ fn set_background( commands.spawn(( BackgroundImage, SpriteBundle { - texture: server.load("mars-daybreak.png"), + texture: server.load("images/mars-daybreak.png"), sprite: Sprite { custom_size: Some(Vec2 { x: window.single().width(), @@ -128,6 +125,10 @@ fn set_background( }), ..default() }, + transform: Transform { + translation: Vec3::NEG_Z, + ..default() + }, ..default() }, )); diff --git a/src/display3d.rs b/src/display3d.rs index e977239..00c5b20 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -4,68 +4,144 @@ pub(crate) struct Display3dPlugin; impl Plugin for Display3dPlugin { fn build(&self, app: &mut App) { - app.add_systems( - Startup, - (initialize_camera, load_models).run_if(in_state(GameState::Loading)), - ) - .add_systems( - Update, - ( - initialize_board.run_if(resource_added::()), + app.add_systems(Startup, initialize_camera) + .add_systems(OnEnter(GameState::Loading), load_models) + .add_systems(OnExit(GameState::Loading), initialize_board) + .add_systems( + Update, menu::exit_to_menu.run_if(in_state(GameState::Display3d)), - ), - ) - .add_systems(OnEnter(GameState::Display3d), activate); + ) + .add_systems(Update, gizmo_system.run_if(in_state(GameState::Display3d))) + .add_systems(OnEnter(GameState::Display3d), activate) + .add_systems(OnExit(GameState::Display3d), deactivate); } } #[derive(Debug, Component)] struct Board3d; -#[derive(Debug, Resource)] -struct ModelMap; - fn initialize_camera(mut commands: Commands) { commands.spawn(( Camera3dBundle { camera: Camera { is_active: false, + hdr: true, ..default() }, + transform: Transform::from_xyz(0., 1.5, 6.).looking_at(Vec3::ZERO, Vec3::Y), ..default() }, UiCameraConfig { show_ui: true }, )); + // light + commands.spawn(PointLightBundle { + point_light: PointLight { + intensity: 1500.0, + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }); } -fn load_models(server: Res, mut commands: Commands) { - warn!("TODO: Load models"); +#[derive(Debug, Resource)] +struct ModelsFile { + handle: Handle, +} - commands.insert_resource(ModelMap); +/// Load 3d models +/// This is kind of pulling double duty. +/// Both loads the GLTF file _and_ populates the ModelMap once that is loaded. +fn load_models(server: Res, mut commands: Commands) { + commands.insert_resource(ModelsFile { + handle: server.load("models/Martian Chess.glb"), + }); } -fn initialize_board(mut commands: Commands, model_map: Option>) { - if let Some(models) = model_map { - warn!("TODO: Intialize 3D Board!"); +/// Initialize the 3d board +fn initialize_board( + mut commands: Commands, + model_file: Option>, + gltfs: Res>, +) { + info!("Initializing board"); + if let Some(mf) = model_file { + let gltf = gltfs.get(&mf.handle).expect("Load GLTF content"); - commands.spawn(( - SpatialBundle { - visibility: Visibility::Hidden, - ..default() - }, - Board3d, - )); + info!("Initializing root"); + commands + .spawn(( + SpatialBundle { + visibility: Visibility::Hidden, + ..default() + }, + Board3d, + )) + .with_children(|parent| { + info!("Initializing 3D lights!"); + parent.spawn(( + Board3d, + PointLightBundle { + point_light: PointLight { + intensity: 1500.0, + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }, + )); + + info!("Intializeing 3D Board!"); + parent.spawn(( + Board3d, + SceneBundle { + scene: gltf + .named_scenes + .get("Gameboard") + .expect("Game board model") + .clone(), + ..default() + }, + )); + }); } } +/// Make this the active state fn activate( mut cameras: Query<&mut Camera, With>, mut boards: Query<&mut Visibility, With>, ) { cameras.iter_mut().for_each(|mut camera| { + info!("Activating 3d camera"); camera.is_active = true; }); boards.iter_mut().for_each(|mut visibility| { + info!("Making entities visible"); *visibility = Visibility::Visible; }); } + +/// Make this the non-active state +fn deactivate( + mut cameras: Query<&mut Camera, With>, + mut boards: Query<&mut Visibility, With>, +) { + cameras.iter_mut().for_each(|mut camera| { + info!("Deactivating 3d camera"); + camera.is_active = false; + }); + boards.iter_mut().for_each(|mut visibility| { + info!("Making entities visible"); + *visibility = Visibility::Hidden; + }); +} + +fn gizmo_system(mut gizmos: Gizmos) { + gizmos.cuboid( + Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.)), + Color::WHITE, + ); +} diff --git a/src/game.rs b/src/game.rs index d906391..371c7be 100644 --- a/src/game.rs +++ b/src/game.rs @@ -114,7 +114,6 @@ impl Board { impl std::fmt::Display for Board { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { - let _ = write!(f, "\n"); self.inner.iter().rev().for_each(|row| { let _ = write!(f, "+--+--+--+--+--+--+--+--+\n"); let _ = write!(f, "|"); @@ -126,7 +125,7 @@ impl std::fmt::Display for Board { }); let _ = write!(f, "\n"); }); - let _ = write!(f, "+--+--+--+--+--+--+--+--+\n"); + let _ = write!(f, "+--+--+--+--+--+--+--+--+"); Ok(()) } } diff --git a/src/main.rs b/src/main.rs index 3e7a40e..77730a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,7 +9,8 @@ mod prelude; use std::time::Duration; use bevy::{ - asset::ChangeWatcher, + asset::{ChangeWatcher, HandleId}, + gltf::{GltfMesh, GltfNode}, input::{keyboard::KeyboardInput, ButtonState}, }; @@ -65,13 +66,35 @@ pub enum GameState { fn loading( server: Res, sprites: Res>, + gltfs: Res>, mut next_state: ResMut>, ) { - let items = { sprites.ids() }; - let states = server.get_group_load_state(items); - match states { - LoadState::Loaded | LoadState::NotLoaded => next_state.set(GameState::Menu), - _ => (), + let s_ids = sprites + .ids() + .filter(|&id| matches!(id, HandleId::AssetPathId(_))) + .collect::>(); + + let g_ids = gltfs + .ids() + .filter(|&id| matches!(id, HandleId::AssetPathId(_))) + .collect::>(); + + info!( + "Sprite len: {:?} | GLTF len: {:?}", + s_ids.len(), + g_ids.len() + ); + + if s_ids.len() > 0 && g_ids.len() > 0 { + let s_ready = s_ids + .iter() + .all(|&id| server.get_load_state(id) == LoadState::Loaded); + let g_ready = g_ids + .iter() + .all(|&id| server.get_load_state(id) == LoadState::Loaded); + if s_ready && g_ready { + next_state.set(GameState::Menu) + } } } diff --git a/src/menu.rs b/src/menu.rs index c2205e5..484f05c 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -156,7 +156,7 @@ fn handle_menu_start( events .iter() .filter(|&interaction| *interaction == Interaction::Pressed) - .for_each(|_| next_state.set(GameState::Display2d)) + .for_each(|_| next_state.set(GameState::Display3d)) } fn handle_menu_quit(