loading animations rework is good

main
Elijah Voigt 2 years ago
parent 04befe5ab0
commit a6cc91aacc

@ -7,12 +7,13 @@
// * Multi-GLTF UX is bad. // * Multi-GLTF UX is bad.
// * Consider GLTF hierarchy (GLTF1 > Scene1a/Scene1b, GlTF2 > Scene2a/Scene2b, etc) // * Consider GLTF hierarchy (GLTF1 > Scene1a/Scene1b, GlTF2 > Scene2a/Scene2b, etc)
// * Easy despawn when de-selecting gltf // * Easy despawn when de-selecting gltf
// * Load new GLTF -> Despawn all level entities
// //
// TODO: // TODO:
// * Disable auto start/load // * Disable auto start/load
// * Make GLTF nested menu
// * Better handle hide/close monologue // * Better handle hide/close monologue
// * (hard) Harden Active Camera // * (hard) Harden Active Camera
// * (medium) Despawn entire scene when GLTF changed?
// * (medium) Select Font -> "Default Font" Resource // * (medium) Select Font -> "Default Font" Resource
// * (medium) Pre-compute animation target entities // * (medium) Pre-compute animation target entities
// * (medium) Animation buttons only visible when playable // * (medium) Animation buttons only visible when playable
@ -76,16 +77,16 @@ fn main() {
.add_systems( .add_systems(
Update, Update,
( (
manage_gltf_animation_ui,
init_animations_ui, init_animations_ui,
animations_ui, remove_animations_ui,
add_animations_ui,
play_all_animations, play_all_animations,
play_animation, play_animation,
), ),
) )
.add_systems( .add_systems(
Update, Update,
(manage_gltf_scene_ui, scenes_ui, control_active_scenes), (remove_scenes_ui, add_scenes_ui, control_active_scenes),
) )
.add_systems( .add_systems(
Update, Update,
@ -640,103 +641,6 @@ mod gltf {
} }
}); });
} }
pub fn manage_gltf_animation_ui(
added: Query<Entity, (With<Button>, Added<ui::Active>)>,
mut removed: RemovedComponents<ui::Active>,
targets_gltf: Query<&ui::TargetAsset<Gltf>>,
gltfs: Res<Assets<Gltf>>,
mut animation_clip_events: EventWriter<CustomAssetEvent<AnimationClip>>,
) {
removed
.iter()
.filter_map(|entity| {
if let Ok(ui::TargetAsset { handle }) = targets_gltf.get(entity) {
gltfs.get(handle)
} else {
None
}
})
.for_each(|gltf| {
gltf.named_animations
.iter()
.for_each(|(animation_name, animation_handle)| {
info!("Named animation: {:?}", animation_name);
animation_clip_events.send(CustomAssetEvent::Remove {
handle: animation_handle.clone(),
});
});
});
added
.iter()
.filter_map(|entity| {
if let Ok(ui::TargetAsset { handle }) = targets_gltf.get(entity) {
gltfs.get(handle)
} else {
None
}
})
.for_each(|gltf| {
// Populate animations tab
gltf.named_animations
.iter()
.for_each(|(animation_name, animation_handle)| {
animation_clip_events.send(CustomAssetEvent::Add {
name: animation_name.clone(),
handle: animation_handle.clone(),
})
});
});
}
pub fn manage_gltf_scene_ui(
added: Query<Entity, (With<Button>, Added<ui::Active>)>,
mut removed: RemovedComponents<ui::Active>,
targets_gltf: Query<&ui::TargetAsset<Gltf>>,
gltfs: Res<Assets<Gltf>>,
mut scene_events: EventWriter<CustomAssetEvent<Scene>>,
) {
removed
.iter()
.filter_map(|entity| {
if let Ok(ui::TargetAsset { handle }) = targets_gltf.get(entity) {
gltfs.get(handle)
} else {
None
}
})
.for_each(|gltf| {
gltf.named_scenes
.iter()
.for_each(|(scene_name, scene_handle)| {
info!("Named scene: {:?}", scene_name);
scene_events.send(CustomAssetEvent::Remove {
handle: scene_handle.clone(),
});
});
});
added
.iter()
.filter_map(|entity| {
if let Ok(ui::TargetAsset { handle }) = targets_gltf.get(entity) {
gltfs.get(handle)
} else {
None
}
})
.for_each(|gltf| {
// Populate scenes tab
gltf.named_scenes
.iter()
.for_each(|(scene_name, scene_handle)| {
info!("Named scene: {:?}", scene_name);
scene_events.send(CustomAssetEvent::Add {
name: scene_name.clone(),
handle: scene_handle.clone(),
})
})
});
}
} }
// TODO: Mark loaded animation as active // TODO: Mark loaded animation as active
@ -747,18 +651,16 @@ mod scenes {
#[derive(Debug, Component, Default)] #[derive(Debug, Component, Default)]
pub struct SceneWidget; pub struct SceneWidget;
pub fn scenes_ui( pub fn add_scenes_ui(
mut events: EventReader<CustomAssetEvent<Scene>>, gltf_selected: Query<&ui::TargetAsset<Gltf>, Added<ui::Active>>,
mut commands: Commands, mut commands: Commands,
gltfs: Res<Assets<Gltf>>,
widget: Query<Entity, With<SceneWidget>>, widget: Query<Entity, With<SceneWidget>>,
current: Query<(Entity, &ui::TargetAsset<Scene>)>,
) { ) {
events.iter().for_each(|event| { gltf_selected.iter().for_each(|ui::TargetAsset { handle }| {
match event { if let Some(gltf) = gltfs.get(&handle.clone()) {
CustomAssetEvent::Add { name, handle } => { gltf.named_scenes.iter().for_each(|(name, handle)| {
info!("Asset loading! {:?}({:?})", name, handle); create_asset_button(
// Spawn new tree
let e = create_asset_button(
&widget, &widget,
&mut commands, &mut commands,
ui::TargetAsset { ui::TargetAsset {
@ -767,8 +669,24 @@ mod scenes {
name.clone(), name.clone(),
None, None,
); );
})
}
});
} }
CustomAssetEvent::Remove { handle } => {
pub fn remove_scenes_ui(
mut gltf_unselected: RemovedComponents<ui::Active>,
target_assets: Query<&ui::TargetAsset<Gltf>>,
current: Query<(Entity, &ui::TargetAsset<Scene>)>,
gltfs: Res<Assets<Gltf>>,
mut commands: Commands,
) {
gltf_unselected
.iter()
.filter_map(|entity| target_assets.get(entity).ok())
.filter_map(|ui::TargetAsset { handle }| gltfs.get(handle))
.for_each(|gltf| {
gltf.scenes.iter().for_each(|handle| {
destroy_asset_button( destroy_asset_button(
&current, &current,
&mut commands, &mut commands,
@ -776,11 +694,7 @@ mod scenes {
handle: handle.clone(), handle: handle.clone(),
}, },
); );
} });
CustomAssetEvent::Clear => {
commands.entity(widget.single()).despawn_descendants();
}
}
}); });
} }
@ -862,28 +776,57 @@ mod animations {
}) })
} }
pub fn animations_ui( /// When a new scene is loaded, add any newly compatible animations
mut events: EventReader<CustomAssetEvent<AnimationClip>>, pub fn add_animations_ui(
mut commands: Commands, player_spawned: Query<&Name, Added<AnimationPlayer>>,
widget: Query<Entity, With<AnimationWidget>>, widget: Query<Entity, With<AnimationWidget>>,
current: Query<(Entity, &ui::TargetAsset<AnimationClip>)>, gltfs: Res<Assets<Gltf>>,
mut commands: Commands,
clips: Res<Assets<AnimationClip>>,
) { ) {
events.iter().for_each(|event| { player_spawned.iter().for_each(|player_name| {
match event { gltfs.iter().for_each(|(_, gltf)| {
CustomAssetEvent::Add { name, handle } => { gltf.named_animations
info!("Asset loading! {:?}({:?})", name, handle); .iter()
// Spawn new tree .for_each(|(clip_name, handle)| {
info!("Checking clip {:?}", clip_name);
let clip = clips.get(&handle).expect("load animation clip");
clip.compatible_with(player_name).then(|| {
create_asset_button( create_asset_button(
&widget, &widget,
&mut commands, &mut commands,
ui::TargetAsset { ui::TargetAsset {
handle: handle.clone(), handle: handle.clone(),
}, },
name.clone(), clip_name.clone(),
None, None,
); );
});
});
});
});
} }
CustomAssetEvent::Remove { handle } => {
// When a scene is de-selected, remove any outdated animation options
pub fn remove_animations_ui(
mut events: RemovedComponents<Handle<Scene>>,
current: Query<(Entity, &ui::TargetAsset<AnimationClip>)>,
clips: Res<Assets<AnimationClip>>,
targets: Query<(&AnimationPlayer, &Name)>,
mut commands: Commands,
) {
// For each removed scene
events.iter().for_each(|_| {
info!("Scene despawn!");
// Iterate over the current animation buttons
current.iter().for_each(|(_, ui::TargetAsset { handle })| {
info!("Checking button for {:?}", handle);
// If the button points to a valid clip
if let Some(clip) = clips.get(handle) {
// Check if any active animation players are compatible with this clip
let compatible = targets.iter().any(|(_, name)| clip.compatible_with(name));
// If not, despawn the button
if !compatible {
destroy_asset_button( destroy_asset_button(
&current, &current,
&mut commands, &mut commands,
@ -892,11 +835,9 @@ mod animations {
}, },
); );
} }
CustomAssetEvent::Clear => {
commands.entity(widget.single()).despawn_descendants();
}
} }
}); });
});
} }
pub fn play_all_animations( pub fn play_all_animations(
@ -1082,7 +1023,6 @@ mod monologues {
)); ));
} }
// TODO: Load .txt files for monologues
pub fn texts_ui( pub fn texts_ui(
mut events: EventReader<AssetEvent<Monologue>>, mut events: EventReader<AssetEvent<Monologue>>,
mut commands: Commands, mut commands: Commands,
@ -1215,7 +1155,6 @@ mod cameras {
#[derive(Debug, Component, Default)] #[derive(Debug, Component, Default)]
pub struct CameraWidget; pub struct CameraWidget;
// TODO: Despawn camera button when camera removed
pub fn cameras_ui( pub fn cameras_ui(
mut added: Query<(Entity, &mut Camera, &Name), (Added<Camera>, Without<EditorCamera>)>, mut added: Query<(Entity, &mut Camera, &Name), (Added<Camera>, Without<EditorCamera>)>,
mut removed: RemovedComponents<Camera>, mut removed: RemovedComponents<Camera>,
@ -1229,7 +1168,7 @@ mod cameras {
}); });
added.iter_mut().for_each(|(entity, mut camera, name)| { added.iter_mut().for_each(|(entity, mut camera, name)| {
info!("Camera added {:?} {:?}", entity, name); info!("Camera added {:?} {:?}", entity, name);
let e = create_entity_button( create_entity_button(
&widget, &widget,
&mut commands, &mut commands,
ui::TargetEntity { entity }, ui::TargetEntity { entity },
@ -1268,13 +1207,11 @@ mod cameras {
mut cameras: Query<&mut Camera>, mut cameras: Query<&mut Camera>,
) { ) {
removed.iter().for_each(|entity| { removed.iter().for_each(|entity| {
info!("Setting {:?} to inactive camera", entity);
if let Ok(mut camera) = cameras.get_mut(entity) { if let Ok(mut camera) = cameras.get_mut(entity) {
camera.is_active = false; camera.is_active = false;
} }
}); });
added.iter().for_each(|entity| { added.iter().for_each(|entity| {
info!("Setting {:?} to active camera", entity);
if let Ok(mut camera) = cameras.get_mut(entity) { if let Ok(mut camera) = cameras.get_mut(entity) {
camera.is_active = true; camera.is_active = true;
} }

Loading…
Cancel
Save