Multirious / bevy_tween

Flexible tweening plugin library for Bevy.
Apache License 2.0
87 stars 2 forks source link

Reverse ease graph on `RepeatStyle::PingPong` #24

Open musjj opened 2 months ago

musjj commented 2 months ago

Right now, it looks like that when a tween is being repeated with RepeatStyle::PingPong the direction of the ease is not reversed.

So for example when using EaseFunction::BounceOut, the movement is bounced at the end of the movement in the first loop, but then bounced at the start in the second loop.

I'm not sure which is more intuitive and I'm pretty sure that there might be a use-case that require this behavior. But I feel being able to reverse the ease would a pretty useful feature.

Multirious commented 2 months ago

RepeatStyle::PingPong is a calculation in bevy_time_runner where it literally reverse the TimeDirection on 'bounce'. This is the simplest implementation and most intuitive behavior IMO. This should supports most looping animations that will be made, I hope...

Short term solution: For any specific animation style you want to animate will need to be done specifically in 2 part and use RepeatStyle::WrapAround. Eg.

commands.animation().repeat(Repeat::Infinitely).insert(sequence((
    tween(duration, EaseFunction::BounceOut, ...),
    tween(duration, EaseFunction::BounceIn, ...)
)));

System solution: There could be a method to retrieve the 'inverse' ease version (In <-> Out). And then every time the time_runner 'bounce', Run a system that inverse the ease. Example API could looks like

commands.spawn(InverseEaseOnBounce).animation().repeat(Repeat::Infinitely).insert(sequence((
    tween(duration, (EaseFunction::BounceOut, InverseThis), ...), // or DontInverseThis marker
)));

InverseEaseOnBounce is a marker component for the animation root. The ease inversing systems will then selectively target this animation to inverse any ease with the marker InverseThis. Of course you can also implement without the marker too if you want the system to apply everywhere. You can have a try implementing this method in your project. This might be a useful feature but I think I need more people responding to this issue to confirm. If that did happen then I'm happy to put this feature into the crate!