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

Adding new tweens to existing ones #115

Open
musjj opened this issue Jan 22, 2024 · 5 comments
Open

Adding new tweens to existing ones #115

musjj opened this issue Jan 22, 2024 · 5 comments
Labels
enhancement New feature or request

Comments

@musjj
Copy link

musjj commented Jan 22, 2024

Let's say I have an entity that is set up with a tween targeting the entity's transform.rotation. The tween loops infinitely throughout the game.

But I also want to have a system that can insert a new tween that targets said entity's transform.scale, depending on the state of the game. The tween loops only once. I also want to be able to replay that tween, depending on the game state.

The problem is that this requires you to put more than one Animator<Transform> component on the entity, which is currently not possible in Bevy. Is there a good solution for this use-case?

@SecretPocketCat
Copy link
Contributor

You could use tracks, but you'd have to recreate the looping tween which would be tedious.
A simple-ish approach would be to add a wrapper that can have it's own animator which can do the rotation.

@guyguy2001
Copy link
Contributor

A similar need I have (I'm not sure if this should go here or in a new issue) is to tell a tween to run after the current tween.
So for example, when my player is hit, I want them to flash red, and afterwards start animating their alpha to indicate an invulnerability state.
(This might not be the correct way to approach the problem, I'm not sure yet).

To do this I need one of the following:

  • A .then(self, &tween) method on the Tweenable trait, and a way of owning animator.tweenable() in order to be able to call it (since Sequence::then only accepts an owned self, not a reference)
  • A .then method on the animator itself (which will probably use the .then I suggested)
  • A way of passing animator.tweenable() into Sequence::from_single (or ::new or the likes).

I also need a way to know when the current animation will end - but I think I can get that via the existing total_duration, which seems great

The second option is probably the best one, but I'm too new to writing APIs in rust to have a clear idea.
Also, I could see a world in which it is just a bad idea to allow enqueuing more animations from the outside.

@djeedai
Copy link
Owner

djeedai commented Apr 24, 2024

@musjj sorry I completely missed this issue.

The problem is that this requires you to put more than one Animator component on the entity, which is currently not possible in Bevy. Is there a good solution for this use-case?

Yes indeed. So you're stuck with a single animator, unless you can reparent your scaled object to an invisible rotating one? If not, then the way I'd approach it in this case given the two animations are widely different is to put the logic into a custom Lens, where you always apply the rotation, and conditionally apply the scaling when needed. You will need to use some form of Arc to share the lens (or some of it's fields) with the animator. And it's a bit awkward if the scaling doesn't start in sync with the rotation nor has the same duration, but you can figure some delayed t value inside the lens from the first time the scaling is activated I think. Definitely more complex than it should, but I don't see a good solution at least until we have dynamic queries in Bevy ECS.

@djeedai
Copy link
Owner

djeedai commented Apr 24, 2024

@guyguy2001

So for example, when my player is hit, I want them to flash red, and afterwards start animating their alpha to indicate an invulnerability state.

I'm not sure I understand. It seems that you want to animate first the color and then the alpha of the same material or sprite? If so, you can just use Tracks and enqueue two Tweens one after the other.

If, on the other hand, you're trying to execute a tweenable on one Animator and synchronize it with another tween on a different Animator, then yes there's no good built-in solution for this. One workaround I can think of is if you know the duration of each individual tweenable, you can insert delays to indirectly synchronize them based on time.

@djeedai djeedai added the enhancement New feature or request label Apr 24, 2024
@musjj
Copy link
Author

musjj commented Sep 15, 2024

I think a simple solution would be to allow Animator to target an entity other than itself. For example:

Animator::new(tween).with_entity(entity)

This way you can just spawn multiple animator entities targeting the entity you want. This is similar to the approach used by bevy_tween, except that it traverses up the parent hierarchy until it finds a target marker.

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

4 participants