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 type | Behaviour | Typical use |
|---|---|---|
Dynamic | Fully simulated — responds to forces, gravity, and collisions | Moving enemies, projectiles, falling objects |
Kinematic | Moves via script only — not affected by forces or gravity; still detects collisions | Player characters, moving platforms |
Static | Does not move | Walls, 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:
0for 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.Translateor settransform.positiondirectly on a Dynamic Rigidbody2D — this bypasses the physics engine and causes jitter, missed collisions, and tunnelling. Userb.linearVelocity,AddForce, or (for Kinematic)rb.MovePosition. - Read input in
Update; apply it inFixedUpdate. CallingInput.GetAxisRawinFixedUpdateis often acceptable for held movement axes in small beginner demos, but it can miss one-frame button events that occur between physics steps. rb.linearVelocityis the Unity 6 API name. In older Unity versions (pre-6), the property isrb.velocity. Both refer to the same thing.
Related
- unity-collider2d-and-triggers — collision and trigger detection
- monobehaviour-lifecycle —
FixedUpdateandAwakein the lifecycle - unity-transform — transform-based movement (use instead of Rigidbody2D on non-physics objects)
- unity-getcomponent — caching the Rigidbody2D reference