animation events on last frame aren't fired in timeline when it's the last frame of the timeline

Animation events on the last frame of my animations aren't being fired when those animations are played at the end of a timeline.

Right now the activation clip for the object with the animator is flush with the end of the animation. If I extend it one frame beyond, the animation event fires. Is this expected behavior?

Yes, that is expected. Timeline is inclusive of the first frame of clips and exclusive of the last, meaning that an active clip that starts exactly at 0 and ends at exactly frame N, will be disabled at frame N.

This is done to make sure adjacent clips have predictable behaviour, and that only one is evaluated at the frame they connect at.

Note that timeline doesn't necessarily playback on frames, it is sampled based on the current clock, so if it lands anywhere between frame N-1 and N, the clip is evaluated.

@seant_unity Is there a way to get around this behaviour? I really need the last frame of the first clip to be evaluated before the next clip's first frame is evaluated.

@KristofferH The only workaround is to use override tracks and overlap the clips by one frame.

I just spent over an hour to try to get a sound clip to play, one which worked fine previously. The sound was set up to play through a function in a script, but only by an event on the very last frame of an animation clip. I eventually discovered that I could get it to work by inserting a keyframe for something else (without changing anything in the keyframe) on a frame immediately after the original last frame, where the event to play the sound function was placed.

What I don't understand is why there are three other animation clips and sound clips that I have set up in exactly the same way, that work perfectly fine, but which don't need an extra keyframe added in. The animations all have the same sample rate (bar one - not the one I was having troubles with). The sound clips all have the same loading and compression options applied. The script function is very simple, designed only to play a particular sound from an array of sounds included in the editor UI.

I came across another post that mentioned changing a setting in the audio low pass filter, but I am not using that component anywhere in my project.

Perhaps this is something Unity devs could look into, as it is inconsistent behaviour in the Mechanim timeline.

I would strongly recommend filing a bug report with repro steps, including both functioning and non-functioning clips. We would be happy to look into and fix it, but we obviously need the appropriate context to debug it.

I’ll likely submit a bug report soon as this is still not working in 2020.3 version correctly.

but in the meantime (for anyone reading this) a quick work around for this is that on the last frame you evaluate on a time which is clip length - 0.0001f

and then evaluate again but assign a modified track with all nonclip tracks muted. that way you end up in a correct state with both the Clip tracks and Animation track being in their intended last state.

_director.time = _internalTime;
            _director.Evaluate();
            _prevInternalTime = _internalTime;

            if (atEnd)
            {
                _state = PlayState.Completed;

                var asset = _director.playableAsset as TimelineAsset;
                DisableClipTracks(ref asset);

                // Bug fix
                // Timeline track will properly evaluate its animation track at max length
                // but it won't on clips: as they are seen as disabled on the last frame
                _director.playableAsset = asset;
                _director.time = _director.playableAsset.duration;
                _director.Evaluate();
            }

    private void DisableClipTracks(ref TimelineAsset asset)
    {
        for (var i = 0; i < asset.rootTrackCount; i++)
        {
            var track = asset.GetRootTrack(i);

            // skip
            if (track == null)
                continue;

            if (track.hasClips)
            {
                track.muted = true;
            }
        }
    }

To elaborate the REAL reason why a timeline clip wont give you a proper state if you Evaluate() on its last frame / Length.

Its that the timeline editor allows you to make clips which do not end on a frame but rather somewhere in-between.

This can happen easily, without modifying the values directly, just move around the clip and or drag on its ends to change the length of it.

In this example the Timeline asset has a length of a flat 5 seconds, yet 2 clips have a length of 4.99999 by just dragging them around.

This has to then be fixed manually as you can't directly set the End value of clips by code. This prevents a programmatic solution as rounding errors on the start and duration of the clip will still occur.

7106632--847585--upload_2021-5-4_17-13-40.png

1 Like