added some simple functions to AnimationPlayer#5912
added some simple functions to AnimationPlayer#5912asafigan wants to merge 4 commits intobevyengine:mainfrom
Conversation
|
I changed it to an option which was a really simple change. |
| if elapsed < 0.0 { | ||
| elapsed += animation_clip.duration; | ||
| } else if elapsed > animation_clip.duration { | ||
| player.finished = true; |
There was a problem hiding this comment.
Shouldn't this information (player.finished) be used to avoid calculating the elapsed time over and over again?
like add it together if paused check:
if player.finished || (player.paused && !player.is_changed()) {
continue;
}There was a problem hiding this comment.
Well I think:
if (player.paused || player.finished) && !player.is_changed() {
continue;
}would be more correct with this implementation, because some field like repeat could have changed.
|
I have a change stashed locally that does this and a bit more, but it's not finished yet because it's actually a bit more complicated than that. I don't think this PR handles animations being played backward, repeating animations or setting the |
|
So for playing backward. It looks like the animation will repeat even if In this PR, repeating animations never finish. The correctness of this is up to debate. Setting elapsed manually has a one frame delay before Which of these would you like me to work on? |
I actually haven't found yet a fix that makes me happy, which is why I didn't open the PR. Try some things, let's see how it works out 😄 Another thing about repeat that I don't like if you have ideas on how to fix: setting repeat to false on a currently playing and repeating animation should let the current loop finish before stopping. This is currently true if done during the first repeat, not during others |
After a deeper look this is actually incorrect. I will set up so test cases and iterate over some solutions. |
|
What should the behavior of a non-repeating animation player with a negative speed at time 0? Should it stay on the first frame or should it play the entire animation backwards. What should happen if speed is negative with any positive time? Should you have to set the time to the duration of the animation to play it once backwards? What if you want to play it forward and then backward? With the current implementation, it seems like a non-repeating animation with negative speed set to the duration of the animation will play the animation backward twice. Also I find it odd that the elapsed time goes up (or down if negative) forever. This is also weird because a non-repeating backward animation with an elapsed time greater than the duration of the animation will be on the last frame for a period of time before playing the animation backward (twice). |
james7132
left a comment
There was a problem hiding this comment.
LGTM other than this one nit.
| ) { | ||
| for (entity, mut player) in &mut animation_players { | ||
| if let Some(animation_clip) = animations.get(&player.animation_clip) { | ||
| if let Some(animation_clip) = player.animation_clip().and_then(|x| animations.get(x)) { |
There was a problem hiding this comment.
I'd actually prefer for us to use let ... else with continue here instead of and_then inside the if expression.
IMO, we should treat non-repeating behavior as a clamp on the time modulus the length of the clip. If it's not repeating and the speed is negative, we should play to the beginning then mark it finished. This is essentially playing the clip backwards, and allows users to ping-pong the clip if they so desire. It's the least surprising interaction between these two features. |
|
@asafigan can you resolve the merge conflicts? I'd like to get this moving again and they're more complex than I want to tackle in the web UI :) |
|
@DevinLeamy your review here would be welcome, since you're building on it. |
I'm on board with the changes here! IMO it probably would be easiest to patch them into #9002. @alice-i-cecile Any opposition to doing that? |
|
No objections; just credit the original author at the top of your PR description :) |
Of course! It's been updated. |
|
Updated and incorporated into #9002. Thanks a ton for your work, and if you get a chance your review there would be welcome! |
# Objective Added `AnimationPlayer` API UX improvements. - Succestor to #5912 - Fixes #5848 _(Credits to @asafigan for filing #5848, creating the initial pull request, and the discussion in #5912)_ ## Solution - Created `RepeatAnimation` enum to describe an animation repetition behavior. - Added `is_finished()`, `set_repeat()`, and `is_playback_reversed()` methods to the animation player. - ~~Made the animation clip optional as per the comment from #5912~~ > ~~My problem is that the default handle [used the initialize a `PlayingAnimation`] could actually refer to an actual animation if an AnimationClip is set for the default handle, which leads me to ask, "Should animation_clip should be an Option?"~~ - Added an accessor for the animation clip `animation_clip()` to the animation player. To determine if an animation is finished, we use the number of times the animation has completed and the repetition behavior. If the animation is playing in reverse then `elapsed < 0.0` counts as a completion. Otherwise, `elapsed > animation.duration` counts as a completion. This is what I would expect, personally. If there's any ambiguity, perhaps we could add some `AnimationCompletionBehavior`, to specify that kind of completion behavior to use. Update: Previously `PlayingAnimation::elapsed` was being used as the seek time into the animation clip. This was misleading because if you increased the speed of the animation it would also increase (or decrease) the elapsed time. In other words, the elapsed time was not actually the elapsed time. To solve this, we introduce `PlayingAnimation::seek_time` to serve as the value we manipulate the move between keyframes. Consequently, `elapsed()` now returns the actual elapsed time, and is not effected by the animation speed. Because `set_elapsed` was being used to manipulate the displayed keyframe, we introduce `AnimationPlayer::seek_to` and `AnimationPlayer::replay` to provide this functionality. ## Migration Guide - Removed `set_elapsed`. - Removed `stop_repeating` in favour of `AnimationPlayer::set_repeat(RepeatAnimation::Never)`. - Introduced `seek_to` to seek to a given timestamp inside of the animation. - Introduced `seek_time` accessor for the `PlayingAnimation::seek_to`. - Introduced `AnimationPlayer::replay` to reset the `PlayingAnimation` to a state where no time has elapsed. --------- Co-authored-by: Hennadii Chernyshchyk <genaloner@gmail.com> Co-authored-by: François <mockersf@gmail.com>
# Objective Added `AnimationPlayer` API UX improvements. - Succestor to bevyengine#5912 - Fixes bevyengine#5848 _(Credits to @asafigan for filing bevyengine#5848, creating the initial pull request, and the discussion in bevyengine#5912)_ ## Solution - Created `RepeatAnimation` enum to describe an animation repetition behavior. - Added `is_finished()`, `set_repeat()`, and `is_playback_reversed()` methods to the animation player. - ~~Made the animation clip optional as per the comment from bevyengine#5912~~ > ~~My problem is that the default handle [used the initialize a `PlayingAnimation`] could actually refer to an actual animation if an AnimationClip is set for the default handle, which leads me to ask, "Should animation_clip should be an Option?"~~ - Added an accessor for the animation clip `animation_clip()` to the animation player. To determine if an animation is finished, we use the number of times the animation has completed and the repetition behavior. If the animation is playing in reverse then `elapsed < 0.0` counts as a completion. Otherwise, `elapsed > animation.duration` counts as a completion. This is what I would expect, personally. If there's any ambiguity, perhaps we could add some `AnimationCompletionBehavior`, to specify that kind of completion behavior to use. Update: Previously `PlayingAnimation::elapsed` was being used as the seek time into the animation clip. This was misleading because if you increased the speed of the animation it would also increase (or decrease) the elapsed time. In other words, the elapsed time was not actually the elapsed time. To solve this, we introduce `PlayingAnimation::seek_time` to serve as the value we manipulate the move between keyframes. Consequently, `elapsed()` now returns the actual elapsed time, and is not effected by the animation speed. Because `set_elapsed` was being used to manipulate the displayed keyframe, we introduce `AnimationPlayer::seek_to` and `AnimationPlayer::replay` to provide this functionality. ## Migration Guide - Removed `set_elapsed`. - Removed `stop_repeating` in favour of `AnimationPlayer::set_repeat(RepeatAnimation::Never)`. - Introduced `seek_to` to seek to a given timestamp inside of the animation. - Introduced `seek_time` accessor for the `PlayingAnimation::seek_to`. - Introduced `AnimationPlayer::replay` to reset the `PlayingAnimation` to a state where no time has elapsed. --------- Co-authored-by: Hennadii Chernyshchyk <genaloner@gmail.com> Co-authored-by: François <mockersf@gmail.com>
Objective
Fixes #5848.
Solution
animation_clipfromAnimationPlayerwhile documenting that it could be the default handle.animation_clip.The language used to explain what the default handle implies could be more clear. My problem is that the default handle could actually refer to an actual animation if an
AnimationClipis set for the default handle, which leads me to ask, "Shouldanimation_clipshould be anOption?"