[SOLVED] Anim: triggering initial state leads to unexpected behaviour

Hey,

I have recently been working a lot with animation state graphs and discovered some weird behavior. In all my state graphs I start with the idle state going on loop (with a transition from the “start” node). However, in some cases I have had the need to trigger the idle state again at some later stage, so I set up a transition from the “any” node to the idle sate, with the condition trigger “idle”. See picture:

Triggering the idle animation with:

this.entity.anim.setTrigger('idle');

which works fine… usually.

It seems to break the whole animation setup if it is triggered when the idle animation is already playing. This can take the form of consecutive states not to playing properly, or the whole character just freezing up completely.

A quick fix could be something like:
if(!this.entity.anim.getTrigger('idle')) this.entity.anim.setTrigger('idle')

However, since the idle animation are playing from the beginning there will be cases when it is playing even if the trigger is not set to true yet, making this fix only work in some cases.

That this setup can break the whole animation graph seems to me like a bug in the engine. Anyone else had this problem? Any suggestions for a better quick fix?

1 Like

Hi @Astra!

It sounds like it’s related to my feature requests below. Can you check this please?

hmm… it might be somewhat related… but the problem is not that the idle animation is interrupted and start playing again from the beginning when you trigger it, which is what is sounds like that issue was about. The trouble is that triggering the initial state when it is already playing actually makes everything else stop working. In the sense that no other animations can be triggered later on.

That doesn’t sound right indeed. Are you be able to share your project so someone can take a look?

hmm… its a new feature for my company… so don’t think so, but I can make a new project and reproduce it quick.

Perfect! :ok_hand:

Ok, so. I set up the project, and got some of the strange behavior. However, I think I might have been somewhat incorrect with my initial assessment. It seems that it doesn’t rly have anything to do with the initial state or “start state”. But rather if you trigger an animation twice, the next new animation you trigger will not play correctly.

The project can be found here.

Thank you.

I found some other reported issues that may be related.

Can please take a look at this @Elliott?

I had a look. It’s similar, but I don’t think its the same as any of the issues reported there.

Hi @Astra, trigger parameters are consumed when a transition that uses it in one of its conditions is activated. If you set an ‘idle’ trigger while in the Idle state, that trigger will exist until a transition becomes available that can consume it. Checking that the graph isn’t currently in the idle state before setting the idle trigger parameter would stop the graph reentering that state on exit:

if (this.entity.anim.baseLayer.activeState !== 'Idle') this.entity.anim.setTrigger('idle')

2 Likes

k, thx!!
That makes sense.

But why is it like that? At least in the case where you try to trigger a state that’s already playing, would you ever want it to “queue up”?

If a user pressed a jump key right at the end of the current jump animation, you may want to still queue that user action up. In that case you can use something like:

if (this.entity.anim.baseLayer.activeState !== 'Jump' || this.entity.anim.baseLayer.activeStateProgress > 0.9) {
    this.entity.anim.setTrigger('jump');
}

Aaaa… ok that does make sense. Thx for the help!

(btw. I don’t think this is mentioned in the API, so might be an idea to add something about it?)

2 Likes

If you don’t want the ‘queue up’ effect, you can use the second parameter of setTrigger to only have it apply for the current frame.

AnimComponent | PlayCanvas API Reference>

this.entity.anim.setTrigger('idle', true);

This way, if the trigger is not consumed in this frame, it gets reset at the end of it.

Also as a side note, I personally prefer to use ‘sub graphs’ over ANY FRAME. With layer.transition , you can transition to any state even if there is no set transition path between the states.

This makes it handy to jump to other parts of the graph.

Example: https://playcanvas.com/project/1061484/overview/f-jump-example

And the code when jumping:

if (this.app.keyboard.wasPressed(pc.KEY_SPACE)) {
   this._anim.baseLayer.transition('Jump', 0.1);
}
2 Likes

oh, thx!

For some reason I didn’t notice it in the API