Unity3D: When are transition conditions evaluated
animation, graphics, unity-game-engine
Solution
I built a small scene for myself and played around a little bit. I could reproduce your problem and even found a simple solution.
Why it happens
The problem seems to occur when the animator state machine is still in transition to a new state. During that time, new parameter values are ignored but your code is going to change that value again in the next `update()` call. The state machine ignored your new direction and now only sees a value for which it has no transition available, `direction = -1` for example.
The default behavior for transitions is `atomic` which means according to the reference that it cannot be interrupted. However, setting it to false made no difference... It could be a bug and you may want to file a bug report.
Solution
You need to check if the state machine is currently in a transition by checking `IsInTransition(int layer)` like this:
void Update()
{
// update animator (Stupid transition from any state includes current state -_-")
int heading = CalculateHeading(horizontalInput, verticalInput);
if (heading != previousHeading && !anim.IsInTransition(0)) // you may need to adjust the layer index
{
anim.SetInteger("direction", heading);
previousHeading = heading;
}
else
{
anim.SetInteger("direction", -heading);
}
}
Another possible solution
I don't know what kind of animations you are using for the different directions, but it may be easier to use one animation and just turn your character around :) This way you have less transitions and states and it may be easier to add more animations later on.
Problem
I have a very simple game running in Unity, and unfortunately, it is not working as expected. The Context I have the following setup: (source: mazyod.com) From any state, if an integer parameter `direction` is equal to `1`, set animation `player_move_e`. Same goes for `2`, `3`, `4` for the other directions. Once `direction` is set to `0`, the idle animation associated with the direction is played. An important thing to point here is, since I am using the "Any State" block, I must make sure that once the animation state changes to one of the move animation states, I reset `direction` to sentinel value, like `-1`, that keeps the animation state in the current state, and not change states to itself again. The Problem When the player is in the, say, `move_n` state, and I quickly change the direction to the, say, `move_e` (not giving it enough time to transition to idle), the animation state is stuck at the `move_n` :( How can I know if the transition happened, and I am not updating too often? Initially, I was updating `direction` in `FixedUpdate`, and then moved it to `Update`, but it's the same issue in both methods. Here is the logic I am seeing: ``` // MY CODE animator.SetInteger(1); // Initially, it's move_e ... // WITHIN UNITY (making it up) Unity.UpdateStates(); // The number is read in the engine, and transition happens ... // MY CODE animator.SetInteger(-1); // Stay at current animation ... // WITHIN UNITY (making it up) Unity.UpdateStates(); // The number is read in the engine, nothing should happen ... // MY CODE animator.SetInteger(0); // The logic briefly changes to idle ... // WITHIN UNITY (making it up) Unity.UpdateStates(); // The number is read in the engine, transition to idle ... // MY CODE animator.SetInteger(4); // transition to north ... // WITHIN UNITY (making it up) // NOTHING HAPPENS!! It doesn't catch up ... // MY CODE animator.SetInteger(-1); // Stay at current state, assuming it changed to move_n ... // WITHIN UNITY (making it up) Unity.UpdateStates(); // The number is read in the engine, stays at idle_e! ... ``` UPDATE: Here is the whole code: ``` void Update() { // update animator (Stupid transition from any state includes current state -_-") int heading = CalculateHeading(horizontalInput, verticalInput); if (heading != previousHeading) { anim.SetInteger("direction", heading); previousHeading = heading; } else { anim.SetInteger("direction", -heading); } } void MovementManagement () { // If there is some axis input... if(horizontalInput != 0f || verticalInput != 0f) { Vector3 position = transform.position; position.x += horizontalInput * movementSpeed; position.y += verticalInput * movementSpeed; transform.position = position; } } int CalculateHeading(float horizontal, float vertical) { if (horizontal == 0f && vertical == 0f) { return 0; } if (Mathf.Abs(horizontal) > Mathf.Abs(vertical)) { return (horizontal > 0 ? 1 : 3); } else { return (vertical > 0 ? 4 : 2); } } ```