add deletion of keyframes

This commit is contained in:
Lee-Orr
2024-03-18 16:43:29 -04:00
parent 09a09af240
commit 4952c0c613
3 changed files with 71 additions and 30 deletions
@@ -101,6 +101,10 @@ export class AnimEditorElement extends LitElement {
keyframes[keyframe] = added[keyframe]; keyframes[keyframe] = added[keyframe];
} }
for (let keyframe of removed) {
delete keyframes[keyframe];
}
this.keyframes = keyframes; this.keyframes = keyframes;
let min = Infinity let min = Infinity
+53 -29
View File
@@ -11,14 +11,13 @@ use bevy::{
use bevy_tweening::{ use bevy_tweening::{
lens::{TransformPositionLens, TransformRotationLens, TransformScaleLens}, lens::{TransformPositionLens, TransformRotationLens, TransformScaleLens},
Animator, EaseMethod, Sequence, Targetable, Tracks, Tween, Animator, EaseMethod, Sequence, Targetable, Tracks, Tween, TweenCompleted,
TweenCompleted,
}; };
use itertools::Itertools; use itertools::Itertools;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use space_editor::space_prefab::editor_registry::EditorRegistryExt; use space_editor::space_prefab::editor_registry::EditorRegistryExt;
use crate::interaction::Selectable; use crate::interaction::{MarkedForDeletion, Selectable};
pub struct TimelinePlugin; pub struct TimelinePlugin;
@@ -53,6 +52,7 @@ impl Plugin for TimelinePlugin {
timeline_bound_component_animator_system::<Transform>, timeline_bound_component_animator_system::<Transform>,
), ),
); );
app.add_systems(PostUpdate, generate_transform_animation); app.add_systems(PostUpdate, generate_transform_animation);
@@ -77,6 +77,8 @@ impl Plugin for TimelinePlugin {
} }
} }
const MIN_KEYFRAME_DISTANCE: f32 = 0.01;
#[derive(Event, Clone, Copy, Debug)] #[derive(Event, Clone, Copy, Debug)]
pub enum TimelineInteractionEvent { pub enum TimelineInteractionEvent {
Play, Play,
@@ -88,7 +90,7 @@ pub enum TimelineInteractionEvent {
pub enum KeyframeInteractionEvent { pub enum KeyframeInteractionEvent {
RecordKeyframe { target: Entity }, RecordKeyframe { target: Entity },
MoveKeyframeTime { target: Entity, time: f32 }, MoveKeyframeTime { target: Entity, time: f32 },
AddEntityTrack { target: Entity } AddEntityTrack { target: Entity },
} }
#[derive(Resource, Clone, Copy, Debug, Default, Reflect, Serialize, Deserialize)] #[derive(Resource, Clone, Copy, Debug, Default, Reflect, Serialize, Deserialize)]
@@ -227,29 +229,50 @@ fn process_keyframe_events(
r_global_seek_time: Res<GlobalSeekTime>, r_global_seek_time: Res<GlobalSeekTime>,
q_animation_targets: Query<(Entity, &Transform), With<AnimationTarget>>, q_animation_targets: Query<(Entity, &Transform), With<AnimationTarget>>,
q_potential_targets: Query<Entity, (With<Transform>, Without<AnimationTarget>)>, q_potential_targets: Query<Entity, (With<Transform>, Without<AnimationTarget>)>,
mut q_keyframes: Query<&mut Keyframe>, mut q_keyframes: Query<(Entity, &mut Keyframe)>,
) { ) {
for event in e_timeline_event.read() { for event in e_timeline_event.read() {
info!("Processing Keyframe Event {event:?}"); info!("Processing Keyframe Event {event:?}");
match event { match event {
KeyframeInteractionEvent::RecordKeyframe { target } => { KeyframeInteractionEvent::RecordKeyframe { target } => {
if let Ok((target, transform)) = q_animation_targets.get(*target) { if let Ok((target, transform)) = q_animation_targets.get(*target) {
commands.spawn(( let mut existing = None;
SpatialBundle { for (entity, keyframe) in q_keyframes.iter_mut() {
transform: *transform, if keyframe.target == target
..Default::default() && (keyframe.time - r_global_seek_time.time).abs()
}, < MIN_KEYFRAME_DISTANCE
Selectable, {
Keyframe { existing = Some(entity);
target, break;
time: r_global_seek_time.time, }
}, }
TransformKeyframe::default(), if let Some(existing) = existing {
)); commands.entity(existing).insert((
*transform,
TransformKeyframe::default(),
Keyframe {
target,
time: r_global_seek_time.time,
},
));
} else {
commands.spawn((
SpatialBundle {
transform: *transform,
..Default::default()
},
Selectable,
Keyframe {
target,
time: r_global_seek_time.time,
},
TransformKeyframe::default(),
));
}
} }
} }
KeyframeInteractionEvent::MoveKeyframeTime { target, time } => { KeyframeInteractionEvent::MoveKeyframeTime { target, time } => {
if let Ok(mut keyframe) = q_keyframes.get_mut(*target) { if let Ok((_, mut keyframe)) = q_keyframes.get_mut(*target) {
keyframe.time = *time; keyframe.time = *time;
} }
} }
@@ -260,7 +283,7 @@ fn process_keyframe_events(
} else { } else {
warn!("Can't add animation target to entity"); warn!("Can't add animation target to entity");
} }
}, }
} }
} }
} }
@@ -268,11 +291,16 @@ fn process_keyframe_events(
fn generate_transform_animation( fn generate_transform_animation(
mut commands: Commands, mut commands: Commands,
changed: Query<&Keyframe, (With<TransformKeyframe>, Changed<Keyframe>)>, changed: Query<&Keyframe, (With<TransformKeyframe>, Changed<Keyframe>)>,
keyframes: Query<(&Keyframe, &Transform, &TransformKeyframe, Entity)>, keyframes: Query<(&Keyframe, &Transform, &TransformKeyframe, Entity), Without<MarkedForDeletion>>,
removed: Query<&Keyframe, With<MarkedForDeletion>>,
) { ) {
let changed_targets = changed let changed_targets = changed
.iter() .iter()
.map(|keyframe| keyframe.target) .map(|keyframe| keyframe.target)
.chain(removed.iter().map(|keyframe| {
info!("Processing a removed keyframe {keyframe:?}");
keyframe.target
}))
.collect::<HashSet<_>>(); .collect::<HashSet<_>>();
let keyframes = keyframes let keyframes = keyframes
.iter() .iter()
@@ -467,13 +495,11 @@ mod wasm {
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
use crate::{ use crate::{
scene::SceneElement, interaction::MarkedForDeletion, scene::SceneElement, wasm::{FromStr, StaticBuffer, WasmMessageBuffer}
wasm::{FromStr, StaticBuffer, WasmMessageBuffer},
}; };
use super::{ use super::{
AnimationTarget, EaseType, GlobalSeekTime, Keyframe, KeyframeInteractionEvent, AnimationTarget, EaseType, GlobalSeekTime, Keyframe, KeyframeInteractionEvent, TimedAnimationClipAsset, TimelineInteractionEvent, TransformKeyframe
TimedAnimationClipAsset, TimelineInteractionEvent, TransformKeyframe,
}; };
static SEEK_TIME: WasmMessageBuffer<TimelineInteractionEvent> = WasmMessageBuffer::new(); static SEEK_TIME: WasmMessageBuffer<TimelineInteractionEvent> = WasmMessageBuffer::new();
@@ -522,9 +548,7 @@ mod wasm {
let Ok(target) = Entity::from_str(&entity) else { let Ok(target) = Entity::from_str(&entity) else {
return; return;
}; };
KEYFRAME_EVENT.write_message(vec![KeyframeInteractionEvent::AddEntityTrack { KEYFRAME_EVENT.write_message(vec![KeyframeInteractionEvent::AddEntityTrack { target }]);
target
}]);
} }
pub(super) fn update_global_seek_time( pub(super) fn update_global_seek_time(
@@ -734,7 +758,7 @@ mod wasm {
(Entity, &Keyframe, &TimedAnimationClipAsset), (Entity, &Keyframe, &TimedAnimationClipAsset),
Or<(Changed<Keyframe>, Changed<TimedAnimationClipAsset>)>, Or<(Changed<Keyframe>, Changed<TimedAnimationClipAsset>)>,
>, >,
mut removed: bevy::prelude::RemovedComponents<Keyframe>, removed: Query<Entity, With<MarkedForDeletion>>,
) -> Result<(), String> { ) -> Result<(), String> {
let Ok(window) = q_window.get_single() else { let Ok(window) = q_window.get_single() else {
return Ok(()); return Ok(());
@@ -775,7 +799,7 @@ mod wasm {
})) }))
.collect::<Result<HashMap<_, _>, String>>()?; .collect::<Result<HashMap<_, _>, String>>()?;
let removed = removed.read().map(|v| format!("{v:?}")).collect::<Vec<_>>(); let removed = removed.iter().map(|v| format!("{v:?}")).collect::<Vec<_>>();
if added.is_empty() && removed.is_empty() { if added.is_empty() && removed.is_empty() {
return Ok(()); return Ok(());
+14 -1
View File
@@ -27,6 +27,7 @@ impl Plugin for SelectionPlugin {
PostUpdate, PostUpdate,
draw_selection_outline.run_if(resource_changed_or_removed::<Selection>()), draw_selection_outline.run_if(resource_changed_or_removed::<Selection>()),
) )
.add_systems(First, finalize_delete)
.add_systems( .add_systems(
OnEnter(SceneState::Active), OnEnter(SceneState::Active),
(apply_deferred, tag_scene_elements) (apply_deferred, tag_scene_elements)
@@ -158,6 +159,9 @@ fn update_selection(
} }
} }
#[derive(Component)]
pub struct MarkedForDeletion;
fn process_delete_inputs( fn process_delete_inputs(
mut cmd: Commands, mut cmd: Commands,
mut er_input: EventReader<InputAction>, mut er_input: EventReader<InputAction>,
@@ -172,7 +176,7 @@ fn process_delete_inputs(
}) { }) {
let entity = **r_selection; let entity = **r_selection;
cmd.entity(entity).despawn_recursive(); cmd.entity(entity).insert(MarkedForDeletion);
cmd.remove_resource::<Selection>(); cmd.remove_resource::<Selection>();
ew_changes.send(NewChange { ew_changes.send(NewChange {
change: Arc::new(RemovedEntity { entity }), change: Arc::new(RemovedEntity { entity }),
@@ -180,6 +184,15 @@ fn process_delete_inputs(
} }
} }
fn finalize_delete(
mut cmd: Commands,
q: Query<Entity, With<MarkedForDeletion>>
) {
for entity in &q {
cmd.entity(entity).despawn_recursive();
}
}
fn draw_selection_outline( fn draw_selection_outline(
mut cmd: Commands, mut cmd: Commands,
q_selected: Query<&Children, With<Selected>>, q_selected: Query<&Children, With<Selected>>,