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

Allow Animator to target other entities #136

Merged
merged 5 commits into from
Dec 10, 2024

Conversation

patrickariel
Copy link
Contributor

@patrickariel patrickariel commented Nov 24, 2024

This adds an optional property to Animator that stores an entity.
If the property contains a value, it will be used as the target of the animation. Otherwise, the Animator's entity will be used (default behavior).

This makes the creation of complex, modular tweens much easier. For example, you can now have one animator entity tweening Transform::translation and the other tweening Transform::rotation. Previously, this would have to be done with a single animator, which is very inflexible.

They can be used like this:

let sprite = commands.spawn(
    SpriteBundle {
        sprite: Sprite {
            color: Color::RED,
            custom_size: Some(Vec2::new(size, size)),
            ..default()
        },
        ..default()
    },
).id();

// This animator will animate the previously spawned entity
commands.spawn(Animator::new(tween).with_target(sprite));

This adds an optional property to `Animator` that stores an entity. If
the property contains a value, it will be used as the target of the
animation. Otherwise, the `Animator`'s entity will be used (default
behavior).
This makes it so that the user can easily set/unset it later on.
@djeedai
Copy link
Owner

djeedai commented Dec 9, 2024

This makes the creation of complex, modular tweens much easier. For example, you can now have one animator entity tweening Transform::translation and the other tweening Transform::rotation. Previously, this would have to be done with a single animator, which is very inflexible.

I don't understand this rationale. Either you want to animate both translation and rotation at the same time, and then you use a combined Lens. Or you want to have completely unrelated translation and rotation, for example your object moves along some kind of trajectory, and also spins on itself, and chances are that's because you conceptually have 2 different objects and should have 2 different entities, with one parented to the other (the spinning child entity parented to the trajectory entity).

Can you please provide some detailed example where that feature is useful? I'm all for adding new features, but this makes the code more complex, adds some indirection query, for a result which it seems can be achieved without any change.

@patrickariel
Copy link
Contributor Author

Yes, that particular example can be worked around by re-parenting, but my general rationale is that you sometimes want to target different fields of the same component via different animators.

For example, let's say I want to create a button with a pulsing border width that loops indefinitely (as a way to attract player attention). I would need to insert an Animator<Node> that targets Node::border. Now when the user hovers over the button, I want it to bounce up a bit. This requires inserting another temporary Animator<Node> that targets Node::bottom. But of course, this isn't possible in ECS.

Maybe in a perfect world, components will always be split up in such a granular way that a problem like this will never happen. But in messy, complex scenarios, something like this will eventually be a problem. Especially when dealing with external libraries that you can't control. And when the time comes, you want your users to have the power to deal with it.

As a precedent, bevy_eventlistener had a similar issue. The problem was that the event handler entity and the event target entity was coupled. This means that you can't put more than one handler component per event type in the target entity.

But when it was upstreamed as observers, this problem was solved by decoupling the observer entity and the observed entity. So now an entity can have any number of observers of the same event type.
This library is currently also having the exact same issue: the animator entity and the animated entity is coupled together, creating problems like mentioned above.

Another limitation I've found is that you can't animate more than one component per animator. Which means that it's hard to make tween sequences that alternates between different components. Of course, something like this will require a massive rework, so it's pretty unlikely that it can be done in this library.

As a comparison, tweening APIs from other game engines don't have any of the above limitations: see Godot, Unity, etc.

For the reasons above I've since moved to bevy_tween, which solved most of my gripes. So if you think this PR is out of place, I'm completely fine with it being closed 🙂

@djeedai djeedai merged commit b0bae2a into djeedai:main Dec 10, 2024
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants