When creating 2D games in Unity, setting up smooth player movement that respects game world collisions is essential. In this guide, we’ll walk through the process of building a basic 2D character controller that handles movement and rigidbody collision detection using Unity’s physics system.
Prerequisites
- Unity installed (version 2020 or newer recommended)
- Familiarity with Unity’s basic components
- Understanding of the Unity physics system (especially Rigidbody2D)
We will also utilize the new Input System package, so make sure your project has it installed and set up.
Step 1: Adding Components to the Player
To begin, ensure your player GameObject has the following components:
- Rigidbody2D: Set the body type to
Kinematic
, as we are moving the player through scripts. - Collider2D: Use a suitable collider such as
BoxCollider2D
orCapsuleCollider2D
to define the player’s collision shape. - PlayerInput: This component integrates with Unity’s new Input System.
These components ensure that your player GameObject can detect and interact with collision shapes.
Step 2: Writing the Player Script
Here’s a complete script for handling player movement and collision detection:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class Player : MonoBehaviour
{
public float moveSpeed = 1f;
public float collisionOffset = 0.05f;
public ContactFilter2D movementFilter;
private Vector2 moveInput;
private List<RaycastHit2D> castCollisions = new List<RaycastHit2D>();
private Rigidbody2D rb;
public void Start()
{
rb = GetComponent<Rigidbody2D>();
}
public void FixedUpdate()
{
bool success = MovePlayer(moveInput);
if (!success)
{
success = MovePlayer(new Vector2(moveInput.x, 0));
if (!success)
{
success = MovePlayer(new Vector2(0, moveInput.y));
}
}
}
public bool MovePlayer(Vector2 direction)
{
int count = rb.Cast(
direction,
movementFilter,
castCollisions,
moveSpeed * Time.fixedDeltaTime + collisionOffset);
if (count == 0)
{
Vector2 moveVector = direction * moveSpeed * Time.fixedDeltaTime;
rb.MovePosition(rb.position + moveVector);
return true;
}
else
{
return false;
}
}
public void OnMove(InputValue value)
{
moveInput = value.Get<Vector2>();
}
public void OnFire()
{
Debug.Log("Shots fired");
}
}
Step 3: Understanding the Key Script Components
Collision Detection
The script uses Rigidbody2D.Cast()
to check for potential collisions before moving the player.
- Direction: Determines where to cast the detection ray.
- Movement Filter: Specifies what layers can block movement.
- Collision Offset: A small buffer to prevent the player from getting stuck.
Handling Smooth Movement
When diagonal movement causes a collision, the player checks horizontal and vertical paths independently, ensuring fluid sliding behavior along obstacles.
FixedUpdate vs Update
We use FixedUpdate
instead of Update
because physics interactions should be handled in FixedUpdate
for consistent and accurate results.
Step 4: Setting Up the Movement Filter
In Unity, configure the ContactFilter2D
by selecting the appropriate collision layers under the Player component’s settings. This ensures the player interacts only with specified objects.
Step 5: Testing the Movement
- Attach the script to your player GameObject.
- Set the Rigidbody2D to
Kinematic
. - Assign movement values for speed and configure the collision offset as needed.
- Press Play and test movement.
Troubleshooting Tips
- Ensure your player and obstacles have colliders.
- Verify that the Rigidbody2D component is set to
Kinematic
. - Double-check the layers in the ContactFilter2D settings.
Conclusion
By following these steps, you now have a basic player movement setup with collision handling in Unity. This approach provides a smooth and responsive movement system, allowing characters to slide along obstacles and ensuring a more polished gameplay experience. Happy coding!