Animated Character 2D in Unity (Part 2)
When you are attempting to build a 2D platform game, one of the most important elements will help me a character movement. So in this post, I will show you how to make a simple animated character in Unity.
That character will have an idle animation, walking, and running animations, and jumping and falling down animations.
I will be using a few assets make by Kenney so buckle up!
Read part 1 first! ?
This post is a continuation of Animated Character 2D in Unity (Part 1). You should start reading there before reading this post. ?
Start walking! ?♀️
So it’s finally time to make our character walk! To do that, we would need to create a little script that will be responsible for that. Let’s call it CharacterMovement.
This script will read player input and translates it into a character walk.
Let’s start with gathering necessary references for our component. We will need here Animator and Rigidbody2D.
using UnityEngine; /// <summary> /// Simple Character movement. /// </summary> [RequireComponent(typeof(Animator))] [RequireComponent(typeof(Rigidbody2D))] public class CharacterMovement : MonoBehaviour { // Reference to the Animator private Animator characterAnimator; // Reference to the Rigidbody2D private Rigidbody2D rb; /// <summary> /// Setup component /// </summary> private void Awake() { // Get references characterAnimator = GetComponent<Animator>(); rb = GetComponent<Rigidbody2D>(); } }
The next step will be to configure walk speed and read player input. We can also set the value for our animator to make our character “walk”.
using UnityEngine; /// <summary> /// Simple Character movement. /// </summary> [RequireComponent(typeof(Animator))] [RequireComponent(typeof(Rigidbody2D))] public class CharacterMovement : MonoBehaviour { ... [Header("Movement")] /// <summary> /// Character Walk Speed /// </summary> [SerializeField] private float walkSpeed = 1f; // Input private float horizontalInput; ... /// <summary> /// Called on each frame /// </summary> private void Update() { // Get input horizontalInput = Input.GetAxisRaw("Horizontal"); // Set animation movement speed var animSpeed = horizontalInput; characterAnimator.SetFloat(Keys.ANIMATION_SPEED_KEY, Mathf.Abs(animSpeed)); } }
You can also spot a little Keys class. I’m using that to store all of my string keys, so I won’t make any typos in my code. ?
That’s how it looks:
/// <summary> /// This class contains constant strings for use in code. /// </summary> public static class Keys { public const string ANIMATION_SPEED_KEY = "Speed"; public const string ANIMATION_INAIR_KEY = "InAir"; public const string ANIMATION_AIRSPEED_KEY = "AirSpeed"; }
So the result of that code is…
That’s not yet completed! As you can see, our character is not moving! And it’s not changing direction…
Because we are using Rigidbody (and physics system) for our movement, we should only move our character in FixedUpdate method!
So let’s do just that!
using UnityEngine; /// <summary> /// Simple Character movement. /// </summary> [RequireComponent(typeof(Animator))] [RequireComponent(typeof(Rigidbody2D))] public class CharacterMovement : MonoBehaviour { ... /// <summary> /// Called on each physics frame /// </summary> private void FixedUpdate() { // Get character velocity var velocity = rb.velocity; // Calculate character movement var moveSpeed = 0f; var moveDirection = 1f; // Calculate move speed and direction if (!Mathf.Approximately(horizontalInput, 0)) { moveSpeed = walkSpeed; moveDirection = Mathf.Sign(horizontalInput); } // Set character velocity and direction velocity.x = moveSpeed * moveDirection; transform.localScale = new Vector3(moveDirection, 1, 1); rb.velocity = velocity; } }
And that will make our character walk freely in the scene.
How about running? ?♀️
Walking in games is really boring, so let’s ease that pain by introducing running for our character!
We would need to read another input. This time we will have to define “Sprint” in InputManager.
Go to the Project Settings, and then select Input Manager. Add a new entry and name it “Sprint”.
Now we can use our new “Sprint” button in our code, but we shouldn’t forget about adding a new property to control character running speed.
using UnityEngine; /// <summary> /// Simple Character movement. /// </summary> [RequireComponent(typeof(Animator))] [RequireComponent(typeof(Rigidbody2D))] public class CharacterMovement : MonoBehaviour { ... /// <summary> /// Character Run Speed /// </summary> [SerializeField] private float runSpeed = 1.5f; // Input private float horizontalInput; private bool sprintInput; ... /// <summary> /// Called on each frame /// </summary> private void Update() { // Get input horizontalInput = Input.GetAxisRaw("Horizontal"); sprintInput = Input.GetButton("Sprint"); // Set animation movement speed var animSpeed = horizontalInput * (sprintInput ? 2 : 1); characterAnimator.SetFloat(Keys.ANIMATION_SPEED_KEY, Mathf.Abs(animSpeed)); } /// <summary> /// Called on each physics frame /// </summary> private void FixedUpdate() { ... // Calculate move speed and direction if (!Mathf.Approximately(horizontalInput, 0)) { moveSpeed = sprintInput ? runSpeed : walkSpeed; moveDirection = Mathf.Sign(horizontalInput); } ... } }
After adding all of that code, our character will be able to run! Just like this:
But can it jump? ?
Every 2D platformer need to have jumped! Or at least should have it… ?
So let’s make our character do that! But be aware that it might be a little bit more complex, so pay attention to the code!
First of all, we have to check if our character is on the ground. That information is needed as our character will only jump if it’s on the ground.
using UnityEngine; /// <summary> /// Simple Character movement. /// </summary> [RequireComponent(typeof(Animator))] [RequireComponent(typeof(Rigidbody2D))] public class CharacterMovement : MonoBehaviour { ... [Header("Ground check")] /// <summary> /// Ground check origin offset /// </summary> [SerializeField] private float groundOffsetCheck = 1f; /// <summary> /// Ground check distance /// </summary> [SerializeField] private float groundDistanceCheck = 0.4f; ... /// <summary> /// Checks if player is on the ground. /// </summary> /// <returns><c>true</c>, if on ground, <c>false</c> otherwise.</returns> private bool IsOnGround() { // Get ground layer mask var groundMask = LayerMask.GetMask("Ground"); // Raycasting var origin = rb.position + Vector2.down * groundOffsetCheck; var result = Physics2D.Raycast(origin, Vector2.down, groundDistanceCheck, groundMask); // Draw debug line to adjust parameters Debug.DrawLine(origin, origin + Vector2.down * groundDistanceCheck); // Check if something was hit return result.transform != null; } }
The next step will be to make our character jump! We would have to read another input from the player and extend our FixedUpdate method with code for jumping.
We would also need to pass some info to the Animator, so our character can be properly animated.
using UnityEngine; /// <summary> /// Simple Character movement. /// </summary> [RequireComponent(typeof(Animator))] [RequireComponent(typeof(Rigidbody2D))] public class CharacterMovement : MonoBehaviour { ... // Input private float horizontalInput; private bool sprintInput; private bool jumpInput; // Property - if player is on ground private bool isGrounded = false; ... /// <summary> /// Called on each frame /// </summary> private void Update() { // Get input horizontalInput = Input.GetAxisRaw("Horizontal"); sprintInput = Input.GetButton("Sprint"); jumpInput = Input.GetButtonDown("Jump"); ... } /// <summary> /// Called on each physics frame /// </summary> private void FixedUpdate() { ... // Check if grounded isGrounded = IsOnGround(); // Assign ground status to animator characterAnimator.SetBool(Keys.ANIMATION_INAIR_KEY, !isGrounded); // Initial jump only on ground if (isGrounded) { if (jumpInput) { velocity.y = jumpForce; } } // Set air velocity characterAnimator.SetFloat(Keys.ANIMATION_AIRSPEED_KEY, velocity.y); ... } ... }
This should make our character jump!
I need double jump! ?
Okay, I missed that one… But yeah, we need a double jump!
Luckily, this won’t be that hard to implement at this point! ?
using UnityEngine; /// <summary> /// Simple Character movement. /// </summary> [RequireComponent(typeof(Animator))] [RequireComponent(typeof(Rigidbody2D))] public class CharacterMovement : MonoBehaviour { ... // Property - if player can do second jump private bool consumedDoubleJump = false; ... /// <summary> /// Called on each physics frame /// </summary> private void FixedUpdate() { ... // Initial jump only on ground if (isGrounded) { consumedDoubleJump = false; if (jumpInput) { velocity.y = jumpForce; } } else { // Double jump if (!consumedDoubleJump && jumpInput) { velocity.y = jumpForce; consumedDoubleJump = true; } } ... } }
Result! ?
So it’s finally time to see the character movement completed!
I hope you enjoyed this little journey with me! Let me know what you think of it in the comment section below! ?
If you know someone that might need this, share it with him! I would really appreciate that! ?
Besides that, if you want to get notified about future content on my blog, you can sign up for my newsletter!
The whole project is available at my public repository. ?
See you next time! ?