voxell-tech/bevy_motiongfx

Repeat any arbitrary `Sequence`

Opened this issue · 6 comments

It would be nice if you can repeat any arbitrary sequence, like other bevy tweening plugins:

For example:

flow(&[
    commands.play(transform_motions[c].translate_add(Vec3::X), 1.0),
    commands.play(transform_motions[c].scale_to(Vec3::splat(0.9)), 1.0),
])
.with_repeat_count(repeat::finite(2)) // or infinite
.with_repeat_style(repeat::style::mirrored) // this will flip the animation direction on every loop

You can manually do this, but metadatas will make it easy to mix and match repeat counts/styles in a single sequence.

This is extremely important feature, will be supported in the future! I am currently doing some major changes to the Action creation API at the moment for a more robust use case. (because right now, you can only rely on actions that our Motion APi provides, and hardly any control over how things are being interpolated.

Nice. Btw, I'm liking how the new macros are turning out. I tried playing around with it, but it looks likes that completions are starting to show some cracks. For example:

let sequence = play!(
    commands,
    act!(
        (cube_ids[c], Transform),
        start = {transforms[c]}.scale,
        end = Vec3::splat(0.9),
    )
    .with_ease(ease::circ::ease_in_out)
    .animate(1.0),
    |
);

When you start typing with your cursor at |, completions no longer work. It works perfectly for commands and the first act!, but breaks down afterwards.

@musjj Thanks for trying it out! I am looking to resolve this issue by replacing the play! macro with sth like this instead!

let sequence = [
    act!(
        (cube_ids[c], Transform),
        start = {transforms[c]}.scale,
        end = Vec3::splat(0.9),
    )
    .with_ease(ease::circ::ease_in_out)
    .animate(1.0),
    act!(
        (cube_ids[c], Transform),
        start = {transforms[c]}.transform,
        end = Transform::default(),
    )
    .with_ease(ease::circ::ease_in_out)
    .animate(1.0),
]
.play(&mut commands)
.all();

So we are now back to rust land and completions just works! :D I am also a huge fan of autocomplete & autoformat working hahahaha

Hmm after some experimentation, I don't think I can achieve what I mentioned above, because all types inside an array must be the same, the best I can do is sth like this:

let sequence = [
    act!(
        (cube_ids[c], Transform),
        start = {transforms[c]}.scale,
        end = Vec3::splat(0.9),
    )
    .with_ease(ease::circ::ease_in_out)
    .play(&mut commands, 1.0),
    act!(
        (cube_ids[c], Transform),
        start = {transforms[c]}.transform,
        end = Transform::default(),
    )
    .with_ease(ease::circ::ease_in_out)
    .play(&mut commands, 1.0),
]
.all();

Each play() function converts the Action to Sequence but the downside is that we will need to retype &mut commands for every action...

But I do wonder how does bevy managed to support this kind of thing in the add_systems function, basically a tuple of functions that are completely different from one another...

@musjj

ahh I found it, maybe it would be useful to use this all_tuples! macro!

macro_rules! impl_system_collection {
    ($(($param: ident, $sys: ident)),*) => {
        impl<$($param, $sys),*> IntoSystemConfigs<(SystemConfigTupleMarker, $($param,)*)> for ($($sys,)*)
        where
            $($sys: IntoSystemConfigs<$param>),*
        {
            #[allow(non_snake_case)]
            fn into_configs(self) -> SystemConfigs {
                let ($($sys,)*) = self;
                SystemConfigs::Configs {
                    configs: vec![$($sys.into_configs(),)*],
                    collective_conditions: Vec::new(),
                    chained: Chain::No,
                }
            }
        }
    }
}

all_tuples!(impl_system_collection, 1, 20, P, S);

Hey I came up with something much simpler now haha 🤣

let sequence = commands
    .add_motion(
        cube.to_scale(Vec3::splat(0.9))
            .with_ease(circ_ease)
            .animate(1.0),
    )
    .add_motion(
        cube.to_translation_x(cube.transform.translation.x + 1.0)
            .with_ease(circ_ease)
            .animate(1.0),
    )
    .add_motion(
        cube.to_rotation(Quat::from_euler(
            EulerRot::XYZ,
            0.0,
            f32::to_radians(90.0),
            0.0,
        ))
        .with_ease(circ_ease)
        .animate(1.0),
    )
    .all();

Don't mind the to_translation_x or to_rotation, you can easily replace them with the original act! macro as well. These are just motion trait functions that I created recently to simplify the creation of commonly used Actions.