1. Set up the scene
- Add a Rigidbody2D (Gravity Scale 3 to 4 feels snappy) and a collider to the player.
- Add an empty child at the feet named GroundCheck.
- Put ground colliders on a Ground layer.
2. The controller
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class PlatformerController : MonoBehaviour
{
public float moveSpeed = 7f;
public float jumpForce = 12f;
public float coyoteTime = 0.1f;
public float jumpBuffer = 0.1f;
public Transform groundCheck;
public float groundRadius = 0.15f;
public LayerMask groundMask;
Rigidbody2D rb;
float coyoteCounter, bufferCounter, input;
void Awake() => rb = GetComponent<Rigidbody2D>();
void Update()
{
input = Input.GetAxisRaw("Horizontal");
bool grounded = Physics2D.OverlapCircle(groundCheck.position, groundRadius, groundMask);
coyoteCounter = grounded ? coyoteTime : coyoteCounter - Time.deltaTime;
bufferCounter = Input.GetButtonDown("Jump") ? jumpBuffer : bufferCounter - Time.deltaTime;
if (bufferCounter > 0f && coyoteCounter > 0f)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpForce);
bufferCounter = 0f;
coyoteCounter = 0f;
}
// Variable jump height: releasing early cuts the jump short.
if (Input.GetButtonUp("Jump") && rb.linearVelocity.y > 0f)
rb.linearVelocity = new Vector2(rb.linearVelocity.x, rb.linearVelocity.y * 0.5f);
}
void FixedUpdate() => rb.linearVelocity = new Vector2(input * moveSpeed, rb.linearVelocity.y);
}This uses Unity 6's linearVelocity; in older versions use velocity. It reads the classic Input Manager; with the Input System package, read the same actions from your input asset.
3. Why the three feel features matter
| Feature | What the player feels |
|---|---|
| Coyote time | Jumps right after running off a ledge still work, so the game feels fair |
| Jump buffer | A jump pressed just before landing still happens, so the game feels responsive |
| Variable height | Tap for a small hop, hold for a high jump, giving control |
4. Tune it
Make the jump a little too snappy first, then tone it down. Raise gravity scale for a heavier fall. Add a small fall gravity multiplier so descent is faster than ascent. Playtest with other people, because feel is subjective.
5. Next steps
Add a dash, wall slide and animations, then design a small map. How to make your own Hollow Knight is the roadmap, and how to animate a character in Blender covers rigs for 3D characters. For an art look, see Readable Pixels.
Questions
Use a Rigidbody2D, set horizontal velocity from input, check the ground with an overlap circle and set vertical velocity to jump.
A short grace period after leaving a ledge during which the player can still jump.
A Rigidbody2D works well for physics-based platformers. Some teams write kinematic controllers for pixel-exact movement.
The same logic applies. In Godot, use CharacterBody2D and track the same timers.
Who wrote this
Imersa Studios builds the Unity systems, low poly packs and field guides sold on itch.io. The code and techniques here come from shipping those products. More about the studio.

