Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend Tracks and Sequence functionality #8

Open
Shatur opened this issue Mar 6, 2022 · 16 comments
Open

Extend Tracks and Sequence functionality #8

Shatur opened this issue Mar 6, 2022 · 16 comments
Labels
enhancement New feature or request

Comments

@Shatur
Copy link

Shatur commented Mar 6, 2022

To combine multiply tweens and loop them I have to create custom lens which is not very ergonomic. We currently have Tracks and Sequence, 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 with Loop and translation tween with PingPong. Video of how such pickups look.

@djeedai djeedai added the enhancement New feature or request label Mar 6, 2022
@djeedai
Copy link
Owner

djeedai commented Mar 6, 2022

Thanks for logging this and for the video. It's definitely something I want to add.

@djeedai
Copy link
Owner

djeedai commented Mar 19, 2022

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.

@Shatur
Copy link
Author

Shatur commented Mar 19, 2022

@djeedai Makes sense... Maybe we should keep only Tween objects loopable, but turn Tracks into a simple array to allow users to apply multiply Tweens to the same object?

@djeedai
Copy link
Owner

djeedai commented Mar 19, 2022

@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.

@Shatur
Copy link
Author

Shatur commented Mar 19, 2022

@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.

@djeedai
Copy link
Owner

djeedai commented Mar 19, 2022

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.

@Shatur
Copy link
Author

Shatur commented Mar 19, 2022

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?

@azarmadr
Copy link

azarmadr commented Apr 3, 2022

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:

  • add/remove seq or track from the tweenable collection that the animator holds.

@Shatur
Copy link
Author

Shatur commented Apr 3, 2022

@azarmadr Makes sense to me. So we will be able to store multiply Tweenable objects inside the Animator object?

@djeedai
Copy link
Owner

djeedai commented Apr 3, 2022

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.

@Shatur
Copy link
Author

Shatur commented Apr 17, 2022

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 :(

@djeedai
Copy link
Owner

djeedai commented Apr 24, 2022

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.

@azarmadr
Copy link

azarmadr commented Apr 30, 2022

I have been playing around with lens and settled on this.

multiple-field-lens.mp4

@azarmadr
Copy link

azarmadr commented May 1, 2022

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();
            }
        }
    }
}

You can find the above system in my fork

bundle_animator.mp4

@musjj
Copy link

musjj commented Jan 22, 2024

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?

@PraxTube
Copy link

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,
        },
    ),
]);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants