Summary

Rigidbody2D is the Unity component that makes a 2D GameObject participate in the physics simulation. It enables realistic movement driven by forces and velocities, and is required for OnCollisionEnter2D and OnTriggerEnter2D callbacks to fire on a moving object. There are three body types, each suited to a different role. Physics-related code belongs in FixedUpdate, which runs on a fixed timestep independent of frame rate.


Key ideas

Body types:

Body typeBehaviourTypical use
DynamicFully simulated — responds to forces, gravity, and collisionsMoving enemies, projectiles, falling objects
KinematicMoves via script only — not affected by forces or gravity; still detects collisionsPlayer characters, moving platforms
StaticDoes not moveWalls, floors, static hazards

Gravity Scale: How strongly gravity pulls the object. Set to 0 for top-down 2D games or for kinematic players that manage their own movement.

Freeze Rotation Z: Prevents the physics engine from rotating the object when it collides. Almost always enabled on player characters — a player that tips over when touching a wall is rarely intentional.

FixedUpdate(): The correct place for all physics and Rigidbody2D calls. It runs on Unity’s fixed timestep (default 50 times per second), independent of frame rate. Calling physics in Update causes frame-rate-dependent behaviour — the physics will feel different on machines with different performance.

rb.linearVelocity (Unity 6) / rb.velocity (older Unity): Direct velocity assignment gives crisp, predictable movement. Setting velocity directly is preferred for character movement over AddForce, which introduces acceleration drift.

AddForce(direction * magnitude, ForceMode2D.Impulse): Applies the entire force in a single physics step. Use for one-shot impulses: knockback, jump, explosion.

Vector2.normalized: Returns a direction vector with a magnitude of exactly 1. Normalising before multiplying by speed prevents diagonal movement from being faster than horizontal or vertical movement (diagonal magnitude is √2 ≈ 1.41 without normalisation).

Vector2.ClampMagnitude(velocity, maxSpeed): Limits the magnitude of a vector without changing its direction. Use as a speed cap to prevent velocity accumulating beyond a safe maximum.


In practice

Caching Rigidbody2D in Start:

private Rigidbody2D rb;
 
private void Awake()
{
    rb = GetComponent<Rigidbody2D>();
    if (rb == null) Debug.LogError("[PlayerPhysics] No Rigidbody2D found!");
}

Physics movement in FixedUpdate:

private Vector2 moveInput;
 
private void Update()
{
    float h = Input.GetAxisRaw("Horizontal");
    float v = Input.GetAxisRaw("Vertical");
 
    // Store input for the next physics step
    moveInput = new Vector2(h, v).normalized;
}
 
private void FixedUpdate()
{
    HandleMovement();
    EnforceSpeedCap();
}
 
private void HandleMovement()
{
    // Direct velocity assignment — crisp, predictable
    rb.linearVelocity = moveInput * moveSpeed;
}
 
private void EnforceSpeedCap()
{
    // Preserves direction while clamping magnitude
    rb.linearVelocity = Vector2.ClampMagnitude(rb.linearVelocity, maxSpeed);
}

Read this as two clocks working together. Update runs once per rendered frame and records the latest player input. FixedUpdate runs on Unity’s physics timestep and applies that stored input to the Rigidbody2D. This separation is more reliable than mixing all input and physics work into one method, especially when a project grows beyond held movement keys.

Knockback impulse:

public void ApplyKnockback(Vector2 sourcePosition)
{
    // Direction: away from the damage source
    Vector2 direction = ((Vector2)transform.position - sourcePosition).normalized;
 
    rb.linearVelocity = Vector2.zero;  // clear existing velocity for clean impulse
    rb.AddForce(direction * knockbackForce, ForceMode2D.Impulse);
}

Invoke for timed callbacks (e.g. ending a knockback window):

isKnockedBack = true;
Invoke("EndKnockback", knockbackDuration);  // calls EndKnockback() after N seconds
 
private void EndKnockback()
{
    isKnockedBack = false;
}

Inspector setup checklist

For a typical 2D player character:

  • Body Type: Kinematic (if script-driven) or Dynamic (if physics-driven)
  • Gravity Scale: 0 for top-down; keep default for platformer
  • Freeze Rotation → Z: enabled (prevents tipping on collision)
  • Attach the Rigidbody2D to the same GameObject as the movement script

Gotchas

  • Never use transform.Translate or set transform.position directly on a Dynamic Rigidbody2D — this bypasses the physics engine and causes jitter, missed collisions, and tunnelling. Use rb.linearVelocity, AddForce, or (for Kinematic) rb.MovePosition.
  • Read input in Update; apply it in FixedUpdate. Calling Input.GetAxisRaw in FixedUpdate is often acceptable for held movement axes in small beginner demos, but it can miss one-frame button events that occur between physics steps.
  • rb.linearVelocity is the Unity 6 API name. In older Unity versions (pre-6), the property is rb.velocity. Both refer to the same thing.