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"
board = "Gameboard"
valid_move = "Valid Move Static"
title = "Title"
[title]
image = "images/title.png"

@ -90,17 +90,23 @@ impl Plugin for Display3dPlugin {
.run_if(resource_exists::<tweak::GameTweaks>)
.run_if(in_state(GameState::Play))
.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_added::<BoardIndex>())
.or_else(any_component_changed::<BoardIndex>())
.or_else(any_component_added::<Animating>())
.or_else(any_component_removed::<Animating>())
.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>),
capture_piece_start.run_if(any_component_added::<game::BeingCaptured>()),
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>),
fog_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(
@ -303,6 +310,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
Display3d,
DisplayState::Display3d,
game::BoardComponent,
DisplayModel("display3d_models_scenes_board"),
SceneBundle {
visibility: Visibility::Hidden,
..default()
@ -326,6 +334,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
mesh: assets.hitbox_shape.clone(),
material: assets.hitbox_material.clone(),
visibility: Visibility::Hidden,
transform: Transform::from_translation(board_translation(&index)),
..default()
},
side,
@ -340,6 +349,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
parent.spawn((
DisplayState::Display3d,
Display3d,
DisplayModel("display3d_models_scenes_valid_move"),
index,
SceneBundle {
visibility: Visibility::Hidden,
@ -372,6 +382,7 @@ fn initialize(mut commands: Commands, board: Res<game::Board>, assets: Res<Asset
transform,
..default()
},
DisplayModel(game::piece_model_key(*piece, side)),
game::Selectable,
Dissolvable {
start: 1.0,
@ -528,32 +539,36 @@ fn fix_skybox(
}
}
fn set_board_model(
mut boards: Query<&mut Handle<Scene>, (Added<game::BoardComponent>, With<Display3d>)>,
#[derive(Debug, Component)]
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>>,
tweaks: Res<Assets<Tweaks>>,
tweaks_file: Res<tweak::GameTweaks>,
) {
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::<Gltf>("display3d_models_assets_file")
.unwrap();
let tweak = tweaks.get(tweaks_file.handle.clone()).expect("Load tweakfile");
let assets_handle = tweak.get_handle::<Gltf>("display3d_models_assets_file").unwrap();
let gltf = gltfs.get(assets_handle).expect("Load GLTF content");
*handle = gltf
.named_scenes
.get(
tweak
.get::<String>("display3d_models_scenes_board")
.unwrap()
.as_str(),
)
.expect("Game board model")
.clone();
});
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::<String>(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<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(
|(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<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();
}
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<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(
mut events: Query<
(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(
mut players: Query<&mut AnimationPlayer, (With<Camera>, With<Display3d>)>,
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)]
pub(crate) enum Tile {
Dark,

@ -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::<game::Side>()
// 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<NextState<TutorialState>>,
mut seen: ResMut<SeenStates>,
) {
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

Loading…
Cancel
Save