use crate::editor::prelude::*; #[derive(Debug, Default)] pub struct EditorAnimationPlugin; impl Plugin for EditorAnimationPlugin { fn build(&self, app: &mut App) { app.add_event::() .add_systems(Update, sync_asset_buttons::) .add_systems(Update, sync_remove_asset_buttons::) .add_systems(Update, set_epoch_animations) .add_systems(Update, load_epoch_animations) .add_systems(Update, init_animations_ui) .add_systems(Update, remove_animations_ui) .add_systems(Update, add_animations_ui) .add_systems(Update, play_all_animations) .add_systems(Update, play_animation) .add_systems(Update, ui_control_animations) .add_systems(Update, ui_active_animation); } } #[derive(Debug, Component, Default)] pub struct AnimationWidget; #[derive(Debug, Component)] pub struct AnimationPlayAll; pub fn init_animations_ui(events: Query>, mut commands: Commands) { events.iter().for_each(|entity| { commands.entity(entity).with_children(|parent| { parent.spawn(( AnimationPlayAll, ButtonBundle { style: Style { border: UiRect::all(Val::Px(1.0)), margin: UiRect::all(Val::Px(1.0)), padding: UiRect::all(Val::Px(1.0)), ..default() }, border_color: Color::BLACK.into(), ..default() }, ui::Title { text: "Play All".into(), ..default() }, )); }); }) } /// When a new scene is loaded, add any newly compatible animations /// TODO: Add target entity(s) too pub fn add_animations_ui( player_spawned: Query<&Name, Added>, widget: Query>, mut commands: Commands, gltfs: Res>, clips: Res>, ) { player_spawned.iter().for_each(|player_name| { gltfs .iter() .flat_map(|(_, gltf)| gltf.named_animations.iter()) .filter_map(|(clip_name, handle)| { clips.get(&handle).map(|clip| (clip_name, handle, clip)) }) .filter(|(_, _, clip)| clip.compatible_with(player_name)) .for_each(|(clip_name, handle, _)| { create_asset_button( &widget, &mut commands, ui::TargetAsset { handle: handle.clone(), }, clip_name.clone(), None, ); }); }); } // When a scene is de-selected, remove any outdated animation options pub fn remove_animations_ui( mut removed_players: RemovedComponents>, current: Query<(Entity, &ui::TargetAsset)>, clips: Res>, targets: Query<(&AnimationPlayer, &Name)>, mut commands: Commands, ) { // For each removed scene removed_players.iter().for_each(|_| { // Iterate over the current animation buttons current .iter() .filter(|(_, ui::TargetAsset { handle })| { // Check if this clip is compatible with any remaining entities // NOTE: We are checking this is *not* compatible with any entities clips .get(handle) .map(|clip| !(targets.iter().any(|(_, name)| clip.compatible_with(name)))) .unwrap_or(true) }) .for_each(|(_, ui::TargetAsset { handle })| { // Destroy the buton if it is so destroy_asset_button( ¤t, &mut commands, &ui::TargetAsset { handle: handle.clone(), }, ); }); }); } #[derive(Debug, Event)] pub enum ControlAnimation { Play(Handle), Pause(Handle), } pub fn play_animation( mut events: EventReader, mut targets: Query<(&mut AnimationPlayer, &Name), With>, clips: Res>, ) { events.iter().for_each(|event| match event { ControlAnimation::Play(handle) => { let clip = clips.get(&handle).expect("Load animation clip"); targets .iter_mut() .filter(|(_, name)| clip.compatible_with(name)) .for_each(|(mut player, _)| { if player.is_paused() { player.resume(); } else { player.play(handle.clone()).repeat(); } }); } ControlAnimation::Pause(handle) => { let clip = clips.get(handle).expect("Load animation clip"); targets .iter_mut() .filter(|(_, name)| clip.compatible_with(name)) .for_each(|(mut player, _)| { player.pause(); }); } }); } pub fn play_all_animations( events: Query< (Entity, &Interaction, Option<&ui::Active>), (With, Changed), >, clip_btns: Query<&ui::TargetAsset>, mut writer: EventWriter, mut commands: Commands, ) { events .iter() .filter_map(|(entity, &interaction, active)| { (interaction == Interaction::Pressed).then_some((entity, active)) }) .for_each(|(entity, active)| match active { Some(_) => { commands.entity(entity).remove::(); clip_btns.iter().for_each(|ui::TargetAsset { handle }| { writer.send(ControlAnimation::Pause(handle.clone())); }); } None => { commands.entity(entity).insert(ui::Active); clip_btns.iter().for_each(|ui::TargetAsset { handle }| { writer.send(ControlAnimation::Play(handle.clone())); }); } }) } fn ui_control_animations( events: Query< ( &Interaction, &ui::TargetAsset, Option<&ui::Active>, ), (With