Start Mecanim animation at random time.

I am in the process of changing over my game to use Mecanim and have one issue remaining. Previously with the legacy animation system I started animations at a random point for groups and crowds so that animations were not synced up.

This was easy to accomplish using the following code:

animation["idle"].time = Random.Range(0.0f, animation["idle"].length;

Is there any way to duplicate this behavior in Mecanim?

4 Answers

4

dunno, but now you can do just:

Animator.Play(state, layer, normalizedTime);

or

Animator.CrossFade(state, crossFadeTime, layer, normalizedTime);

if you put whatever float from 0 to 1 into normalized time, you can set it to any time position you want

Been meaning to update this. This functionality was added when ForceStateNormalizedTime was deprecated.

–

This works to start an animation, but what if the animation is the default, such as idle, i.e. an anim the characters will return to after finishing moving etc? 5 characters running together will then go back to standing still at pretty much the same time (or, exactly the same time, if doing a turn-based game) and I would like to avoid doing a hard cut back to idle via code, upon finising moving, as oppose to set the state-flag as per usual. What is the approach then? Any way to set a different start-location of a looped animation per character?

–

void Start()
{
var animator = GetComponentInChildren();
animator.Update(Random.value);
}

Or as an extension:

	protected bool _randomSet = false;

	void Update () 
	{	
		if (_randomSet == false)
		{
			// random animation start point
			_animator.SetTimeForCurrentClip(Random.value);
			_randomSet = true;
		}
	}

	public static Animator SetTimeForCurrentClip(this Animator self, float percent, int layer = 0)
	{
		AnimatorClipInfo[] cInfo = self.GetCurrentAnimatorClipInfo(layer);
		if (cInfo.Length > 0)
		{
			AnimationClip clip = cInfo[0].clip;
			self.Play(clip.name, layer, clip.length * percent);
		}

		return self;
	}

Thank you! This worked for me. With this method, you don't need the state name which is wonderful and generic.

–

Here is a code snippet I use that randomizes the start time with a public bool at awake. That way you can easily tweak whether it should be randomized or not.

	anim = GetComponent<Animator>();

	if (!randomizeStartFrame) {
		anim.Play(animatiorStartName);
	} else {
		float startPoint = Random.Range(0f, 1f);
		anim.Play(animatiorStartName, -1, startPoint);
	}

I've actually created an open source helper library that includes this script and others for typical use cases like this. [https://github.com/ashblue/unity-animator-helpers][1] [1]: https://github.com/ashblue/unity-animator-helpers

–