animating the timeline

This commit is contained in:
Lee-Orr
2024-03-15 17:14:47 -04:00
parent 15b65f114b
commit 53e91cf5a5
2 changed files with 114 additions and 13 deletions
+94 -13
View File
@@ -39,7 +39,7 @@ export class AnimEditorElement extends LitElement {
@state() keyframes : Record<string, Keyframe> = {};
@state() selected_track : string | false = false;
@state() selected_track : { track: string } | {outside_entity: string } | false = false;
trackCount(): number {
return Object.keys(this.tracks).length;
@@ -78,6 +78,14 @@ export class AnimEditorElement extends LitElement {
this.track_ordered = Object.keys(tracks);
if (typeof this.selected_track === "object") {
if ("track" in this.selected_track && !(this.selected_track.track in tracks)) {
this.selected_track = { outside_entity: this.selected_track.track};
} else if ("outside_entity" in this.selected_track && this.selected_track.outside_entity in tracks) {
this.selected_track = { track: this.selected_track.outside_entity};
}
}
this.tracks = tracks;
}
@@ -94,13 +102,32 @@ export class AnimEditorElement extends LitElement {
}
this.keyframes = keyframes;
let min = 0;
let max = 5;
for (const keyframe of Object.keys(this.keyframes)) {
let time = this.keyframes[keyframe].time;
if (typeof time != "number") {
continue;
}
if (time > max) {
max = time + 1;
}
}
this.timelineEnd = max;
}
@on("window:entity-select")
onEntitySelected({ detail: id }: EntitySelectEvent): void {
if (id && this.tracks[id]) {
this.selected_track = id;
if (id) {
if (this.tracks[id]) {
this.selected_track = { track: id };
} else if (!this.keyframes[id]) {
this.selected_track = {outside_entity: id};
} else {
this.selected_track = false;
}
} else {
this.selected_track = false;
}
@@ -111,8 +138,8 @@ export class AnimEditorElement extends LitElement {
}
addKeyframe(): void {
if (this.selected_track) {
studio.recordKeyframe([this.selected_track]);
if (typeof this.selected_track === "object" && "track" in this.selected_track) {
studio.recordKeyframe([this.selected_track.track]);
}
}
@@ -123,19 +150,58 @@ export class AnimEditorElement extends LitElement {
prevKeyframe(): void {
let pos = this.playHead;
this.playHead = pos;
let closest_keyframe = -1 * Infinity;
for (const keyframe of Object.keys(this.keyframes)) {
const time = this.keyframes[keyframe]?.time;
if (!time || typeof time != "number") {
continue;
}
if (time < pos && time > closest_keyframe ) {
closest_keyframe = time;
}
}
if (closest_keyframe < 0) {
return;
}
this.playHead = closest_keyframe;
}
nextKeyframe(): void {
let pos = this.playHead;
this.playHead = pos;
let closest_keyframe = Infinity;
for (const keyframe of Object.keys(this.keyframes)) {
const time = this.keyframes[keyframe]?.time;
if (!time || typeof time != "number") {
continue;
}
if (time > pos && time < closest_keyframe ) {
closest_keyframe = time;
}
}
if (closest_keyframe > this.timelineEnd) {
return;
}
this.playHead = closest_keyframe;
}
jumpToEnd(): void {
this.playHead = this.clipEnd;
}
addTarget(): void {
if (typeof this.selected_track === "object" && "outside_entity" in this.selected_track) {
studio.addEntityTrack(this.selected_track.outside_entity);
}
}
togglePlaying(): void {
console.log("toggling play");
if (this.playing) {
@@ -146,10 +212,6 @@ export class AnimEditorElement extends LitElement {
}
protected override render(): TemplateResult {
let track_count = {
'--track-count': `${this.trackCount()}`,
'--row-count': `calc(var(--track-count) + 1)`
};
const track_order_hashed : Record<string, number> = {};
@@ -157,12 +219,21 @@ export class AnimEditorElement extends LitElement {
track_order_hashed[track] = index;
}
const selected = typeof this.selected_track === "object" && "track" in this.selected_track ? this.selected_track.track : false;
const can_add_selected = typeof this.selected_track === "object" && "outside_entity" in this.selected_track ? this.selected_track.outside_entity : false;
let track_count = {
'--track-count': `${this.trackCount()}`,
'--row-count': `calc(var(--track-count) + ${can_add_selected ? 2 : 1})`
};
const tracklist = this.track_ordered.map((entity) => {
let track = this.tracks[entity];
let name = track.name ?? track.target_type;
let icon = TRACK_ICONS[track.target_type] ?? "minus";
return html`
<sts-tree class=${`track ` + (this.selected_track === entity ? `selected` : ``)}
<sts-tree class=${`track ` + (selected === entity ? `selected` : ``)}
role="listitem"
name=${name}
icon=${icon}
@@ -173,7 +244,17 @@ export class AnimEditorElement extends LitElement {
`;
});
const none_selected = !this.selected_track;
if (can_add_selected) {
tracklist.push(html`
<sts-tree class=${`track`}
role="button"
name="animate current selection"
icon="plus-large"
@click=${this.addTarget}></sts-tree>
`);
}
const none_selected = !selected;
return html`
<div class="sidebar"
+20
View File
@@ -88,6 +88,7 @@ pub enum TimelineInteractionEvent {
pub enum KeyframeInteractionEvent {
RecordKeyframe { target: Entity },
MoveKeyframeTime { target: Entity, time: f32 },
AddEntityTrack { target: Entity }
}
#[derive(Resource, Clone, Copy, Debug, Default, Reflect, Serialize, Deserialize)]
@@ -225,6 +226,7 @@ fn process_keyframe_events(
mut e_timeline_event: EventReader<KeyframeInteractionEvent>,
r_global_seek_time: Res<GlobalSeekTime>,
q_animation_targets: Query<(Entity, &Transform), With<AnimationTarget>>,
q_potential_targets: Query<Entity, (With<Transform>, Without<AnimationTarget>)>,
mut q_keyframes: Query<&mut Keyframe>,
) {
for event in e_timeline_event.read() {
@@ -251,6 +253,14 @@ fn process_keyframe_events(
keyframe.time = *time;
}
}
KeyframeInteractionEvent::AddEntityTrack { target } => {
if let Ok(target) = q_potential_targets.get(*target) {
info!("Adding Animation Target to Entity");
commands.entity(target).insert(AnimationTarget);
} else {
warn!("Can't add animation target to entity");
}
},
}
}
}
@@ -507,6 +517,16 @@ mod wasm {
}]);
}
#[wasm_bindgen(js_name = addEntityTrack)]
pub fn add_entity_track(entity: String) {
let Ok(target) = Entity::from_str(&entity) else {
return;
};
KEYFRAME_EVENT.write_message(vec![KeyframeInteractionEvent::AddEntityTrack {
target
}]);
}
pub(super) fn update_global_seek_time(
mut e_timeline_event: EventWriter<TimelineInteractionEvent>,
) {