mirror of
https://github.com/storytold/storyteller-bevy.git
synced 2026-10-17 00:13:17 +00:00
- avoid updating seek time from UI if source of seek time is studio, … (#102)
…to avoid re-processing timeline info - move generating animation to first thing in a frame, and notifying about timeline changes to last, to ensure that it happens before the time updates - re-generate the animation tweens whenever you start playing or manually seek a new time in the timeline to prevent inconsistencies
This commit is contained in:
@@ -64,9 +64,6 @@ implements TreeSelectionProvider {
|
||||
}
|
||||
|
||||
protected override update(changes: PropertyValues<this>): void {
|
||||
if (changes.has("playHead"))
|
||||
studio.seekTime(this.playHead);
|
||||
|
||||
if (changes.has("selectedTrack")) {
|
||||
const treeSelectionChanges: PropertyValues<TreeSelectionProvider> = new Map();
|
||||
const prevSelectedTrack = changes.get("selectedTrack");
|
||||
@@ -81,6 +78,10 @@ implements TreeSelectionProvider {
|
||||
super.update(changes);
|
||||
}
|
||||
|
||||
setPlayTime(time: number) : void {
|
||||
studio.seekTime(time);
|
||||
}
|
||||
|
||||
@on("window:seek-time-changed")
|
||||
onSeekTimeChanged({ detail: {time, playing} }: SeekTimeChanged ): void {
|
||||
console.log("Seek Time Changed", time, playing);
|
||||
@@ -189,9 +190,9 @@ implements TreeSelectionProvider {
|
||||
|
||||
jumpToStart(): void {
|
||||
if (Math.abs(this.playHead - this.clipStart) < 0.0001) {
|
||||
this.playHead = 0;
|
||||
studio.seekTime(0);
|
||||
} else {
|
||||
this.playHead = this.clipStart;
|
||||
studio.seekTime(this.clipStart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +215,7 @@ implements TreeSelectionProvider {
|
||||
closest_keyframe = 0;
|
||||
}
|
||||
|
||||
this.playHead = closest_keyframe;
|
||||
studio.seekTime(closest_keyframe);
|
||||
}
|
||||
|
||||
nextKeyframe(): void {
|
||||
@@ -237,11 +238,11 @@ implements TreeSelectionProvider {
|
||||
return;
|
||||
}
|
||||
|
||||
this.playHead = closest_keyframe;
|
||||
studio.seekTime(closest_keyframe);
|
||||
}
|
||||
|
||||
jumpToEnd(): void {
|
||||
this.playHead = this.clipEnd;
|
||||
studio.seekTime(this.clipEnd);
|
||||
}
|
||||
|
||||
addTarget(): void {
|
||||
@@ -380,7 +381,7 @@ implements TreeSelectionProvider {
|
||||
.rangeEnd=${bind(this, "timelineEnd")}
|
||||
.clipStart=${this.clipStart}
|
||||
.clipEnd=${this.clipEnd}
|
||||
.playHead=${bind(this, "playHead")}
|
||||
.playHead=${this.playHead}
|
||||
.keyframes=${bind(this, "keyframes")}
|
||||
.track_ordered=${track_order_hashed}
|
||||
.track_animation_target_ordered=${track_animation_target_order_hashed}
|
||||
|
||||
@@ -200,7 +200,7 @@ export class AnimTimelineElement extends LitElement {
|
||||
const seconds = (this.rangeEnd - this.rangeStart) * ratioX + this.rangeStart;
|
||||
const updated = seconds;
|
||||
|
||||
this.dispatchEvent(new CustomEvent("playHead-change", { detail: updated }));
|
||||
studio.seekTime(updated);
|
||||
}
|
||||
|
||||
onKeyframeDrag(id: string, event: PointerEvent): void {
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
use std::{str::FromStr, time::Duration};
|
||||
|
||||
use bevy::{
|
||||
prelude::*,
|
||||
utils::{hashbrown::HashMap, HashSet},
|
||||
};
|
||||
use bevy::{prelude::*, utils::hashbrown::HashMap};
|
||||
|
||||
use bevy_tweening::{
|
||||
lens::{TransformPositionLens, TransformRotationLens, TransformScaleLens},
|
||||
@@ -44,6 +41,7 @@ impl Plugin for TimelinePlugin {
|
||||
})
|
||||
.add_event::<TweenCompleted>();
|
||||
|
||||
app.add_systems(First, generate_transform_animation);
|
||||
app.add_systems(PreUpdate, (process_timeline_events, update_tick).chain());
|
||||
|
||||
app.add_systems(
|
||||
@@ -54,12 +52,12 @@ impl Plugin for TimelinePlugin {
|
||||
),
|
||||
);
|
||||
|
||||
app.add_systems(PostUpdate, generate_transform_animation);
|
||||
// app.add_systems(PostUpdate, generate_transform_animation);
|
||||
|
||||
#[cfg(feature = "wasm")]
|
||||
{
|
||||
app.add_systems(
|
||||
First,
|
||||
Last,
|
||||
(
|
||||
wasm::update_global_seek_time,
|
||||
wasm::update_keyframe_interaction,
|
||||
@@ -347,37 +345,34 @@ fn process_keyframe_events(
|
||||
|
||||
fn generate_transform_animation(
|
||||
mut commands: Commands,
|
||||
changed: Query<
|
||||
&Keyframe,
|
||||
(
|
||||
With<TransformKeyframe>,
|
||||
Or<(Changed<Keyframe>, Changed<Transform>)>,
|
||||
),
|
||||
>,
|
||||
keyframes: Query<
|
||||
(&Keyframe, &Transform, &TransformKeyframe, Entity),
|
||||
Without<MarkedForDeletion>,
|
||||
>,
|
||||
added_targets: Query<(Entity, &AnimationTarget), Added<AnimationTarget>>,
|
||||
valid_targets: Query<(Entity, &AnimationTarget)>,
|
||||
removed: Query<&Keyframe, With<MarkedForDeletion>>,
|
||||
mut e_timeline_event: EventReader<TimelineInteractionEvent>,
|
||||
) {
|
||||
let mut playing = false;
|
||||
for e in e_timeline_event.read() {
|
||||
if matches!(
|
||||
e,
|
||||
TimelineInteractionEvent::Play | TimelineInteractionEvent::Seek(_)
|
||||
) {
|
||||
playing = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if !playing {
|
||||
return;
|
||||
}
|
||||
|
||||
let available_targets = valid_targets
|
||||
.iter()
|
||||
.map(|(e, a)| (*a, e))
|
||||
.collect::<HashMap<_, _>>();
|
||||
let changed_targets = changed
|
||||
.iter()
|
||||
.map(|keyframe| keyframe.target)
|
||||
.chain(removed.iter().map(|keyframe| {
|
||||
info!("Processing a removed keyframe {keyframe:?}");
|
||||
keyframe.target
|
||||
}))
|
||||
.chain(added_targets.iter().map(|(_, a)| *a))
|
||||
.collect::<HashSet<_>>();
|
||||
|
||||
let keyframes = keyframes
|
||||
.iter()
|
||||
.filter(|(keyframe, _, _, _)| changed_targets.contains(&keyframe.target))
|
||||
.group_by(|(keyframe, _, _, _)| keyframe.target);
|
||||
|
||||
for (target, keyframes) in &keyframes {
|
||||
@@ -635,6 +630,7 @@ mod wasm {
|
||||
mut e_timeline_event: EventWriter<TimelineInteractionEvent>,
|
||||
) {
|
||||
if let Some(timestamp) = SEEK_TIME.take_message() {
|
||||
info!("Updating Seek Time {timestamp:?}");
|
||||
e_timeline_event.send(timestamp);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user