I want to implement “some code” that’s able to play a random animation for a particular animation state, where the number of animation variations is unknown at the time of writing that code.
For example, I have an Idle
state that’s triggered by code via:
animator.Play("Idle");
This Idle
must then be able to trigger a random animation. This allows to add and remove idle variations through the Animator Controller, without code modifications.
I don’t want the (game) code to be aware of how many “Idle variations” there are.
I don’t want:
var stateName = $"Idle {Random.Range(1, 4)}";
animator.Play(stateName);
This code falls apart when an idle animation is removed or added, so it’s not an acceptable solution.
I don’t want:
To hook up an Animator Parameter for every animation that might have variations:
animator.SetInteger("Idle Variation", Random.Range(1, 4));
animator.Play("Idle");
This again falls apart when the number of animations change. It also introduces another level of complexity that shouldn’t be necessary.
What I do want:
I want that the Idle state knows how many transitions there are and picks a random one and plays it.
The closest I came to it was to implement a StateMachineBehaviour
that holds a list of state names (Idle 1, Idle 2, Idle 3).
The problem is that you still need to keep the State Names
array as shown in the screenshot in-sync with the number of actual state transitions.
public class RandomAnimatorBehaviour : StateMachineBehaviour
{
[SerializeField] string[] m_StateNames = new string[0];
// OnStateEnter is called when a transition starts and the state machine starts to evaluate this state
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
var index = UnityEngine.Random.Range(0, m_StateNames.Length);
var stateName = m_StateNames[index];
animator.Play(stateName, layerIndex);
}
}
This again is rather error-prone and shouldn’t be needed, since the state must be aware of its transitions. I also don’t really want to “animator.Play” again, but rather just substitute the animation variation, because the caller might have called Play, CrossFade, etc.
So… I guess the question is:
- How can I access the “transitions array” from an animator state inside a StateMachineBehaviour callback.
- Is there a better way to play a random animation without having to manually keeping an extra list of state names (or similar) in-sync with the Animator Controller?
I added my test project to this post. If you open SampleScene and press play, the cube changes colors between red, green and blue, which represent different idle variations.
7275517–878953–TestRandomAnimation.zip (27.3 KB)