- 수정됨
Wrong frame of animation
Good day all.
Have a trouble that I cannot understand at the moment. I have three animations. Let them be called "A", "B" and "AtoB" transition. I need to play them smoothly as "A"->"AtoB"->"B". The problem is that this sequence looks good only from time to time. Almost every run of this sequence there is one wrong frame of animation right before "B" animation starts playing. So in most cases it looks like "A"->"AtoB"->"wrong frame"->"B". The wrong frame looks like the first frame of "AtoB" animation. The most confusing for me is the fact that sometimes in the same situation this sequence looks cool - like it should be.
At the moment logic is:
- I have animation "A" looped
- in some moment requested to play animation "B"
- wait for animation "A" complete event
- play animation "AtoB"
- wait for animation "AtoB "complete event
- play animation "B"
I have a strong suspicion that I missed something obvious and need an advice :bang:
Have you Check a Skeleton Data's Mix Settings?
If you intended them to have no animation blending/animation crossfading, make sure you set the mix durations to 0.
As bonelethita mentioned, this can be found in the SkeletonData asset inspector.
Thx for the reply. Ok. More info. Set zero as default mix duration from the beginning. Because auto-mixing is not cool when animation "A" is sitting and "B" is standing.
The main problem is that sometimes this sequence looks perfect. Without any changes in code/settings.
Anyone? =\
That's the only reason I can think of that would affect the transition between animations.
Setting the mix to 0 ensures AnimationState doesn't do any mixing, which might show any pose other than what you keyed in Spine.
Could there be something else in your code affecting this? Or is there something special about your setup that might be affecting this that you did not mention?
I'll try to provide full info.
As I mentioned before, I have an animation sequence. The full needed algorithm is described in the first post. Additional info - I have to count animations (for example, I have to repeat animation B for N times, then begin new transition), that's why I am using SetAnimation, not AddAnimation.
I am playing animation like:
_animation.AnimationState.SetAnimation(0, animationName, true);
_animation is SkeletonGraphic.
If animation is looped and I need to count the number of repetitions, I use this code to subscribe to animation complete event:
_animation.AnimationState.Complete += OnAnimationComplete;
In OnAnimationComplete callback I check current animation requested repeat count left and if it reaches zero, unsubscribe from animation complete event:
_animation.AnimationState.Complete -= OnAnimationComplete;
If there is next animation defined in sequence, the procedure is repeated with next animation.
So, for "transition from animation A to animation B using animation AtoB" algorithm is:
- Wait for complete animation A
- Start animation AtoB and subscribe complete event
- In the OnAnimationComplete callback unsubscribe complete event and start animation B
- If I need to repeat animation B for the defined number of times, subscribe to animation complete event
etc.
The bug is visual and looks like the first frame of AtoB animation at the moment when animation B should begin. And, as I said before, the most confusing is the fact, that from time to time, the animation sequence looks great, as it should be.
This is settings of skeleton, used for animations to prevent questions about mix durations:
The Complete
event is raised during the AnimationState.Apply when when the AnimationState detects that the time has gone beyond the duration of the animation during the last AnimationState Update. This is the same time when the animation pose is applied to the skeleton.
The tl;dr of it is that setting a new animation in Complete means you set a new animation after the phase where the skeleton is posed. So the previous animation will still be visible.
If you played the first animation in a loop, a pose closer to the start of the first animation to the start may be visible (because it started looping again) will be visible for one frame. How visible this is can vary just based on the time before Complete and the deltaTime during that frame, which may explain why you sometimes see it and why sometimes you don't.
A remedy for this visually is probably an extra AnimationState.Apply(skeleton)
call after the SetAnimation call.
This is normally not a problem when you play looping animations in a loop, and non-looping animations not in a loop.
While you sensibly wouldn't be playing non-looping animations in a loop, having that extra frame or not having the pose immediately applied might be a concern elsewhere. I'll discuss this with the team and see what the recommendation is. But I have a feeling it would be the same: Just call AnimationState.Apply.
If this wasn't the case in your code, it might be something else, but this was as much as I could glean from what you described.
- 수정됨
Thanks a lot! I used the common rule: "always play looped", set amount of times to repeat and counted it.
Both variants:
_animation.AnimationState.SetAnimation(0, animationName, (repeatCount != 1));
and
_animation.AnimationState.SetAnimation(0, animationName, true);
_animation.AnimationState.Apply(_animation.Skeleton);
work as I wanted to. Is there any critical difference between them in depth? As it will be called very often, at the moment left the first variant, but do not like the magic number =\
Thanks one more time for help
I think 0
and 1
are innocuous if you literally mean none or once. It would be weird and redundant to declare a const that's like:
const int PlayOnce = 1;
Alternatively, you could go:
bool loop = repeatCount > 1;
Anyway. Either one works. The difference is that the first one has a one-update delay before it starts showing your animation. If your animation is just purely visual, it should be fine. Some people rely on the skeleton for game logic (which I don't agree with but really, it's their game, and sometimes it's just the most practical way to go) so option 1 may not be for them.
The second one just has an extra Apply for that frame. It means the skeleton is posed twice in that frame. If you have a large number of instances of this skeleton, or this skeleton has an insane number of bones and that animation has an equally insane number of keys, this may become a problem. Otherwise, it's fine.
ps
The arg in the second one should actually be _animation.Skeleton