Open Shatur opened 2 years ago
Thanks for logging this and for the video. It's definitely something I want to add.
Note: I've looked into looping Tracks
and it's a minefield of corner cases that I'm not sure how to handle. For example with one tweenable of 0.8 second and another one of 1 second, what does looping look like in the [0.8:1.0] time frame for the first tweenable (since the Tracks
will be 1 second long, the max of all its children)? What about ping-pong looping (reverse playback) in that time frame? etc.
@djeedai Makes sense... Maybe we should keep only Tween
objects loopable, but turn Tracks
into a simple array to allow users to apply multiply Tween
s to the same object?
@Shatur I'm not sure I follow, that sounds like what Tracks
is already doing. What is the difference between what you describe and what Tracks
currently does, which is applying a collection of Tweenable
in parallel to the same object. Granted, it doesn't have introspection so you can't index like an array to inspect its content, but internally it is an array.
@djeedai sorry for confusion, I didn't mean indexing.
If I understand correctly, I can't execute multiply loopable tweens in parallel with Tracks
. Is it correct? I would expect Tracks
to have infinity duration if at least one Tween
is loopable.
If I understand correctly, I can't execute multiply loopable tweens in parallel with
Tracks
. Is it correct?
Correct.
I would expect
Tracks
to have infinity duration if at least one Tween is loopable.
Yes. But that's the easy part of making Tracks
loopable. Are you saying you want each single tweenable to loop completely independently of each other, and so Tracks
wouldn't really have a defined duration anymore? So Tracks
wouldn't implement Tweenable
.
So Tracks wouldn't implement Tweenable.
Oh, I see. Hm... Maybe instead of having tracks, we allow could to store multiply tweenable objects inside the Animator
?
So far animator allows us to mutate various components in a seq or track. What if we wanted to add another seq/track to the same animator? I might be out of my depth, but can we achieve this by:
@azarmadr Makes sense to me. So we will be able to store multiply Tweenable
objects inside the Animator
object?
I don't really like the Animator
having to manage multiple Tweenable
, first because a lot of use cases only need a single one, and second because the entire purpose of abstracting things behind a Tweenable
trait is for the Animator
not to have to care about any extra complexity. Especially since code is mostly duplicated between the Animator
and AssetAnimator
, so the simpler they remain and the more code moved into a shared Tweenable
the better.
I'm open to discuss modifying Tracks
, or even adding a new Tweenable
type, if there's a use case that's not currently covered. As stated above, making Sequence
loopable seems doable (didn't try yet) but Tracks
as it is can't really be made loopable unless we solve all the corner cases it has when doing so. If someone has an idea to solve those, or an idea of a different type of Tweenable
that would allow looping parallel tweens, then that would be I think a better approach.
I'm open to discuss modifying Tracks, or even adding a new Tweenable type, if there's a use case that's not currently covered
@djeedai I mentioned the use-case in the first message, but I don't know what to suggest for architecture to provide such functionality :(
Opened #16 for the case of making Sequence
loopable, which is well-defined and "just" need to be done. The case of Tracks
is more complicated and I don't think there's a good proposal for it yet.
I observed that Animator is constrained to Component
. Unlike AssetAnimator, where it needs to be constrained to Asset
, the Animator
type could be anything. We can just constrain the system using Animator to be Component
, which is already happening.
Yesterday I was trying to make the animator with WorldQuery
type, which might be impossible because of timing constraints. Then I finally settled on a Tuple
of components.
if Animator is without any constraints, I tried this
/// trying to create a bundled animator
pub fn component_animator2_system<T:Component+Clone,R:Component+Clone>(
time: Res<Time>,
mut query: Query<(Entity, (&mut T,&mut R), &mut Animator<(T,R)>)>,
mut event_writer: EventWriter<TweenCompleted>,
)
{
for (entity, ref mut target, ref mut animator) in query.iter_mut() {
if animator.state != AnimatorState::Paused {
if let Some(tweenable) = animator.tweenable_mut() {
let nt = &mut(target.0.clone(),target.1.clone());
tweenable.tick(time.delta(), nt, entity, &mut event_writer);
let (ref a,ref b) = nt;
*target.0 = a.clone();
*target.1 = b.clone();
}
}
}
}
I'm also facing difficulties with the lack of flexibility in the current API. So I'm thinking of a different approach: in addition to entity-level animators, we can also provide system-level animators.
A sketch of what the API might look like:
let tween = SystemTween::new(EaseFunction::QuadraticInOut, Duration::from_secs(1))
.with_repeat_count(RepeatCount::Finite(2))
.with_repeat_strategy(RepeatStrategy::MirroredRepeat);
// a `SystemAnimator` associated with this system will be passed
let system = |In(mut animator): In<&mut SystemAnimator>,
mut foo_query: Query<&mut Transform, With<Foo>>,
mut bar_query: Query<&mut Transform, With<Bar>>| {
let ratio = animator.get_ratio();
let mut transform = foo_query.get_single().unwrap();
transform.x = 50.0_f32.lerp(80.0, ratio);
animator.set_speed(0.5);
// do some other stuff
};
app.add_animation(SystemAnimator::new(tween), system);
This gives the user a lot of flexibility to basically do anything they want.
But after a quick look through the library, it looks like that Lens
is coupled with many parts of the library, which might make it hard to implement. Also, I guess Track
wouldn't make sense under this API.
What do you think?
I also expected to be able to have different Lens types in one Track but that doesn't work either. Not sure if there is a way and I was just too blind to see it though.
let seq = Tracks::new([
Tween::new(
EaseFunction::QuarticOut,
Duration::from_secs_f32(0.2),
TransformPositionLens {
start: Vec3::ZERO,
end: Vec3::ONE,
},
),
Tween::new(
EaseFunction::QuarticOut,
Duration::from_secs_f32(0.2),
SpriteColorLens {
start: Color::WHITE,
end: Color::BLACK,
},
),
]);
To combine multiply tweens and loop them I have to create custom lens which is not very ergonomic. We currently have
Tracks
andSequence
, but they aren't loopable. I would like to request to extend their functionality. It would be great if we could combine multiply tweens with different tweening type. For example, to animate healing pickup like in Owerwatch I need rotation tween withLoop
and translation tween withPingPong
. Video of how such pickups look.