Blend trees + Animation Events

When you use animations with events inside a blend tree, all events will trigger no matter which blend tree’s animation is running at the moment. Is there a way to avoid this?

Nope. The same is true when you have multiple animations active during a transition.

The only workaround I know of is to give each event a parameter to identify the clip its coming from and use that to filter out the ones you don’t want. It’s not at all a good solution, but I don’t know of anything better.

I was just fiddling around with some events and it turns out I was wrong.

If you give your receiver method an AnimationEvent parameter, Unity will give it all the details of the event which can be used to access the clip and its weight. So your method will always get triggered, but you can just ignore any events with 0 weight if you want to.

Edit: note that this will allocate some garbage every time the event is invoked. The same applies to string parameters, but not the other types.

4 Likes

Sorry to revive such an old thread, but I’m having this same issue. The solution above is interesting, but the thing about it is that often the weight will not be 0. There might even be a point where both animation from and to have weights of 0.5 while blending. So the undesired event from the previous animation will still go through. I’m trying to find an elegant solution to this, but have not had any luck so far. Telling it to ignore any weights less than 1 will filter out all the old animation’s stuff, but it will also filter out any events that occur in the new animation while that’s blending in. I wish there was a way to determine if the clip is a “To” clip or a “From” clip. Like just getting its position in the transition itself. I’ve not been able to find anything for that yet though.

Edit: One hacky solution I found was using something like this:

if (animationEvent.animatorStateInfo.normalizedTime > 0.5f && animationEvent.animatorClipInfo.weight < 1)
                return;

So kind of like saying “if we’re in the latter half of an animation and yet somehow its weight is less than 1, we assume we’re transitioning out of it”. How good and durable that assumption is, well… that’s what makes it a less than ideal solution. It’s possible it will break if things are going fast enough.

2 Likes

Yeah, I never found a better solution in the standard Animation Events system and ended up implementing my own event system in Animancer which only triggers events from the current animation by default. Surely you have access to something less hacky than time though, since that would only work reliably for exit time transitions and not any sort of interruptions.

1 Like

Hey, try this one. Call it from the AnimationEvent.
If you want to aim for performance, cache the heaviest clip, compare each Animation Event Clip with the heaviest clip

void DodgeEnd(AnimationEvent evt) {
    if (IsHeaviestAnimClip(evt.animatorClipInfo.clip)) { 
        // Only called by the highest weighted clip from the blendtree
    }
}
bool IsHeaviestAnimClip(AnimationClip currentClip) {
    var currentAnimatorClipInfo = _animator.GetCurrentAnimatorClipInfo(0);
    float highestWeight = 0f;
    AnimationClip highestWeightClip = null;
            
    // Find the clip with the highest weight
    foreach (var clipInfo in currentAnimatorClipInfo) {
        if (clipInfo.weight > highestWeight) {
            highestWeight = clipInfo.weight;
            highestWeightClip = clipInfo.clip;
        }
    }
            
    return highestWeightClip != null && currentClip == highestWeightClip;
}
4 Likes

WOW THANK YOU

It seems you had exactly the same problem I was having and found a solution (I’m also implementing a 360 dodge implementation using blend animations).

1 Like

very helpful for me, thank you!

1 Like