- Modificato
Complete event wierdness
Hello
I am using the latest unity runtimes + new animationstate from pharan (question in runtimes because more of a runtime design question)
there are a few wierd behaviours that I have not noticed in other runtimes, or just didn't happen and I'm not sure which.
Firstly, The complete event fires after every loop.
Also, the interrupt event fires after the complete event on a non looping animation.
The below code is a check for when an animation ends:
private void AnimationComplete(TrackEntry trackEntry)
{
if (!trackEntry.Loop)
{
m_History.Add(new EntryData(trackEntry, Time.time, Time.time - trackEntry.TrackTime));
m_MoveScrollpos = true;
}
}
private void AnimationInterupt(TrackEntry trackEntry)
{
if (!trackEntry.IsComplete || trackEntry.Loop)
{
m_History.Add(new EntryData(trackEntry, Time.time, Time.time - trackEntry.TrackTime));
m_MoveScrollpos = true;
}
}
note the convoluted checks to see if it really fired (I had to repeat this pattern a lot when I upgraded the runtimes)
So my questions really is, should the complete
event fire on every loop of an animation, should the interrupt
event fire after a complete
event? And is there a better way to get when an animation end? (not End
event, as that fires too late, iirc depending on the mix)
The docs detail exactly when events are fired:
complete
: Invoked every time this entry's animation completes a loop.
interrupt
: Invoked when another entry has replaced this entry as the current entry. This entry may continue being applied for mixing.
BinaryCats ha scrittoSo my questions really is, should the complete event fire on every loop of an animation
Yes. See above.
BinaryCats ha scrittoshould the interrupt event fire after a complete event?
See above, interrupt
fires when the animation is no longer the current animation for the track. Whether this happens before or after complete
depends on when you are setting the next animation (or clearing the track).
BinaryCats ha scrittois there a better way to get when an animation end?
What do you mean by "when an animation end"? There's the animation duration, the track end time, the delay for when the next queued animation will be played, the end
event, etc. If someone runs some code to play a new animation or clear a track, the current animation for the track can end at any time, in which case its not something you can know about beforehand. If you just want notifications about what is happening on the tracks, use AnimationStateListener.
PS, interrupt has two Rs.
Ah, its strange how this hasn't come up before now :s , the track end time
has just exposed this design.
I would say an animation ends when the data gets added to the m_history
above. there are a few times where we want something to happen to a gameobject when an animation completes/interrupted, but there isn't an event for that, you have to do use hook into both events and do the above checks.
I don't understand. Many events are provided, such as when an animation completes a loop (complete
) or when it is no longer the current animation (interrupt
). Your checks don't make sense to me since I don't know what you are trying to achieve.
but complete
also fires when the animation is played fully, and then the queued animation will will.
how do you know the difference?
I thought, interrupt
only fires if the animation was unable to complete because a new animation was set on the track.
setanimation("a",0,false);
addanimation("b",0,false,nodelay);//a->b mix = 0
complete
will fire just before/sameframe as "b"
starts
interrupt
will not fire as "a" was allowed to complete
setanimation("a",0,false);
//wait 1 second
setanimation("b",0,false);//a->b mix = 0
complete
will not fire because it did not complete
interrupt
will fire as "a" was interrupted by "b"
this is how I thought it worked. Maybe that changed with the latest runtimes, because trackend
is #inf
, so a completed animation would also be a interrupted animation.
BinaryCats ha scrittobut complete also fires when the animation is played fully
It fires when a loop is completed and for absolutely no other reason. Note you can set TrackEntry animationStart
and TrackEntry animationEnd
to loop a portion of an animation and complete
fires on each loop.
BinaryCats ha scrittoI thought, interrupt only fires if the animation was unable to complete because a new animation was set on the track.
It fires when "another entry has replaced this entry as the current entry". Nothing in AnimationState cares how many loops an animation has completed except for firing the complete
event.
If you care about when an animation is done playing, you can listen for interrupt
to know the animation is mixing out because another animation was played. You can also listen for end
to know the animation has been mixed out completely.
If you use trackEnd
or you clear a track, you'll get end
with no interrupt
, since a new animation was not set. Maybe we should improve interrupt
by having it having it fire any time the track entry is no longer the current track entry, whether that is because a new animation was set, trackEnd
, or clearTrack
. Thoughts?
ah it seems you are correct, listening to complete
is pointless, I should just listen to interrupt
and that catches all cases except trackend
and cleartrack
. Those two exceptions would explain bugs we have been having!
I feel we should be using these events more in our codebase (to be fair). but legacy systems are a bitch to change. currently we check for animations like this
public bool IsAnimationPlaying(int track)
{
Spine.TrackEntry entry = m_Animation.state.GetCurrent(track);
return (entry != null && ( entry.Loop || !entry.IsComplete ) );
}
(it use to be a null check but now trackend
is big the two other checks are needed
public bool IsAnimationPlaying(string name, int track)
{
Spine.TrackEntry entry = m_Animation.state.GetCurrent(track);
if (entry != null)
{
if (!entry.Animation.Name.Equals(name))
return false;
else if (entry.loop)
return true;
else
return !entry.IsComplete;
}
else
return false;
(eww string checks)
It doesn't have to be a string compare.
Pharan ha scritto
How else can it be done?
Need a link between the data (animation name, set in editor) and the trackentry. I didn't think string.gethashcode()
would be guaranteed because its compiled separately
You could cache the Animation object reference in whatever method or object is calling IsAnimationPlaying. Then reference compare.
that would be a pain in the ass to do because of the previous implementations :bang: I have thought about doing it before though
We also sometimes want to wait until an animation is playing, :bang: Basically I want to re-write our spine implementation as is wasn't written by me lol
I guess I could do a check trackentry.animation
rather than trackentry
though :wonder: