mod implemented;
mod lerp;
pub mod prelude {
pub use crate::{lerp::Lerp, *};
}
use std::ops::Deref;
use bevy::{hierarchy::HierarchySystem, prelude::*, transform::TransformSystem, utils::HashMap};
use crate::lerp::Lerp;
pub struct Keyframe<T>(pub T);
impl<T> Lerp<T> for Keyframe<T>
where
T: Lerp<T>,
{
fn lerp(&self, other: &Self, scalar: f32, target: &T, options: &Option<Vec<String>>) -> Self {
Keyframe(self.0.lerp(&other.0, scalar, target, options))
}
}
pub struct KeyframeVariableCurve<T> {
pub keyframe_timestamps: Vec<f32>,
pub keyframes: Vec<Keyframe<T>>,
pub options: Option<Vec<String>>,
}
#[derive(Clone, Debug, Hash, PartialEq, Eq, Default)]
pub struct KeyframeEntityPath {
pub parts: Vec<Name>,
}
#[derive(Default, Component)]
pub struct KeyframeAnimationClip<T> {
curves: HashMap<KeyframeEntityPath, Vec<KeyframeVariableCurve<T>>>,
duration: f32,
}
impl<T> KeyframeAnimationClip<T> {
#[inline]
pub fn curves(&self) -> &HashMap<KeyframeEntityPath, Vec<KeyframeVariableCurve<T>>> {
&self.curves
}
#[inline]
pub fn duration(&self) -> f32 {
self.duration
}
pub fn add_curve_to_path(&mut self, path: KeyframeEntityPath, curve: KeyframeVariableCurve<T>) {
self.duration = self
.duration
.max(*curve.keyframe_timestamps.last().unwrap_or(&0.0));
self.curves.entry(path).or_default().push(curve);
}
}
#[derive(Component)]
pub struct KeyframeAnimationPlayer<T> {
paused: bool,
repeat: bool,
speed: f32,
elapsed: f32,
animation_clip: KeyframeAnimationClip<T>,
}
impl<T> KeyframeAnimationPlayer<T> {
pub fn new(animation_clip: KeyframeAnimationClip<T>) -> Self {
Self {
paused: false,
repeat: false,
speed: 1.0,
elapsed: 0.0,
animation_clip,
}
}
}
impl<T> KeyframeAnimationPlayer<T> {
pub fn play(&mut self, handle: KeyframeAnimationClip<T>) -> &mut Self {
*self = Self {
animation_clip: handle,
paused: false,
repeat: false,
speed: 1.0,
elapsed: 0.0,
};
self
}
pub fn repeat(&mut self) -> &mut Self {
self.repeat = true;
self
}
pub fn stop_repeating(&mut self) -> &mut Self {
self.repeat = false;
self
}
pub fn pause(&mut self) {
self.paused = true;
}
pub fn resume(&mut self) {
self.paused = false;
}
pub fn is_paused(&self) -> bool {
self.paused
}
pub fn speed(&self) -> f32 {
self.speed
}
pub fn set_speed(&mut self, speed: f32) -> &mut Self {
self.speed = speed;
self
}
pub fn elapsed(&self) -> f32 {
self.elapsed
}
pub fn set_elapsed(&mut self, elapsed: f32) -> &mut Self {
self.elapsed = elapsed;
self
}
}
pub fn keyframe_animation_player<T: Component>(
time: Res<Time>,
mut query: Query<(Entity, &mut T)>,
mut animation_players: Query<&mut KeyframeAnimationPlayer<T>>,
names: Query<&Name>,
children: Query<&Children>,
) where
Keyframe<T>: Lerp<T>,
T: Default,
{
for (entity, mut object) in query.iter_mut() {
if let Ok(mut player) = animation_players.get_mut(entity) {
if player.paused && !player.is_changed() {
continue;
}
if !player.paused {
player.elapsed += time.delta_seconds() * player.speed;
}
let mut elapsed = player.elapsed;
if player.repeat {
elapsed %= player.animation_clip.duration;
}
if elapsed < 0.0 {
elapsed += player.animation_clip.duration;
}
'entity: for (path, curves) in &player.animation_clip.curves {
let mut current_entity = entity;
for part in path.parts.iter().skip(1) {
let mut found = false;
if let Ok(children) = children.get(current_entity) {
for child in children.deref() {
if let Ok(name) = names.get(*child) {
if name == part {
current_entity = *child;
found = true;
break;
}
}
}
}
if !found {
warn!("Entity not found for path {:?} on part {:?}", path, part);
continue 'entity;
}
}
for curve in curves {
if curve.keyframe_timestamps.len() == 1 {
*object = Keyframe(T::default())
.lerp(&curve.keyframes[0], 0., &*object, &curve.options)
.0;
continue;
}
let step_start = match curve
.keyframe_timestamps
.binary_search_by(|probe| probe.partial_cmp(&elapsed).unwrap())
{
Ok(i) => i,
Err(0) => continue, Err(n) if n > curve.keyframe_timestamps.len() - 1 => continue,
Err(i) => i - 1,
};
let ts_start = curve.keyframe_timestamps[step_start];
let ts_end = curve.keyframe_timestamps[step_start + 1];
let lerp = (elapsed - ts_start) / (ts_end - ts_start);
*object = curve.keyframes[step_start]
.lerp(
&curve.keyframes[step_start + 1],
lerp,
&*object,
&curve.options,
)
.0;
}
}
}
}
}
#[derive(Default)]
pub struct KeyframeAnimationPlugin;
impl Plugin for KeyframeAnimationPlugin {
fn build(&self, app: &mut App) {
app.add_system_to_stage(
CoreStage::PostUpdate,
keyframe_animation_player::<Transform>
.before(TransformSystem::TransformPropagate)
.after(HierarchySystem::ParentUpdate),
)
.add_system(keyframe_animation_player::<Sprite>)
.add_system(keyframe_animation_player::<Handle<Image>>)
.add_system(keyframe_animation_player::<TextureAtlasSprite>);
}
}