- Home /
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?
I'm wondering if the syntax of this line is causing issues:
if (!thisObj.animation.clip == movementAnim)
{
thisObj.animation.Stop();
thisObj.animation.clip = movementAnim;
}
It should be written like this:
if (thisObj.animation.clip != movementAnim)
{
thisObj.animation.Stop();
thisObj.animation.clip = movementAnim;
}
See if that changes any behavior at all. If so, I'll make this an answer.
Nah, it didn't, unfortunately. $$anonymous$$ade sense though. Any other ideas?
if clips[2] is the idle animation, shouldn't you be checking to see if the magnitude is equal to zero rather than greater than zero? Or am I misunderstanding your intent.
else if(c$$anonymous$$.movement.velocity.magnitude == 0f)
{
thisObj.animation.Stop();
movementAnim = clips[2];
}
Okay, well I feel incredibly foolish. Could have sworn I put
Answer by tw1st3d · Oct 03, 2013 at 06:06 AM
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);
}
}
Animation.CrossFade provides a more smooth transition between animations than Stop/Play.
Answer by SilentSin · Oct 03, 2013 at 05:29 AM
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].
2) 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.
This definitely helped, but it's still not working quite right. +1 for the help, but can't tick correct. :(
Your answer
![](https://koobas.hobune.stream/wayback/20220613115217im_/https://answers.unity.com/themes/thub/images/avi.jpg)