From fcf89e91fca3a6aa5c3166d0d8bda7fee0b7d531 Mon Sep 17 00:00:00 2001 From: "Elijah C. Voigt" Date: Sun, 19 May 2024 13:16:55 -0700 Subject: [PATCH] Generalized 3D model management This as it turned out was not as much of a win as I would have liked, especially now that the title is an image instead of a model. But it is still nice to have a more ECS-centric way of managing models. --- assets/martian.tweak.toml | 1 - src/display3d.rs | 171 ++++++++++++-------------------------- src/game.rs | 11 +++ src/tutorial.rs | 60 ++++++++++++- 4 files changed, 118 insertions(+), 125 deletions(-) diff --git a/assets/martian.tweak.toml b/assets/martian.tweak.toml index 69da32f..da8cba5 100644 --- a/assets/martian.tweak.toml +++ b/assets/martian.tweak.toml @@ -225,7 +225,6 @@ drone_blue = "DroneBlue" pawn_blue = "PawnBlue" board = "Gameboard" valid_move = "Valid Move Static" -title = "Title" [title] image = "images/title.png" diff --git a/src/display3d.rs b/src/display3d.rs index 9b069e7..64836ad 100644 --- a/src/display3d.rs +++ b/src/display3d.rs @@ -90,17 +90,23 @@ impl Plugin for Display3dPlugin { .run_if(resource_exists::) .run_if(in_state(GameState::Play)) .run_if( - any_component_changed::() + any_component_added::() + .or_else(any_component_changed::()) + .or_else(any_component_added::()) .or_else(any_component_changed::()) + .or_else(any_component_added::()) .or_else(any_component_changed::()) - .or_else(any_component_added::()) .or_else(any_component_removed::()) .or_else(any_component_removed::()) - .or_else(any_component_removed::()), + .or_else(any_component_removed::()) + ), + set_models + .run_if(resource_exists::) + .run_if( + any_component_changed::() + .or_else(any_component_added::()) + .or_else(any_component_removed::()) ), - set_board_model.run_if(any_component_added::()), - set_valid_move_model.run_if(any_component_added::()), - set_tile_hitbox.run_if(any_component_added::()), dissolve_animation.run_if(any_with_component::), capture_piece_start.run_if(any_component_added::()), capture_piece_end.run_if(any_component_removed::()), @@ -142,7 +148,8 @@ impl Plugin for Display3dPlugin { color_grading_tweak.run_if(resource_exists::), fog_tweak.run_if(resource_exists::), bloom_tweak.run_if(resource_exists::), - update_pieces.run_if(resource_exists::), + set_models.run_if(resource_exists::), + update_pieces.run_if(resource_exists::).after(set_models), ), ) .add_systems( @@ -303,6 +310,7 @@ fn initialize(mut commands: Commands, board: Res, assets: Res, assets: Res, assets: Res, assets: Res, (Added, With)>, +#[derive(Debug, Component)] +struct DisplayModel(&'static str); + +fn set_models( + mut query: Query<(Entity, &mut Handle, &DisplayModel)>, + children: Query<&Children>, + active_animation_players: Query<&AnimationPlayer, With>, gltfs: Res>, tweaks: Res>, tweaks_file: Res, ) { - let tweak = tweaks - .get(tweaks_file.handle.clone()) - .expect("Load tweakfile"); - boards.iter_mut().for_each(|mut handle| { - debug!("Setting board model"); - let assets_handle = tweak - .get_handle::("display3d_models_assets_file") - .unwrap(); - let gltf = gltfs.get(assets_handle).expect("Load GLTF content"); - *handle = gltf - .named_scenes - .get( - tweak - .get::("display3d_models_scenes_board") - .unwrap() - .as_str(), - ) - .expect("Game board model") - .clone(); - }); + let tweak = tweaks.get(tweaks_file.handle.clone()).expect("Load tweakfile"); + let assets_handle = tweak.get_handle::("display3d_models_assets_file").unwrap(); + let gltf = gltfs.get(assets_handle).expect("Load GLTF content"); + + query.iter_mut().for_each(|(entity, mut handle, DisplayModel(key))| { + // Check if any children are animating + if active_animation_players + .iter_many(children.iter_descendants(entity)) + .count() > 0 { + info!("Piece {:?} is animating. Skipping...", entity); + } else { + let scene = tweak.get::(key).unwrap(); + let new_handle = gltf.named_scenes.get(scene.as_str()).expect("Game board model"); + if *new_handle != *handle { + info!("Updating piece for {:?}", entity); + *handle = new_handle.clone(); + } + } + }) } /// Given a board index returns the Vec3 location in space @@ -637,29 +652,15 @@ fn mouse_zoom( // Essentially we iterate over every piece and set the appropriate model and texture fn update_pieces( mut query: Query<( - Entity, - &Piece, - &Side, &BoardIndex, &mut Transform, - &mut Handle, + &mut DisplayModel, + &Side, + &Piece, )>, - children: Query<&Children>, - active_animation_players: Query<&AnimationPlayer, With>, - gltfs: Res>, - tweaks: Res>, - tweaks_file: Res, ) { - let tweak = tweaks - .get(tweaks_file.handle.clone()) - .expect("Load tweakfile"); - let assets_handle = tweak - .get_handle::("display3d_models_assets_file") - .unwrap(); - let models = gltfs.get(assets_handle).unwrap(); - query.iter_mut().for_each( - |(entity, piece, side, board_index, mut transform, mut scene)| { + |(board_index, mut transform, mut display_model, side, piece)| { // Set position of piece let new_translation = board_translation(board_index); if transform.translation != new_translation { @@ -667,34 +668,9 @@ fn update_pieces( transform.translation = new_translation; } - // Check if any children are animating - let animating = active_animation_players - .iter_many(children.iter_descendants(entity)) - .count(); - - if animating > 0 { - debug!("Piece {:?} is animating. Skipping...", entity); - } else { - debug!("Checking piece object scene for {:?}", entity); - - // Find name of this piece's model scene - let scene_tweak_name: Option = match (piece, side) { - (Piece::Pawn, Side::A) => tweak.get("display3d_models_scenes_pawn_red"), - (Piece::Pawn, Side::B) => tweak.get("display3d_models_scenes_pawn_blue"), - (Piece::Drone, Side::A) => tweak.get("display3d_models_scenes_drone_red"), - (Piece::Drone, Side::B) => tweak.get("display3d_models_scenes_drone_blue"), - (Piece::Queen, Side::A) => tweak.get("display3d_models_scenes_queen_red"), - (Piece::Queen, Side::B) => tweak.get("display3d_models_scenes_queen_blue"), - }; - - // Get model scene for this piece - let scene_handle = models.named_scenes.get(&scene_tweak_name.unwrap()).unwrap(); - - // Set scene model for this piece - if *scene != *scene_handle { - warn!("Updating scene for piece {:?}", entity); - *scene = scene_handle.clone(); - } + let key = game::piece_model_key(*piece, *side); + if display_model.0 != key { + *display_model = DisplayModel(key); } }, ); @@ -823,41 +799,6 @@ fn moves_gizmo( }); } -fn set_valid_move_model( - mut events: Query< - (&mut Handle, &mut Visibility), - (With, Added), - >, - gltfs: Res>, - tweaks: Res>, - tweaks_file: Res, -) { - let tweak = tweaks - .get(tweaks_file.handle.clone()) - .expect("Load tweakfile"); - let assets_handle = tweak - .get_handle::("display3d_models_assets_file") - .unwrap(); - if let Some(gltf) = gltfs.get(assets_handle) { - debug!("Setting valid move model"); - - events.iter_mut().for_each(|(mut handle, mut visibility)| { - *handle = gltf - .named_scenes - .get( - tweak - .get::("display3d_models_scenes_valid_move") - .unwrap() - .as_str(), - ) - .unwrap() - .clone(); - - *visibility = Visibility::Hidden; - }) - } -} - fn pick_up( mut events: Query< (Entity, &game::Piece), @@ -1002,16 +943,6 @@ fn put_down( }) } -fn set_tile_hitbox( - mut events: Query<(&mut Transform, &BoardIndex), (With, Added)>, -) { - events.iter_mut().for_each(|(mut transform, index)| { - debug!("Setting tile hitbox"); - - *transform = Transform::from_translation(board_translation(index)); - }); -} - fn opening_animation( mut players: Query<&mut AnimationPlayer, (With, With)>, mut query: Query<(Entity, &Dissolvable), Or<(With, With)>>, diff --git a/src/game.rs b/src/game.rs index cf7528a..64a0dc7 100644 --- a/src/game.rs +++ b/src/game.rs @@ -141,6 +141,17 @@ impl Piece { } } +pub(crate) fn piece_model_key(piece: Piece, side: Side) -> &'static str { + match (piece, side) { + (Piece::Pawn, Side::A) => "display3d_models_scenes_pawn_red", + (Piece::Pawn, Side::B) => "display3d_models_scenes_pawn_blue", + (Piece::Drone, Side::A) => "display3d_models_scenes_drone_red", + (Piece::Drone, Side::B) => "display3d_models_scenes_drone_blue", + (Piece::Queen, Side::A) => "display3d_models_scenes_queen_red", + (Piece::Queen, Side::B) => "display3d_models_scenes_queen_blue", + } +} + #[derive(Debug, Component, Clone, PartialEq)] pub(crate) enum Tile { Dark, diff --git a/src/tutorial.rs b/src/tutorial.rs index bd46f6f..474a911 100644 --- a/src/tutorial.rs +++ b/src/tutorial.rs @@ -16,7 +16,10 @@ impl Plugin for TutorialPlugin { Update, ( // Evaluate if a piece is selected - step.run_if( + step + // tutorial must be running + .run_if(not(in_state(TutorialState::None))) + .run_if( // A piece changes sides any_component_changed::() // When a piece is selected, we @@ -291,6 +294,8 @@ fn initialize_tutorial( margin: UiRect::all(Val::Px(5.0)), align_content: AlignContent::Center, justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + justify_items: JustifyItems::Center, ..default() }, image: UiImage { @@ -304,13 +309,57 @@ fn initialize_tutorial( parent.spawn(TextBundle { text: Text { sections: vec![TextSection { - value: "New Game".into(), + value: "New".into(), style: TextStyle { color: Color::WHITE, font_size: 10.0, font: font_handle.clone(), }, }], + justify: JustifyText::Center, + ..default() + }, + style: Style { + margin: UiRect::all(Val::Px(10.0)), + ..default() + }, + ..default() + }); + }); + + parent + .spawn(( + menu::ButtonAction(tutorial::TutorialState::None), + menu::ButtonAction(GameState::Play), + menu::ButtonAction(menu::MenuState::Off), + ButtonBundle { + style: Style { + margin: UiRect::all(Val::Px(5.0)), + align_content: AlignContent::Center, + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + justify_items: JustifyItems::Center, + ..default() + }, + image: UiImage { + texture: button_handle.clone(), + ..default() + }, + ..default() + }, + )) + .with_children(|parent| { + parent.spawn(TextBundle { + text: Text { + sections: vec![TextSection { + value: "Continue".into(), + style: TextStyle { + color: Color::WHITE, + font_size: 10.0, + font: font_handle.clone(), + }, + }], + justify: JustifyText::Center, ..default() }, style: Style { @@ -331,6 +380,8 @@ fn initialize_tutorial( margin: UiRect::all(Val::Px(5.0)), align_content: AlignContent::Center, justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + justify_items: JustifyItems::Center, ..default() }, image: UiImage { @@ -351,6 +402,7 @@ fn initialize_tutorial( font: font_handle.clone(), }, }], + justify: JustifyText::Center, ..default() }, style: Style { @@ -380,13 +432,13 @@ fn step( mut next_state: ResMut>, mut seen: ResMut, ) { - info!("Evalute tutorial state"); + debug!("Evalute tutorial state"); // Store the current state // Used to avoid doing a prevoius state again seen.0.insert(curr_state.get().clone()); - info!("Curr: {:?}, Seen: {:?}", curr_state.get(), seen); + debug!("Curr: {:?}, Seen: {:?}", curr_state.get(), seen); match curr_state.get() { // None does not go to Intro, that is controlled by the button handler