- Home /
Help with Top-Down Controls using 2D Toolkit
I am attempting to make a top-down game using the 2D Toolkit.
I am looking for a controls that "I press LEFT. While he is walk it is not possible to press any other key." After the button is released, it should play the "animation" for idle in each direction (1 frame each). While the player is walking they should not be able to interrupt the current walk animation.
Forward Walk: 4 frames/4 Frame rate, Up Walk: 4 frames/4 Frame rate, Left Walk: 2 Frames/8 Frame rate, Right Walk: 2 Frames/8 Frame rate
also, as you hold the movement button, the animation should loop, which at the moment it fails to do, only showing the first and last frames when press/holding and releasing, respectively.
At the moment I am attempting to get my controller working properly, playing different walking animations based on which direction the character is moving. Problems include if multiple buttons are pressed the incorrect animation will play. I have been attempting to rebuild from scratch:
using UnityEngine; using System.Collections;
public class Animation_Controler : MonoBehaviour
{
tk2dAnimatedSprite anim;
float speed = 0.25f;
int lastButtonPress = 2;
// Use this for initialization
void Start ()
{
anim = GetComponent<tk2dAnimatedSprite>();
}
// Update is called once per frame
void Update ()
{
//Moving Animations
if (Input.GetKey(KeyCode.UpArrow))
{
transform.Translate(0,0,speed * Time.deltaTime,Space.World);
if (Input.GetKeyDown(KeyCode.UpArrow))
{
anim.Play("Walk_Up");
}
lastButtonPress = 0;
}
else if (Input.GetKey(KeyCode.LeftArrow))
{
transform.Translate(-speed * Time.deltaTime,0,0,Space.World);
if (Input.GetKeyDown(KeyCode.LeftArrow))
{
anim.Play("Walk_Left");
}
lastButtonPress = 1;
}
else if (Input.GetKey(KeyCode.DownArrow))
{
transform.Translate(0,0,-speed * Time.deltaTime,Space.World);
if (Input.GetKeyDown(KeyCode.DownArrow))
{
anim.Play("Walk_Forward");
}
lastButtonPress = 2;
}
else if (Input.GetKey(KeyCode.RightArrow))
{
transform.Translate(speed * Time.deltaTime,0,0,Space.World);
if (Input.GetKeyDown(KeyCode.RightArrow))
{
anim.Play("Walk_Right");
}
lastButtonPress = 3;
}
//Idle Animations
else if (lastButtonPress == 0)
{
anim.Play("Up_Idle");
}
else if (lastButtonPress == 1)
{
anim.Play("Left_Idle");
}
else if (lastButtonPress == 2)
{
anim.Play("Forward_Idle");
}
else if (lastButtonPress == 3)
{
anim.Play("Right_Idle");
}
}
}
Split the steps up. First deter$$anonymous$$e the direction of movement from the key presses. Then when you know the direction, apply the correct animation.
code converted to answer
$$anonymous$$ake sure you also read the answer by Fattie, and think about how you can organize scripts. (nestled ifs and input after if input - ouch).
Also consider animation.CrossFade : http://docs.unity3d.com/Documentation/ScriptReference/Animation.CrossFade.html
Asy1umrat : The cases look interesting as well. Would that solve my issue of multiple button presses?
$$anonymous$$e : yes, I do believe splitting up the steps will resolve your input and animation issues. The switch-case is a fantastic alternative to an endless thread of nestled if statements.
Answer by Fattie · Oct 02, 2012 at 04:18 PM
Never, EVER use "else if".
Maybe this is what you want. You can write this many different ways, I have tried to do it so it is as explanatory as possible.
enum FACING {up, right, down, left }
private var playingOneAnimationLoop:boolean
private var weNeedAnIdle:boolean
private var facing:FACING;
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 this split-second, or, we're just doing nothing
// if we have JUST finished an anaimtion, it's possible
// the user wants ANOTHER animation, if a key is down
if (Input.GetKey(KeyCode.UpArrow)) { dpUP(); return; }
if (Input.GetKey(KeyCode.RightArrow)) { doRight(); return; }
if (Input.GetKey(KeyCode.DownArrow)) { doDown(); return; }
if (Input.GetKey(KeyCode.LeftArrow)) { doLeft(); return; }
// if you get to here, you have JUST finished the play loop
// this split-second AND nobody is pressing any damned 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 );
// NOTE use the CORRECT time for each animation
// you may want to tweak them in each case
// for the feel you want, jerky, smooth whatever
facing = FACING.up;
weNeedAnIdle = true;
}
function doRight .. similar
function doDown .. similar
function doLeft .. similar
function oneLoopIsFinished()
{
playingOneAnimationLoop = false;
}
function changeToIdle()
{
if ( facing == FACING.up ) anim.Play("Up_Idle");
if ( facing == FACING.right ) anim.Play("Right_Idle");
.. etc ..
weNeedAnIdle = false;
}
That is fantastic, thank you. I see where I was getting confused with my own logic, as well. That cleared up so much. Thank you.
fantastic! do me a favour and "thumb up" the answer as I get more points, points, POINTS! :-)
do not hesitate to start a new question if there is any further problem
Done! Your outline helped so much, thank you, again! It works wonderfully.
I am, though, currently getting an issue where the player will move, but only the first frame will play. I was able to solve this animation problem by putting a playingOneAnimationLoop = true; line in the doUp, etc, functions. The result being that now holding down a button plays the full animation, but the character only translates a few pixels at a time.
I'm sure I'm just misunderstanding something simple.
i reckon a new question would be in order for that, show all code you are using etc!
Answer by AlucardJay · Oct 03, 2012 at 03:16 AM
Here is the switch-case from my comment, tested and working with an example web player build at the bottom. I also included the change from Input.GetKey to Input.GetAxis :
#pragma strict
private var speed : float = 0.5;
private var moveDir : int = 0;
private var lastDir : int = 0;
function Update()
{
if ( Input.GetAxis("Vertical") > 0 ) // Input.GetKey(KeyCode.UpArrow)
{
moveDir = 0;
lastDir = 0;
}
else if ( Input.GetAxis("Horizontal") < 0 ) // Input.GetKey(KeyCode.LeftArrow)
{
moveDir = 1;
lastDir = 1;
}
else if ( Input.GetAxis("Vertical") < 0 ) // Input.GetKey(KeyCode.DownArrow)
{
moveDir = 2;
lastDir = 2;
}
else if ( Input.GetAxis("Horizontal") > 0 ) // Input.GetKey(KeyCode.RightArrow)
{
moveDir = 3;
lastDir = 3;
}
else
{
moveDir = -1;
}
switch( moveDir )
{
case 0 :
// move up
transform.Translate( 0, 0, speed * Time.deltaTime, Space.World );
animation.CrossFade("TPC_Dude Running");
break;
case 1 :
// move left
transform.Translate( -speed * Time.deltaTime, 0, 0, Space.World );
animation.CrossFade("TPC_Dude Strafing");
break;
case 2 :
// move down
transform.Translate( 0, 0, -speed * Time.deltaTime, Space.World );
animation.CrossFade("TPC_Dude Walking Backward");
break;
case 3 :
// move right
transform.Translate( speed * Time.deltaTime, 0, 0, Space.World );
animation.CrossFade("TPC_Dude Strafing");
break;
default : // case -1 :
// play correct idle animation
switch( lastDir )
{
case 0 :
// idle up
animation.CrossFade("TPC_Dude Idle");
break;
case 1 :
// idle left
animation.CrossFade("TPC_Dude Idle");
break;
case 2 :
// idle down
animation.CrossFade("TPC_Dude Idle");
break;
case 3 :
// idle right
animation.CrossFade("TPC_Dude Idle");
break;
}
break;
}
//Debug.Log( " moveDir " + moveDir + " : lastDir " + lastDir );
}
Here is a web build to demonstrate : http://www.alucardj.net16.net/unityanswers/CrossAnim.html
This is a direct copy of the script in my build, so you'll have to change the animation names (and they're old animations! but all I had on hand right now, enough for the example)
=]
Answer by Xepherys · Oct 23, 2013 at 08:56 PM
Couldn't you just use a SWITCH/CASE clause directly from Input.GetAxis? ELSE IF statements make my skin crawl. :)
Your answer
Follow this Question
Related Questions
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
Sprite staying on idle animation 1 Answer
Unity2D Space shooter rotation resetting when analogue stick input has ended 1 Answer
How to tell when and in which direction the player is moving? (2d) 1 Answer
SpriteManager 2 1 Answer