loading animations rework is good

main
Elijah Voigt 2 years ago
parent 04befe5ab0
commit a6cc91aacc

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

Loading…
Cancel
Save