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.
main
Elijah C. Voigt 1 year ago
parent 665691d000
commit fcf89e91fc

@ -225,7 +225,6 @@ drone_blue = "DroneBlue"
pawn_blue = "PawnBlue" pawn_blue = "PawnBlue"
board = "Gameboard" board = "Gameboard"
valid_move = "Valid Move Static" valid_move = "Valid Move Static"
title = "Title"
[title] [title]
image = "images/title.png" image = "images/title.png"

@ -90,17 +90,23 @@ impl Plugin for Display3dPlugin {
.run_if(resource_exists::<tweak::GameTweaks>) .run_if(resource_exists::<tweak::GameTweaks>)
.run_if(in_state(GameState::Play)) .run_if(in_state(GameState::Play))
.run_if( .run_if(
any_component_changed::<Piece>() any_component_added::<Piece>()
.or_else(any_component_changed::<Piece>())
.or_else(any_component_added::<Side>())
.or_else(any_component_changed::<Side>()) .or_else(any_component_changed::<Side>())
.or_else(any_component_added::<BoardIndex>())
.or_else(any_component_changed::<BoardIndex>()) .or_else(any_component_changed::<BoardIndex>())
.or_else(any_component_added::<Animating>())
.or_else(any_component_removed::<Animating>()) .or_else(any_component_removed::<Animating>())
.or_else(any_component_removed::<Captured>()) .or_else(any_component_removed::<Captured>())
.or_else(any_component_removed::<Promoted>()), .or_else(any_component_removed::<Promoted>())
),
set_models
.run_if(resource_exists::<tweak::GameTweaks>)
.run_if(
any_component_changed::<DisplayModel>()
.or_else(any_component_added::<DisplayModel>())
.or_else(any_component_removed::<Animating>())
), ),
set_board_model.run_if(any_component_added::<game::BoardComponent>()),
set_valid_move_model.run_if(any_component_added::<game::ValidMove>()),
set_tile_hitbox.run_if(any_component_added::<game::Tile>()),
dissolve_animation.run_if(any_with_component::<Dissolving>), dissolve_animation.run_if(any_with_component::<Dissolving>),
capture_piece_start.run_if(any_component_added::<game::BeingCaptured>()), capture_piece_start.run_if(any_component_added::<game::BeingCaptured>()),
capture_piece_end.run_if(any_component_removed::<Dissolving>()), capture_piece_end.run_if(any_component_removed::<Dissolving>()),
@ -142,7 +148,8 @@ impl Plugin for Display3dPlugin {
color_grading_tweak.run_if(resource_exists::<tweak::GameTweaks>), color_grading_tweak.run_if(resource_exists::<tweak::GameTweaks>),
fog_tweak.run_if(resource_exists::<tweak::GameTweaks>), fog_tweak.run_if(resource_exists::<tweak::GameTweaks>),
bloom_tweak.run_if(resource_exists::<tweak::GameTweaks>), bloom_tweak.run_if(resource_exists::<tweak::GameTweaks>),
update_pieces.run_if(resource_exists::<tweak::GameTweaks>), set_models.run_if(resource_exists::<tweak::GameTweaks>),
update_pieces.run_if(resource_exists::<tweak::GameTweaks>).after(set_models),
), ),
) )
.add_systems( .add_systems(
@ -303,6 +310,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
Display3d, Display3d,
DisplayState::Display3d, DisplayState::Display3d,
game::BoardComponent, game::BoardComponent,
DisplayModel("display3d_models_scenes_board"),
SceneBundle { SceneBundle {
visibility: Visibility::Hidden, visibility: Visibility::Hidden,
..default() ..default()
@ -326,6 +334,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
mesh: assets.hitbox_shape.clone(), mesh: assets.hitbox_shape.clone(),
material: assets.hitbox_material.clone(), material: assets.hitbox_material.clone(),
visibility: Visibility::Hidden, visibility: Visibility::Hidden,
transform: Transform::from_translation(board_translation(&index)),
..default() ..default()
}, },
side, side,
@ -340,6 +349,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
parent.spawn(( parent.spawn((
DisplayState::Display3d, DisplayState::Display3d,
Display3d, Display3d,
DisplayModel("display3d_models_scenes_valid_move"),
index, index,
SceneBundle { SceneBundle {
visibility: Visibility::Hidden, visibility: Visibility::Hidden,
@ -372,6 +382,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
transform, transform,
..default() ..default()
}, },
DisplayModel(game::piece_model_key(*piece, side)),
game::Selectable, game::Selectable,
Dissolvable { Dissolvable {
start: 1.0, start: 1.0,
@ -528,32 +539,36 @@ fn fix_skybox(
} }
} }
fn set_board_model( #[derive(Debug, Component)]
mut boards: Query<&mut Handle<Scene>, (Added<game::BoardComponent>, With<Display3d>)>, struct DisplayModel(&'static str);
fn set_models(
mut query: Query<(Entity, &mut Handle<Scene>, &DisplayModel)>,
children: Query<&Children>,
active_animation_players: Query<&AnimationPlayer, With<Animating>>,
gltfs: Res<Assets<Gltf>>, gltfs: Res<Assets<Gltf>>,
tweaks: Res<Assets<Tweaks>>, tweaks: Res<Assets<Tweaks>>,
tweaks_file: Res<tweak::GameTweaks>, tweaks_file: Res<tweak::GameTweaks>,
) { ) {
let tweak = tweaks let tweak = tweaks.get(tweaks_file.handle.clone()).expect("Load tweakfile");
.get(tweaks_file.handle.clone()) let assets_handle = tweak.get_handle::<Gltf>("display3d_models_assets_file").unwrap();
.expect("Load tweakfile");
boards.iter_mut().for_each(|mut handle| {
debug!("Setting board model");
let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
let gltf = gltfs.get(assets_handle).expect("Load GLTF content"); let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
*handle = gltf
.named_scenes query.iter_mut().for_each(|(entity, mut handle, DisplayModel(key))| {
.get( // Check if any children are animating
tweak if active_animation_players
.get::<String>("display3d_models_scenes_board") .iter_many(children.iter_descendants(entity))
.unwrap() .count() > 0 {
.as_str(), info!("Piece {:?} is animating. Skipping...", entity);
) } else {
.expect("Game board model") let scene = tweak.get::<String>(key).unwrap();
.clone(); 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 /// 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 // Essentially we iterate over every piece and set the appropriate model and texture
fn update_pieces( fn update_pieces(
mut query: Query<( mut query: Query<(
Entity,
&Piece,
&Side,
&BoardIndex, &BoardIndex,
&mut Transform, &mut Transform,
&mut Handle<Scene>, &mut DisplayModel,
&Side,
&Piece,
)>, )>,
children: Query<&Children>,
active_animation_players: Query<&AnimationPlayer, With<Animating>>,
gltfs: Res<Assets<Gltf>>,
tweaks: Res<Assets<Tweaks>>,
tweaks_file: Res<tweak::GameTweaks>,
) { ) {
let tweak = tweaks
.get(tweaks_file.handle.clone())
.expect("Load tweakfile");
let assets_handle = tweak
.get_handle::<Gltf>("display3d_models_assets_file")
.unwrap();
let models = gltfs.get(assets_handle).unwrap();
query.iter_mut().for_each( 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 // Set position of piece
let new_translation = board_translation(board_index); let new_translation = board_translation(board_index);
if transform.translation != new_translation { if transform.translation != new_translation {
@ -667,34 +668,9 @@ fn update_pieces(
transform.translation = new_translation; transform.translation = new_translation;
} }
// Check if any children are animating let key = game::piece_model_key(*piece, *side);
let animating = active_animation_players if display_model.0 != key {
.iter_many(children.iter_descendants(entity)) *display_model = DisplayModel(key);
.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<String> = 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();
}
} }
}, },
); );
@ -823,41 +799,6 @@ fn moves_gizmo(
}); });
} }
fn set_valid_move_model(
mut events: Query<
(&mut Handle<Scene>, &mut Visibility),
(With<Display3d>, Added<game::ValidMove>),
>,
gltfs: Res<Assets<Gltf>>,
tweaks: Res<Assets<Tweaks>>,
tweaks_file: Res<tweak::GameTweaks>,
) {
let tweak = tweaks
.get(tweaks_file.handle.clone())
.expect("Load tweakfile");
let assets_handle = tweak
.get_handle::<Gltf>("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::<String>("display3d_models_scenes_valid_move")
.unwrap()
.as_str(),
)
.unwrap()
.clone();
*visibility = Visibility::Hidden;
})
}
}
fn pick_up( fn pick_up(
mut events: Query< mut events: Query<
(Entity, &game::Piece), (Entity, &game::Piece),
@ -1002,16 +943,6 @@ fn put_down(
}) })
} }
fn set_tile_hitbox(
mut events: Query<(&mut Transform, &BoardIndex), (With<Display3d>, Added<game::Tile>)>,
) {
events.iter_mut().for_each(|(mut transform, index)| {
debug!("Setting tile hitbox");
*transform = Transform::from_translation(board_translation(index));
});
}
fn opening_animation( fn opening_animation(
mut players: Query<&mut AnimationPlayer, (With<Camera>, With<Display3d>)>, mut players: Query<&mut AnimationPlayer, (With<Camera>, With<Display3d>)>,
mut query: Query<(Entity, &Dissolvable), Or<(With<BoardComponent>, With<Piece>)>>, mut query: Query<(Entity, &Dissolvable), Or<(With<BoardComponent>, With<Piece>)>>,

@ -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)] #[derive(Debug, Component, Clone, PartialEq)]
pub(crate) enum Tile { pub(crate) enum Tile {
Dark, Dark,

@ -16,7 +16,10 @@ impl Plugin for TutorialPlugin {
Update, Update,
( (
// Evaluate if a piece is selected // 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 // A piece changes sides
any_component_changed::<game::Side>() any_component_changed::<game::Side>()
// When a piece is selected, we // When a piece is selected, we
@ -291,6 +294,8 @@ fn initialize_tutorial(
margin: UiRect::all(Val::Px(5.0)), margin: UiRect::all(Val::Px(5.0)),
align_content: AlignContent::Center, align_content: AlignContent::Center,
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
justify_items: JustifyItems::Center,
..default() ..default()
}, },
image: UiImage { image: UiImage {
@ -304,13 +309,57 @@ fn initialize_tutorial(
parent.spawn(TextBundle { parent.spawn(TextBundle {
text: Text { text: Text {
sections: vec![TextSection { sections: vec![TextSection {
value: "New Game".into(), value: "New".into(),
style: TextStyle { style: TextStyle {
color: Color::WHITE, color: Color::WHITE,
font_size: 10.0, font_size: 10.0,
font: font_handle.clone(), 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() ..default()
}, },
style: Style { style: Style {
@ -331,6 +380,8 @@ fn initialize_tutorial(
margin: UiRect::all(Val::Px(5.0)), margin: UiRect::all(Val::Px(5.0)),
align_content: AlignContent::Center, align_content: AlignContent::Center,
justify_content: JustifyContent::Center, justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
justify_items: JustifyItems::Center,
..default() ..default()
}, },
image: UiImage { image: UiImage {
@ -351,6 +402,7 @@ fn initialize_tutorial(
font: font_handle.clone(), font: font_handle.clone(),
}, },
}], }],
justify: JustifyText::Center,
..default() ..default()
}, },
style: Style { style: Style {
@ -380,13 +432,13 @@ fn step(
mut next_state: ResMut<NextState<TutorialState>>, mut next_state: ResMut<NextState<TutorialState>>,
mut seen: ResMut<SeenStates>, mut seen: ResMut<SeenStates>,
) { ) {
info!("Evalute tutorial state"); debug!("Evalute tutorial state");
// Store the current state // Store the current state
// Used to avoid doing a prevoius state again // Used to avoid doing a prevoius state again
seen.0.insert(curr_state.get().clone()); 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() { match curr_state.get() {
// None does not go to Intro, that is controlled by the button handler // None does not go to Intro, that is controlled by the button handler

Loading…
Cancel
Save