Seemless Animation Transitions

So, I’ve never really been a huge game developer, more of a fun-time project kind of guy. I’ve decided to buckle down and start making a full game, instead of just a small portion of one. I’ve never really worked with animations a lot, and I’ve got some problems changing between my walk animation and my run animation. Also, if anyone knows a better way of doing what I’m doing in my following code, I’d appreciate the knowledge.

using UnityEngine;
using System.Collections;

public class Walk_Anim : MonoBehaviour
{
	protected bool isPlaying = false;
	protected GameObject thisObj;
	protected AnimationClip movementAnim;
	public AnimationClip[] clips = new AnimationClip[3];
	protected CharacterMotor cM;
	
	public void Start()
	{
		cM = (CharacterMotor) GetComponent("CharacterMotor") as CharacterMotor;
		thisObj = gameObject;
	}
	
	public void Update()
	{
		if(Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S))
		{
			if(Input.GetKey(KeyCode.LeftShift))
			{
				movementAnim = clips[1];
			}else{
				movementAnim = clips[0];
			}
		}else if(cM.movement.velocity.magnitude > 0){
			thisObj.animation.Stop();
			movementAnim = clips[2];
		}
		
		if(!thisObj.animation.clip == movementAnim)
		{
			thisObj.animation.Stop();
			thisObj.animation.clip = movementAnim;
		}
		
		if(!thisObj.animation.isPlaying)
		{
			thisObj.animation.Play();
		}
	}
}

What’s happening, is, the walk animation works, but neither the run animation, or the idle ( clips[2] ) are ever set to active. What am I doing wrong here?

To answer your actual question, I would recommend removing your clips array entirely and just using animation.Play(“animationName”) instead. It requires significantly less effort to get right.

  1. If you still want to use your clips array, I’d recommend making an enum and using it to index your array:

enum Anim
{

Walk = 0,
Run = 1,
Idle = 2,

//This is my best guess at what your clips array contains based off your code.

//You could also have “Count = 3” and use it to assign the size of the array in case you add more animations later.

}

1b) If you go with my idea and pass the animation name to animation.Play() instead of manually assigning clips, I’d recommend using constant strings to avoid any spelling errors you might do.

public const string
cIdle = “idle”,
cWalk = “walk”,
cRun = “run”;

Because if you need to play an animation with a longer name somewhere in your project, animation.Play(“superLongAnimationName”) can have spelling errors in it which might either do nothing or have unity throw an exception, I’m not sure which because I’ve never tested it. On the other hand, animation.Play(cSuperLongAnimationName) won’t compile and will tell you exactly where your error is straight away.

Then instead of clips[2], you use clips[Anim.Idle].

  1. the existence of your thisObj variable is unnecessary. Using this.gameObject everywhere is perfectly fine. If you are going to store this.gameObject, then you should also store this.animation for uniformity, but I believe that doing so would be pointless and you should just use the gameObject and animation properties on their own.

Well uh, I know it’s rather clunky but it’s working perfectly, here’s the finished code.

using UnityEngine;
using System.Collections;

public class Walk_Anim : MonoBehaviour
{
	protected bool isPlaying = false;
	protected GameObject thisObj;
	public AnimationClip[] clips = new AnimationClip[3];
	protected CharacterMotor cM;
	
	public void Start()
	{
		cM = (CharacterMotor) GetComponent("CharacterMotor") as CharacterMotor;
		thisObj = gameObject;
	}
	
	public void Update()
	{
		bool running = false;
		if(Input.GetKey(KeyCode.LeftShift))
			running = true;
		
		if(Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.S) || (Input.GetKey(KeyCode.W) && running))
		{
			if(running)
			{
				if(thisObj.animation.clip != clips[1] || !thisObj.animation.isPlaying)
				{
					thisObj.animation.Stop();
					thisObj.animation.clip = clips[1];
					thisObj.animation.Play();
				}
			}else{
				if(thisObj.animation.clip != clips[0] || !thisObj.animation.isPlaying)
				{
					thisObj.animation.Stop();
					thisObj.animation.clip = clips[0];
					thisObj.animation.Play();
				}
			}
		}else{
			if(thisObj.animation.clip != clips[2] || !thisObj.animation.isPlaying)
			{
				thisObj.animation.Stop();
				thisObj.animation.clip = clips[2];
				thisObj.animation.Play();
			}
		}
		
		Debug.Log(thisObj.animation.clip.name);
	}
}