This is the 3rd and final installment in the mini tute series ‘Creating 2D Animation States in Unity3D’ . You can find previous installments here: Part1 | Part 2
In part 2 we created our Player animations, created an animation controller, organised our animations in the Animator window, and then mapped them to ‘Conditions’ based on animation ‘Parameters’.
Now we will finish it off by stepping onto the coding dance floor, and creating a system for switching between animations using the keyboard. Complete Project source file link can be found at the end of the tutorial.
Note : Before we get stuck in, I would like to take a moment to do some quick edits to our existing projects from Part 2
- In the Project window, select the ken_crouch animation, and in the inspector, make sure ‘Loop Time’ is unchecked. this will stop the ken from crouching and standing up continuously.
- In The Animator window, create a new transition from animations ken_crouch to ken_walk, with the mapped condition ‘state Equals 1’
Add a Background Graphic to the Scene
Lets add an appropriate Background to our scene, this will give us a reference point for where the floor should be.
In your Project window, expand the ken-sprite-sheet in your spritesheets folder, and find ‘ken-sprite-sheet_49’ which is a background graphic. Drag it into your scene window and position it at the coordinates 0, 0, 0.
You may notice your player is no longer visible, this is because the the Background is sitting above the player (closer to the camera). Select your Player and change the Z position to -1.
Now would be a good time to fix the games screen resolution. Select 16:9 from the resolution drop down, as it’s a good match to our background graphic’s aspect ratio.
You may find the background is now slightly smaller than the viewable area of the camera, select the background element and increase the scale slightly so it completely fills the camera, as well as changing the positions until it fits.
Creating the Player Controller C# Script
If you have followed on from the previous tutorial, you should have an empty ‘scripts’ folder in your project root, if not, create it (right click project tab window > Create > Folder ).
Lets create a new C# script inside this folder by right clicking the folder in the project window and selecting Create > C# Script.
Rename it PlayerController and drag the script onto your Players Inspector window to add it to the player.
Open the script in MonoDevelop by double clicking it (your welcome to use any code editor, for this tute i’ll be using Mono).
Copy and paste the code below into your Player Controller, then attach it to you player object by dragging it onto your Player objects Inspector window.
using UnityEngine; using System.Collections; public class PlayerController : MonoBehaviour { public float walkSpeed = 1; // player left right walk speed private bool _isGrounded = true; // is player on the ground? Animator animator; //some flags to check when certain animations are playing bool _isPlaying_crouch = false; bool _isPlaying_walk = false; bool _isPlaying_hadooken = false; //animation states - the values in the animator conditions const int STATE_IDLE = 0; const int STATE_WALK = 1; const int STATE_CROUCH = 2; const int STATE_JUMP = 3; const int STATE_HADOOKEN = 4; string _currentDirection = "left"; int _currentAnimationState = STATE_IDLE; // Use this for initialization void Start() { //define the animator attached to the player animator = this.GetComponent<Animator>(); } // FixedUpdate is used insead of Update to better handle the physics based jump void FixedUpdate() { //Check for keyboard input if (Input.GetKeyDown (KeyCode.Space)) { changeState (STATE_HADOOKEN); } else if (Input.GetKey ("up") && !_isPlaying_hadooken && !_isPlaying_crouch) { if(_isGrounded) { _isGrounded = false; //simple jump code using unity physics rigidbody2D.AddForce(new Vector2(0, 250)); changeState(STATE_JUMP); } } else if (Input.GetKey ("down")) { changeState(STATE_CROUCH); } else if (Input.GetKey ("right") && !_isPlaying_hadooken ) { changeDirection ("right"); transform.Translate(Vector3.left * walkSpeed * Time.deltaTime); if(_isGrounded) changeState(STATE_WALK); } else if (Input.GetKey ("left") && !_isPlaying_hadooken) { changeDirection ("left"); transform.Translate(Vector3.left * walkSpeed * Time.deltaTime); if(_isGrounded) changeState(STATE_WALK); } else { if(_isGrounded) changeState(STATE_IDLE); } //check if crouch animation is playing if (animator.GetCurrentAnimatorStateInfo(0).IsName("ken_crouch")) _isPlaying_crouch = true; else _isPlaying_crouch = false; //check if hadooken animation is playing if (animator.GetCurrentAnimatorStateInfo(0).IsName("ken_hadooken")) _isPlaying_hadooken = true; else _isPlaying_hadooken = false; //check if strafe animation is playing if (animator.GetCurrentAnimatorStateInfo(0).IsName("ken_walk")) _isPlaying_walk = true; else _isPlaying_walk = false; } //-------------------------------------- // Change the players animation state //-------------------------------------- void changeState(int state){ if (_currentAnimationState == state) return; switch (state) { case STATE_WALK: animator.SetInteger ("state", STATE_WALK); break; case STATE_CROUCH: animator.SetInteger ("state", STATE_CROUCH); break; case STATE_JUMP: animator.SetInteger ("state", STATE_JUMP); break; case STATE_IDLE: animator.SetInteger ("state", STATE_IDLE); break; case STATE_HADOOKEN: animator.SetInteger ("state", STATE_HADOOKEN); break; } _currentAnimationState = state; } //-------------------------------------- // Check if player has collided with the floor //-------------------------------------- void OnCollisionEnter2D(Collision2D coll) { if (coll.gameObject.name == "Floor") { _isGrounded = true; changeState(STATE_IDLE); } } //-------------------------------------- // Flip player sprite for left/right walking //-------------------------------------- void changeDirection(string direction) { if (_currentDirection != direction) { if (direction == "right") { transform.Rotate (0, 180, 0); _currentDirection = "right"; } else if (direction == "left") { transform.Rotate (0, -180, 0); _currentDirection = "left"; } } } }
If you run the game you may find the player is falling through the floor. This is because Unity’s 2D physics engine was leveraged to create the simple jump movement.
To to allow the player to walk on a floor we will need to do 2 more things:
Adding a floor
Create and add a floor. Select GameObject > Create Empty.
Name it ‘Floor’.
With the floor selected, click ‘Add Component’ in the Inspector window then Physics2D > Box Collider 2D. This will add a box collider to the floor so the player has something to stand on. In the Inspector change the Box Collider’s Size properties so it fits the screen, then move the whole Floor object to a suitable position below the players feet.
Adding Collider and RigidBody2D to the Player
Select the player and as in the previous step, add a 2D Box collider, only this time to the player. You can either position it at the players feet or make it the size of the while player, either will work in this case.
Now we need to add a rigidBody2d to the Player. With the Player selected, click ‘Add Component’ in the inspector window, then Physics2D > Rigid Body 2D. Leave the settings as default.
If all goes well running the game should give you some positive results. But as is the way with development you are likely to have some errors!
Incase you run into such problems which you cannot solve, please treat yourself to the Project Source Files on my git repo. Feel free to leave a comment if you have any questions.
Keyboard controls are: Up = Jump, Left/Right = Walk, Down = Crouch, Space Bar = Hadoooooooken
Join me on Patreon to get exclusive access to source code and valuable gamedev info.
Hey!
I love your tutorials, they have helped me a lot!
However, I still have a gigantic issue that has to do with collisions. I’d like to have multiple box colliders for my character on a per-image basis. The problem is, the Animation editor is not graphic at all, and it doesn’t allow me to do advanced stuff like different types of box colliders (one idea I had was to have different subclasses for hitboxes, damage boxes, etc.) but it doesn’t seem to be that much customizable with said editor.
How would you solve this problem? How would you make your colliders go, to have colliders trigger damage and colliders act as movement colliders (you can’t go through your opponent) and “attackable” colliders?
Thanks a bunch! Great series of articles, love what you do!
Im thinking you want to put like a collision box on a fist, of say a punch animation, but only have it fire a hit when a certain animation frame is reached. This technique is a lot easier for 2D animation that has broken up the arms, legs , torso, head into separate objects nested on a body. (animated with unity animation tools). But in the case of the tute example.. i would consider 1) having just one main collision box wrapping the body, head and legs 2) checking if the player is punching 3) write some code to check the targets x,y position in relation to the punching player, to determine if a hit should be registered. this way you don’t have to rely on nested ‘sub’ collision boxes. The example of a fighting game is tricky, as there can be a lot going on with all the different attacks! 🙂
Great tutorial. I have already done some sprite animations of my own thanks to it 🙂
Really nice!! thank you so much for this article!!! Can’t wait for the new posts!
[…] http://johnstejskal.com/wp/creating-2d-animation-states-in-unity3d-pt3/ […]
Thanks for your tutorial, it’s a real pleasure to read it.
However, I have a little problem in the speed of my sprite. In fact, my idle animation is very fast and I can’t find the way to slow it down. Do I have to do it in the C# Code or is there an option to change it on the software ?
Great Tutorial..
Can you tell how to add audio for each action.
for example: adding a audio clip for each single movement, like walk,run,jump,attack
I read your tutorial, and thank you for all the info, which helped me alot. God bless you.
[…] Creating 2D animation states in Unity3D : Part 3 – Switching animations with keyboard input […]
when i compile it says
Error CS0101: The namespace ” already contains a definition for ‘PlayerController’. (CS0101) (Assembly-CSharp)
can you kindly check it?
It’s an issue caused by Unity 5.0 Update.. I’m in the process of updating the tutorial to the new spec. Check back soon 🙂
Oh thanks so much man, it’s amazing how even 2d controllers can get when u have multiple states, this tutorial just abstaracted it all down to integers…a life saver
Hi, johnstejskal
I really would like if you convert the code to the JavaScript ?
Thank you a lot for your job here!
This tutorial is ROCKS!!!
I’ve spent 3-4 hours try to understand animation but fail..
But only 10 mins from yours to success, thanx you..
Hi,
Well written tutorial, however I ve one question.
In the method where you set new animator state, couldn’t you just pass the value from param to animator instantly, instead of using switch-case ?
Awesome tutorial, I’m to Unity and this tutorial help me to understand more in animation controller. Thank you.
Thanks for this tutorial and all the serie.
It’s very useful and funny.
I used this tutorial and got Ken perfectly working. Then I tried the same thing on some Ryu sprites and I can only play one animation before it just gets stuck in an animation loop or on the last sprite of the animation that was run. The player can still move around, if the first animation is walking for example, I can walk back and forth. I can jump as well but the animation just stays stuck on walk.
Please help me.
Yes, I have to say thank you for this tutorial…
This really cleared up some things which seem so simple now lol.
I have to say thank you for this tutorial.
This really clears up some things, which seem so simple now lol.
it did not work