Problem solved, and the problem was... me.
Hello,
I've just updated the Spine runtime (Unity c#) and the EndEvent is not throwed anymore if the animation is complete.
I think that the problem is on AnimationState.cs, around the line 110 and line 550
I just uncomment the last part of the trackEnd = [...] and it works again. Is it normal that this code is commented ?
Thanks.
AnimationState / part 1
// Clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom.
if (current.trackLast >= current.trackEnd && current.mixingFrom == null)
{
tracksItems[i] = null;
queue.End(current);
DisposeNext(current);
continue;
}
AnimationState / part 2
entry.trackEnd = float.MaxValue; // loop ? float.MaxValue : animation.Duration;
Also, it seems that there is another bug in the AnimationState / part 1 that I wrote above.
This code seems better, as the trackTime need to be updated with the currentDelta to know if the endTime has been reached. (I also added the complete event)
// Clear the track when there is no next entry, the track end time is reached, and there is no mixingFrom.
if (current.trackTime + currentDelta >= current.trackEnd && current.mixingFrom == null)
{
tracksItems[i] = null;
queue.End(current);
queue.Complete(current);
DisposeNext(current);
continue;
}
Also, around the line 410, the End event is not throwed if current.nextTrackLast is different than -1 and no mix need to be applied.
public TrackEntry SetAnimation (int trackIndex, Animation animation, bool loop)
{
if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null.");
bool interrupt = true;
TrackEntry current = ExpandToIndex(trackIndex);
if (current != null)
{
if (current.nextTrackLast == -1)
{
// Don't mix from an entry that was never applied.
tracks.Items[trackIndex] = current.mixingFrom;
queue.Interrupt(current);
queue.End(current);
DisposeNext(current);
current = current.mixingFrom;
interrupt = false;
}
else
{
DisposeNext(current);
}
}
TrackEntry entry = NewTrackEntry(trackIndex, animation, loop, current);
SetCurrent(trackIndex, entry, interrupt);
queue.Drain();
return entry;
}
my modification :
public TrackEntry SetAnimation (int trackIndex, Animation animation, bool loop) {
if (animation == null) throw new ArgumentNullException("animation", "animation cannot be null.");
bool interrupt = true;
TrackEntry current = ExpandToIndex(trackIndex);
if (current != null)
{
bool mixDurationZero = data.GetMix(current.Animation, animation) == 0f;
if (current.nextTrackLast == -1 || mixDurationZero)
{
// Don't mix from an entry that was never applied.
tracks.Items[trackIndex] = current.mixingFrom;
queue.Interrupt(current);
queue.End(current);
DisposeNext(current);
if(!mixDurationZero)
{
current = current.mixingFrom;
}
interrupt = false;
}
else
{
DisposeNext(current);
}
}
TrackEntry entry = NewTrackEntry(trackIndex, animation, loop, current);
SetCurrent(trackIndex, entry, interrupt);
queue.Drain();
return entry;
}
I also change the Queue in AnimationState. The trackEntry were disposed just after that the EndEvent were throwed. It
doesn't work if the CompleteEvent has to be throwed at the same frame.
Here is my code :
private List<TrackEntry> m_disposeList = new List<TrackEntry>();
public void Drain () {
if (drainDisabled) return;
drainDisabled = true;
var entries = this.eventQueueEntries;
var entriesItems = entries.Items;
AnimationState state = this.state;
for (int i = 0, n = entries.Count; i < n; i++) {
var queueEntry = entriesItems[i];
TrackEntry trackEntry = queueEntry.entry;
switch (queueEntry.type) {
case EventType.Start:
trackEntry.OnStart();
state.OnStart(trackEntry);
break;
case EventType.Interrupt:
trackEntry.OnInterrupt();
state.OnInterrupt(trackEntry);
break;
case EventType.End:
trackEntry.OnEnd();
state.OnEnd(trackEntry);
m_disposeList.Add(trackEntry);
break;
case EventType.Dispose:
disposeTrackEntry(trackEntry);
break;
case EventType.Complete:
trackEntry.OnComplete();
state.OnComplete(trackEntry);
break;
case EventType.Event:
trackEntry.OnEvent(queueEntry.e);
state.OnEvent(trackEntry, queueEntry.e);
break;
}
}
int c = m_disposeList.Count;
for (int i=0; i< c; i++)
{
disposeTrackEntry(m_disposeList[i]);
}
m_disposeList.Clear();
eventQueueEntries.Clear();
drainDisabled = false;
}
private void disposeTrackEntry(TrackEntry trackEntry)
{
trackEntry.OnDispose();
state.OnDispose(trackEntry);
trackEntryPool.Free(trackEntry); // Pooling
}