-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Description
Note: This could be considered either a bug report or a feature request. I'm labeling this as a bug report because this used to work before #15677 landed.
tl;dr: Bevy animation events fire when animations are progressed via play
, but not when progressed manually via pause
+ seek_to
.
Bevy version and features
0.17.0-rc-1, though this has existed since 0.16 or earlier as well.
Background
There are two approaches to animation for games:
- Time-based animation. This is the most common approach and is the one used in all of Bevy's example code. Given an animation, at some point a
.play()
method is called, and the animation automatically progresses over time, possibly on a loop or with a simple speed multiplier. - Frame-by-frame animation. Under this method, given an animation, some code that runs each frame manually sets the desired frame or timestamp.
Time-based animation is usually the go-to, but there are times when frame-by-frame animation is needed. If animations need to be frame-perfect, synchronized over the network, variable based on gameplay mechanics, procedural, or able to be reversible or skip frames, then animations need frame-by-frame control. For example, fighting games use this since the displayed animation frame needs to be perfectly in sync with hitboxes, network delays, etc. Or a platformer game might manually set "jump" animation frames based on the character's vertical velocity or distance from ground.
You can do time-based animations in Bevy using AnimationPlayer
's play
method. Or, you can do frame-by-frame animations by keeping an animation paused and using AnimationPlayer's seek_to
or set_seek_time
methods.
What you did
I modified the animated_mesh_events
example to use frame-by-frame animations instead of time-based animations to demonstrate the issue. See the code here: hansler@e7ba0fe
Just to show a close-to-real-world example, I tied the animation's speed to a sin wave that varies from 10% to 300% over time.
What went wrong
The animation works fine this way, but animation events don't fire. I think animation events (or at least #15677) are assuming that all animations done with AnimationPlayer are time-based, not frame-by-frame. If I revert the two lines of code changed in #15677 (which my branch does here: hansler@e7ba0fe), then events work again.
Current state:
2.mp4
With #15677 reverted:
1.mp4
#15677 was intended to fix a different bug: paused animations causing events to fire every frame if paused at just the right moment. I think we need a way to fix that bug while still allowing "paused" animations to fire events so we can support animations which progress via seek_to
rather than play
.
As an aside, there is some API weirdness when manually advancing animations frame-by-frame that you can see in my example code. For example, you need to initially start the animation using player.play(animations.index).pause();
, because play
sets the animation as active (which we want) and also starts the animation (which we don't want). So beyond this bug I think there might be room for API improvements for this use-case.