use std::time::Duration;
use bevy::prelude::*;
use bevy_egui::{egui, EguiContexts, EguiPlugin};
use timeline_rs::{easing::{self, EasingFunction, EasingType}, loader::TimelineXMLLoader, Keyframe, Timeline, TimelineTrack, Track, TrackGetter};
fn s(dur: f32) -> Duration {
Duration::from_secs_f32(dur)
}
fn create_timeline() -> Timeline {
let mut tl = Timeline::new();
let xml_x = r#"
<keyframes>
<key>
<easefunc>0</easefunc>
<easetype>0</easetype>
<time>00:00:00:524</time>
<value>0.375000000</value>
</key>
<key>
<easefunc>0</easefunc>
<easetype>0</easetype>
<time>00:00:00:826</time>
<value>0.408691406</value>
</key>
<key>
<easefunc>0</easefunc>
<easetype>0</easetype>
<time>00:00:01:034</time>
<value>0.324999988</value>
</key>
<key>
<easefunc>0</easefunc>
<easetype>0</easetype>
<time>00:00:01:459</time>
<value>0.777343750</value>
</key>
<key>
<easefunc>4</easefunc>
<easetype>0</easetype>
<time>00:00:02:123</time>
<value>0.330175757</value>
</key>
</keyframes>
"#;
let xml_y = r#"
<keyframes>
<key>
<easefunc>0</easefunc>
<easetype>0</easetype>
<time>00:00:00:643</time>
<value>0.585546851</value>
</key>
<key>
<easefunc>4</easefunc>
<easetype>2</easetype>
<time>00:00:00:826</time>
<value>0.141503930</value>
</key>
<key>
<easefunc>1</easefunc>
<easetype>1</easetype>
<time>00:00:01:594</time>
<value>0.443359375</value>
</key>
<key>
<easefunc>0</easefunc>
<easetype>2</easetype>
<time>00:00:02:033</time>
<value>0.400390625</value>
</key>
<key>
<easefunc>4</easefunc>
<easetype>0</easetype>
<time>00:00:02:260</time>
<value>0.586718738</value>
</key>
</keyframes>"#;
tl.load_xml_str::<f32>("x", xml_x).unwrap();
tl.load_xml_str::<f32>("y", xml_y).unwrap();
tl
}
#[derive(Resource)]
struct TimelineData {
pub timeline: Timeline,
pub t : f32,
pub x : f32,
pub y : f32,
pub looped: bool,
}
impl Default for TimelineData {
fn default() -> Self {
TimelineData {
timeline: create_timeline(),
t: 0.0,
x: 0.0,
y: 0.0,
looped: true,
}
}
}
pub fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(EguiPlugin)
.insert_resource(TimelineData::default())
.add_systems(Startup, setup)
.add_systems(Update, update_egui)
.add_systems(Update, update)
.add_systems(Update, bevy::window::close_on_esc)
.run();
}
fn setup(mut commands: Commands) {
commands.spawn(Camera2dBundle::default());
}
fn update_egui (
mut contexts: EguiContexts,
mut data: ResMut<TimelineData>,
) {
egui::Window::new("Easing").show(contexts.ctx_mut(), |ui| {
ui.checkbox(&mut data.looped, "Looped");
let duration: f32 = data.timeline.get_max_duration().as_secs_f32();
ui.add(egui::Slider::new(&mut data.t, 0.0..=duration).text("t"));
ui.add(egui::Slider::new(&mut data.x, 0.0..=1.0).text("x"));
ui.add(egui::Slider::new(&mut data.y, 0.0..=1.0).text("y"));
});
}
fn update(
mut gizmos: Gizmos,
time: Res<Time>,
mut data: ResMut<TimelineData>,
) {
let duration: f32 = data.timeline.get_max_duration().as_secs_f32();
data.t += time.delta_seconds();
if data.looped {
if data.t > duration {
data.t = 0.0;
}
} else {
if data.t > duration {
}
}
let vx = data.timeline.get_value("x", Duration::from_secs_f32(data.t)).into();
let vy = data.timeline.get_value("y", Duration::from_secs_f32(data.t)).into();
data.x = vx;
data.y = vy;
let length = 400.0;
let height = 100.0;
let x = vx * length - length / 2.0;
let y = vy * height;
gizmos.circle_2d(Vec2::new(x, y), 30.0, Color::RED);
let ny = -60.0;
gizmos.line_2d(Vec2::new(-length / 2.0, ny), Vec2::new(length / 2.0, ny), Color::GREEN);
gizmos.line_2d(Vec2::new(-length / 2.0, ny - 10.0), Vec2::new(-length / 2.0, ny + 10.0), Color::GREEN);
gizmos.line_2d(Vec2::new(length / 2.0, ny - 10.0), Vec2::new(length / 2.0, ny + 10.0), Color::GREEN);
}