Contents hide
In this post I will be showing how to make a Character Controller for 2D Platformer using Physics 2D components in Unity. The controller will handle movement, jumping and Camera follow.
So let’s begin!
Steps
- Open Scene with your 2D level (Make sure that sprites have 2D colliders attached so the player won’t fall throug them)
- Create new Game Object and call it “Player”
- Create another Game Object, call it “player_sprite” and add Sprite Renderer component to it
- Assign your sprite and move “player_sprite” inside the “Player” Object
- Create new script, call it “CharacterController2D” and paste the code below inside it:
CharacterController2D.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(CapsuleCollider2D))]
public class CharacterController2D : MonoBehaviour
{
// Move player in 2D space
public float maxSpeed = 3.4f;
public float jumpHeight = 6.5f;
public float gravityScale = 1.5f;
public Camera mainCamera;
bool facingRight = true;
float moveDirection = 0;
bool isGrounded = false;
Vector3 cameraPos;
Rigidbody2D r2d;
Collider2D mainCollider;
// Check every collider except Player and Ignore Raycast
LayerMask layerMask = ~(1 << 2 | 1 << 8);
Transform t;
// Use this for initialization
void Start()
{
t = transform;
r2d = GetComponent<Rigidbody2D>();
mainCollider = GetComponent<Collider2D>();
r2d.freezeRotation = true;
r2d.collisionDetectionMode = CollisionDetectionMode2D.Continuous;
r2d.gravityScale = gravityScale;
facingRight = t.localScale.x > 0;
gameObject.layer = 8;
if(mainCamera)
cameraPos = mainCamera.transform.position;
}
// Update is called once per frame
void Update()
{
// Movement controls
if ((Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.D)) && (isGrounded || r2d.velocity.x > 0.01f))
{
moveDirection = Input.GetKey(KeyCode.A) ? -1 : 1;
}
else
{
if (isGrounded || r2d.velocity.magnitude < 0.01f)
{
moveDirection = 0;
}
}
// Change facing direction
if (moveDirection != 0)
{
if (moveDirection > 0 && !facingRight)
{
facingRight = true;
t.localScale = new Vector3(Mathf.Abs(t.localScale.x), t.localScale.y, transform.localScale.z);
}
if (moveDirection < 0 && facingRight)
{
facingRight = false;
t.localScale = new Vector3(-Mathf.Abs(t.localScale.x), t.localScale.y, t.localScale.z);
}
}
// Jumping
if (Input.GetKeyDown(KeyCode.W) && isGrounded)
{
r2d.velocity = new Vector2(r2d.velocity.x, jumpHeight);
}
// Camera follow
if(mainCamera)
mainCamera.transform.position = new Vector3(t.position.x, cameraPos.y, cameraPos.z);
}
void FixedUpdate()
{
Bounds colliderBounds = mainCollider.bounds;
Vector3 groundCheckPos = colliderBounds.min + new Vector3(colliderBounds.size.x * 0.5f, 0.1f, 0);
// Check if player is grounded
isGrounded = Physics2D.OverlapCircle(groundCheckPos, 0.23f, layerMask);
// Apply movement velocity
r2d.velocity = new Vector2((moveDirection) * maxSpeed, r2d.velocity.y);
// Simple debug
Debug.DrawLine(groundCheckPos, groundCheckPos - new Vector3(0, 0.23f, 0), isGrounded ? Color.green : Color.red);
}
}
- Attach CharacterController2D script to “Player” Object (You’ll notice it also added other components called Rigidbody2D and CapsuleCollider2D)
- Tweak Capsule Collider 2D dimensions until they match the player Sprite
In CharacterController2D you have an option to assign the Main Camera variable which could be any Camera that will follow the player:
The 2D Character Controller is now ready!