Search code examples
c#unity-game-engine

How can I play random animations in animator using script?


I have 12 states they are all connected by transitions in loop. So the flow of the playing is always the same. But I want to play them randomly.

But if they are all connected by transitions I guess it's impossible since the transition make the path.

Animator

And using Animation component not working with mixamo animations. Since in Animation component the animations must to be legacy type but in the animator they have to be humanoid type and to play the animations correctly I need to set them to be humanoid type that's why I'm using the Animator and not Animation. And playing them is working fine but I want to play them in a random order.


Solution

  • private AnimationClip[] clips;
    private Animator animator;
    
    private void Awake()
    {
        // Get the animator component
        animator = GetComponent<Animator>();
    
        // Get all available clips
        clips = animator.runtimeAnimatorController.animationClips;
    }
    

    Now you have all animations.

    There are various ways of how those shall be randomized now ... I show you the simplest one which is just randomly pick an index and play that animation.

    First you will use a Coroutine so to start it from the beginning

    private void Start()
    {
        StartCoroutine (PlayRandomly);
    }
    

    In the Coroutine pick a random index and play the state in the animator

    private IEnumerator PlayRandomly ()
    {
        while(true)
        {
            var randInd = Randome.Range(0, clips.length);
    
            var randClip = clips[randInd];
    
            animator.Play(randClip.name);
    
            // Wait until animation finished than pick the next one
            yield return new WaitForSeconds(randClip.length);
        }
    }
    

    Note as said this is the simplest way and does not assure things like "Don't play the same animation twice right after another" or "First play all animations before repeating one"

    To achieve those you would instead shuffle the list of clips, run through them and after the last clip shuffle again etc e.g. like

    private IEnumerator PlayRandomly ()
    {
        var clipList = clips.ToList();
    
        while(true)
        {
            clipList.Shuffle();
    
            foreach(var randClip in clipList)
            {
                animator.Play(randClip.name);
                yield return new WaitForSeconds(randClip.length);
            }
        }
    }
    
    public static class IListExtensions 
    {
        /// <summary>
        /// Shuffles the element order of the specified list.
        /// </summary>
        public static void Shuffle<T>(this IList<T> ts) {
            var count = ts.Count;
            var last = count - 1;
            for (var i = 0; i < last; ++i) {
                var r = UnityEngine.Random.Range(i, count);
                var tmp = ts[i];
                ts[i] = ts[r];
                ts[r] = tmp;
            }
        }
    }