- Home /
Animation Problems using 2D Toolkit
I have purchased and am using the unity 2D Toolkit and have run into an error with a script that I am using for movement. At the moment, said script allows for character movement in a top-down environment, updating the displayed animation based on input. The issue I am currently having is that the animations will only display the initial frame and be locked until an idle state (no buttons being pressed) is reached. I was able to remedy the problem by using a boolean "playingOneAnimationLoop = true" during each of the movement calls (commented out in the bellow code under doUp(), etc.). This allows the animations to play, but the character only translates at a few pixels per press. I'd like to know what I need to change in order for both the animations to play and the character to translate properly (comments left in the code for explanation of steps):
var playingOneAnimationLoop : boolean;
var weNeedAnIdle : boolean;
var alreadyBusy : boolean;
enum FACING {up, right, down, left }
var facing : FACING;
var speed : float = 0.25f;
var anim : tk2dAnimatedSprite;
anim = GetComponent(tk2dAnimatedSprite);
function Start ()
{
}
function Update()
{
// if you only get to here, one of the walk animations
// is actually playing at this instant
if ( playingOneAnimationLoop )
{
return;
}
// if you get to here, we have either JUST finished an
// animation, or, we're just doing nothing
// if we have JUST finished an animation, it's possible
// the user wants ANOTHER animation, if a key is down
if (Input.GetAxis("Vertical") > 0)
{
doUp();
return;
}
if (Input.GetAxis("Horizontal") < 0)
{
doRight();
return;
}
if (Input.GetAxis("Vertical") < 0)
{
doDown();
return;
}
if (Input.GetAxis("Horizontal") > 0)
{
doLeft();
return;
}
// if you get to here, you have JUST finished the play loop
// this split-second AND nobody is pressing any keys
// (or, we're just doing nothing and sitting around)
// if weNeedAnIdle is true it means we have JUST finished
// an animation. We'll simply ONCE (one time) play the
// correct standing anime. ie "set it to" the right image
if ( weNeedAnIdle ) changeToIdle();
}
function doUp()
{
alreadyBusy = true;
anim.Play("Walk_Up");
Invoke( "oneLoopIsFnished", 1.00 );
facing = FACING.up;
weNeedAnIdle = true;
//playingOneAnimationLoop = true;
transform.Translate(0,0,speed * Time.deltaTime,Space.World);
}
function doRight()
{
alreadyBusy = true;
anim.Play("Walk_Right");
Invoke( "oneLoopIsFinished", 1.00);
facing = FACING.right;
weNeedAnIdle = true;
//playingOneAnimationLoop = true;
transform.Translate(speed * Time.deltaTime,0,0,Space.World);
}
function doDown()
{
alreadyBusy = true;
anim.Play("Walk_Forward");
Invoke( "oneLoopIsFinished", 1.00);
facing = FACING.down;
weNeedAnIdle = true;
//playingOneAnimationLoop = true;
transform.Translate(0,0,-speed * Time.deltaTime,Space.World);
}
function doLeft()
{
alreadyBusy = true;
anim.Play("Walk_Left");
Invoke( "oneLoopIsFinished", 1.00);
facing = FACING.left;
weNeedAnIdle = true;
//playingOneAnimationLoop = true;
transform.Translate(-speed * Time.deltaTime,0,0,Space.World);
}
function oneLoopIsFinished()
{
playingOneAnimationLoop = false;
}
function changeToIdle()
{
if ( facing == FACING.up )
{
anim.Play("Up_Idle");
}
if ( facing == FACING.right )
{
anim.Play("Right_Idle");
}
if ( facing == FACING.left )
{
anim.Play("Left_Idle");
}
if ( facing == FACING.down )
{
anim.Play("Forward_Idle");
}
weNeedAnIdle = false;
}
Yes! The problem is that my animations are through sprites, and while your script worked well, it had the similar issue of not playing the animation fully, locking on the first frame. Here's a quick video of the basic movement from my original controller to get an idea(animations work, but if multiple buttons are pressed, a "moon walking" glitch occurs):
http://www.youtube.com/watch?v=$$anonymous$$$$anonymous$$Qa9NYpP1s&feature=plcp
Answer by ThePunisher · Oct 04, 2012 at 03:01 AM
Hey Asy1umrat, I have re-written the script with a slightly different implementation which should help you manage your facing transitions a little better. The only problem is that I don't know enough Javascript to give the code in Javascript (it's written in C#). However, you should be able to pull the logic straight out of this script and put it in the correct Javascript syntax. I didn't quite get to testing the script (I'll do that once I get a chance), but this should give you an idea of the direction you may want to head in. I hope this helps you.
using UnityEngine;
using System.Collections;
public class CharController : MonoBehaviour
{
private float m_speed = .25f;
private Facing m_facing = Facing.Down;
private bool m_idle = true;
private tk2dAnimatedSprite m_anim;
private void Awake()
{
m_anim = GetComponent<tk2dAnimatedSprite>();
}
// Use this for initialization
private void Start ()
{
}
// Update is called once per frame
private void Update ()
{
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
float horizontalAbs = Mathf.Abs(horizontal);
float verticalAbs = Mathf.Abs(vertical);
// Instead of updating both directions on a single frame, we limit it to movement on a single axis by updating x or z.
if (horizontalAbs > verticalAbs)
{
transform.Translate(new Vector3(horizontal * m_speed * Time.deltaTime, 0.0f, 0.0f), Space.World);
}
else
{
transform.Translate(new Vector3(0.0f, 0.0f, vertical * m_speed * Time.deltaTime), Space.World);
}
if (horizontal < 0.0f && m_facing != Facing.Left) //Only update to left facing if we are not already facing left.
{
m_idle = false;
//Set the new facing.
m_facing = Facing.Left;
UpdateFacing();
}
else if (horizontal > 0.0f && m_facing != Facing.Right)//Only update to Right facing if we are not already facing Right.
{
m_idle = false;
//Set the new facing.
m_facing = Facing.Right;
UpdateFacing();
}
else if (vertical > 0.0f && m_facing != Facing.Up)//Only update to Up facing if we are not already facing Up.
{
m_idle = false;
//Set the new facing.
m_facing = Facing.Up;
UpdateFacing();
}
else if (vertical < 0.0f && m_facing != Facing.Down)//Only update to Down facing if we are not already facing Down.
{
m_idle = false;
//Set the new facing.
m_facing = Facing.Down;
UpdateFacing();
}
if (m_idle == false && horizontal == 0.0f && vertical == 0.0f) //This is an edge case. This will happen when horizontal and vertical are equal (which is basically when we stop moving since both axis will return 0.0f).
{
m_idle = true;
PlayIdleAnimation();
//***Key to starting the correctly-facing walking animation again.
m_facing = Facing.Idle;
}
}
/// <summary>
/// Plays the correct walking animation depending on the current facing.
/// </summary>
private void UpdateFacing()
{
switch (m_facing)
{
case Facing.Down:
m_anim.Play("Walk_Down");
break;
case Facing.Left:
m_anim.Play("Walk_Left");
break;
case Facing.Right:
m_anim.Play("Walk_Right");
break;
case Facing.Up:
m_anim.Play("Walk_Up");
break;
}
}
/// <summary>
/// Plays the correct idle animation depending on the current facing.
/// </summary>
private void PlayIdleAnimation()
{
switch (m_facing)
{
case Facing.Down:
m_anim.Play("Down_Idle");
break;
case Facing.Left:
m_anim.Play("Left_Idle");
break;
case Facing.Right:
m_anim.Play("Right_Idle");
break;
case Facing.Up:
m_anim.Play("Up_Idle");
break;
}
}
enum Facing
{
Up,
Right,
Down,
Left,
Idle//***New variable used when we go into Idle so that we can update our facing correctly once we start moving again.
}
}
Edit: The idle-walking behavior you saw was caused by the current facing already being set. For example, if you walked right, then your current facing would be Facing.Right, therefore the check under `m_facing != Facing.Right` would fail if you tried walking right again. The fix for that is to make a just make a new variable for Facing that we can set the current facing to once we have gone idle.
I was playing around with this, and it works, though I'm finding some problems with the animations still. $$anonymous$$ainly, if a vertical and horizontal input is given, it causes the idle animation to play, but the character to still move. I'm trying an if statement around the translate to check for multiple inputs to see if that solves the problem, though. Thank you for the advice :D
Ah, I saw the video you posted. Looking good! I see the type of movement you wanted. If you haven't already tweaked the script to your liking I can go back and change it.
Please do if you could. List out the differences in the code as well so I can see what you did differently :)
Answer by sheepshenko · Nov 14, 2012 at 04:06 AM
hello i was looking for something like this. but i still have a problem. i cant make it jump. when i push the jump button my character start to fly i try to use gravity but it doesnt work. here is the script.
public class AnimController: MonoBehaviour
{
private float m_speed = 6f;
private float m_speedjump = 10f;
private Facing m_facing = Facing.Right;
private bool m_idle = true;
float gravedad = 80;
bool airControl = true;
Vector3 moveDirection = Vector3.zero;
private tk2dAnimatedSprite m_anim;
private void Awake()
{
m_anim = GetComponent<tk2dAnimatedSprite>();
}
// Use this for initialization
private void Start ()
{
}
private void Jump()
{
CharacterController controller = GetComponent<CharacterController>();
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, 0);//extra
float inputX = Input.GetAxis("Horizontal");//extra
if(Input.GetButton("Jump"))
{
moveDirection.y = m_speedjump; //extra
airControl = true;
}
if (airControl == true)//extra
{
moveDirection.x = inputX * m_speed; //extra
}
moveDirection.y -= gravedad * Time.deltaTime;//extra
controller.Move(moveDirection * Time.deltaTime);//extra
}
// Update is called once per frame
private void Update ()
{
float horizontal = Input.GetAxis("Horizontal");
float vertical = Input.GetAxis("Vertical");
float horizontalAbs = Mathf.Abs(horizontal);
float verticalAbs = Mathf.Abs(vertical);
// Instead of updating both directions on a single frame, we limit it to movement on a single axis by updating x or z.
if (horizontalAbs > verticalAbs)
{
transform.Translate(new Vector3(horizontal * m_speed * Time.deltaTime, 0.0f, 0.0f), Space.World);
}
// else
{
//transform.Translate(new Vector3(0.0f, vertical * m_speed * Time.deltaTime,0.0f), Space.World);
}
//Jump();
if (horizontal < 0.0f && m_facing != Facing.Left) //Only update to left facing if we are not already facing left.
{
m_idle = false;
//Set the new facing.
m_facing = Facing.Left;
UpdateFacing();
}
else if (horizontal > 0.0f && m_facing != Facing.Right)//Only update to Right facing if we are not already facing Right.
{
m_idle = false;
//Set the new facing.
m_facing = Facing.Right;
UpdateFacing();
}
/*
else if (vertical > 0.0f && m_facing != Facing.Up)//Only update to Up facing if we are not already facing Up.
{
m_idle = false;
//Set the new facing.
m_facing = Facing.Up;
UpdateFacing();
}
else if (vertical < 0.0f && m_facing != Facing.Down)//Only update to Down facing if we are not already facing Down.
{
m_idle = false;
//Set the new facing.
m_facing = Facing.Down;
UpdateFacing();
}*/
if (m_idle == false && horizontal == 0.0f && vertical == 0.0f) //This is an edge case. This will happen when horizontal and vertical are equal (which is basically when we stop moving since both axis will return 0.0f).
{
m_idle = true;
PlayIdleAnimation();
//***Key to starting the correctly-facing walking animation again.
m_facing = Facing.Idle;
}
}