Unity Physics (Rigidbody / PhysX)
Make objects move, collide, and detect each other with Unity 6.3 LTS's built-in 3D physics
(PhysX). Get the FixedUpdate discipline, trigger-vs-collision rules, and collision layers
right. Targets Unity 6.3 LTS (6000.3).
Unity 6.3 LTS rename:
Rigidbody.velocityis nowRigidbody.linearVelocity(the old name is deprecated). Code copied from older tutorials will warn or fail to compile.
When to use
- Use when giving an object physical motion (forces, velocity, gravity), responding to collisions or triggers, setting up collision layers/masks, raycasting for ground checks or line-of-sight, or connecting bodies with joints.
- Use when scenes/prefabs contain
Rigidbody+Collidercomponents.
When not to use: 2D physics (Rigidbody2D, Collider2D) is a separate API β adapt the
concepts but the types differ. Cross-engine feel tuning (timestep, jitter, tunnelling) β
physics-tuning. Reading input that drives movement β unity-input-system.
Core workflow
- Add a
Rigidbodyto anything that should be simulated; add aColliderto anything that should be hit. A collision needs aCollideron both, and at least oneRigidbody. - Do all physics in
FixedUpdate. Read input inUpdate, store intent, then apply forces / setlinearVelocity/ callMovePositioninFixedUpdate. - Move bodies through the physics API, not the Transform. Use
AddForce,linearVelocity, orMovePositionβ never assigntransform.positionto a non-kinematic Rigidbody (it teleports and breaks collision resolution). - Pick collision vs trigger. A solid collision blocks and calls
OnCollisionEnter; aColliderwithIs Triggerchecked passes through and callsOnTriggerEnter. - Organise interactions with layers. Put objects on layers and edit the Layer Collision Matrix (Project Settings β Physics) so unrelated things don't test against each other.
- Verify with the Physics Debugger (Window β Analysis β Physics Debugger) and by watching for jitter; if fast objects pass through walls, raise Collision Detection mode.
Patterns
1. Force-based movement in FixedUpdate (with a speed clamp)
using UnityEngine;
[RequireComponent(typeof(Rigidbody))]
public class Mover : MonoBehaviour
{
[SerializeField] private float accel = 30f, maxSpeed = 8f;
private Rigidbody _rb;
private Vector3 _input; // set from Update / input system
private void Awake() => _rb = GetComponent<Rigidbody>();
private void FixedUpdate()
{
_rb.AddForce(_input * accel, ForceMode.Acceleration); // mass-independent accel
// Unity 6.3 LTS: linearVelocity (was 'velocity'). Clamp horizontal speed.
Vector3 flat = new(_rb.linearVelocity.x, 0, _rb.linearVelocity.z);
if (flat.magnitude > maxSpeed)
{
flat = flat.normalized * maxSpeed;
_rb.linearVelocity = new Vector3(flat.x, _rb.linearVelocity.y, flat.z);
}
}
}ForceMode: Force (continuous, mass-scaled), Acceleration (continuous, ignores mass),
Impulse (instant, mass-scaled β jumps), VelocityChange (instant, ignores mass).
2. Collision vs trigger callbacks
// Solid hit: both have colliders, this one has a (non-kinematic) Rigidbody.
private void OnCollisionEnter(Collision col)
{
Debug.Log($"Hit {col.gameObject.name} at {col.contacts[0].point}");
}
// Overlap: one collider has 'Is Trigger' = true. Requires a Rigidbody on at least one party.
private void OnTriggerEnter(Collider other)
{
if (other.CompareTag("Pickup")) Destroy(other.gameObject);
}3. Ground check with a layer-masked raycast
[SerializeField] private LayerMask groundMask; // set to your "Ground" layer in the Inspector
private bool IsGrounded()
{
// Cast a short ray down; only test colliders on groundMask.
return Physics.Raycast(transform.position, Vector3.down, out RaycastHit hit,
1.1f, groundMask);
}4. Kinematic platform that still pushes bodies
// isKinematic Rigidbody: not driven by forces, but MovePosition interpolates and carries
// resting bodies correctly (unlike moving the Transform directly).
private void FixedUpdate() => _rb.MovePosition(_rb.position + Vector3.right * (2f * Time.fixedDeltaTime));Pitfalls
Rigidbody.velocitydoesn't exist in Unity 6.3 LTS β uselinearVelocity(andangularVelocityis unchanged).- Setting
transform.positionon a dynamic Rigidbody β teleports it, skips collision. UseMovePosition(kinematic/interpolated) or apply forces. If you do write the transform, physics queries (Raycast,OverlapSphere) see the old position until the next physics step β callPhysics.SyncTransforms()once before a same-frame query, never every frame. OnCollisionEnternever fires on aCharacterControllerβCharacterController.Movebypasses the Rigidbody system; it reports hits viaOnControllerColliderHit(ControllerColliderHit)instead. Don't add a Rigidbody to "fix" it β the two are mutually exclusive movement modes.Physics.Raycastignores triggers by default β a ray won't report a trigger collider unless you passQueryTriggerInteraction.Collide(or flip the globalPhysics.queriesHitTriggers/ Project Settings β Physics β Queries Hit Triggers). It also returnsfalsewhen the ray origin starts inside the target collider.- A resting Rigidbody stays put after you move or disable what it rests on β below the
Sleep Threshold a body goes to sleep. Collisions and
AddForcewake it automatically, but moving a static collider (no Rigidbody) via its Transform may not, so the crate hangs in mid-air when the floor slides away. CallRigidbody.WakeUp()on the affected bodies. - Applying forces in
Updateβ frame-rate-dependent and jittery. Physics goes inFixedUpdate. - Trigger callbacks never fire β triggers need a
Rigidbodyon at least one of the two colliders, and both colliders enabled; two static triggers don't report overlaps. - Fast objects pass through walls (tunnelling) β raise the Rigidbody's Collision Detection
from
Discrete. NoteContinuoussweeps against static colliders only (it falls back to Discrete against other dynamic bodies);Continuous Dynamicalso sweeps against other continuous dynamic bodies;Continuous Speculativeworks against everything and is cheaper. For bullets, also consider aSphereCast/Raycastalong the trajectory instead of a collider. - Non-uniform-scaled
MeshColliders or scaled colliders misbehave; prefer primitive colliders and keep scale uniform. - A concave
MeshCollideron a moving body β Mesh colliders are concave by default, and concave ones can only be static or kinematic; two concave colliders never collide at all. For a dynamic Rigidbody enable Convex on the MeshCollider, or build a compound collider from primitives. - Everything collides with everything β wasted cost; assign layers and prune the Layer Collision Matrix.
References
- For raycast variants (
SphereCast,RaycastAll,OverlapSphere,LayerMaskbit math) and joints (FixedJoint,HingeJoint,ConfigurableJoint, breakable joints), readreferences/raycasting-and-joints.md. - Primary docs: Unity Manual "Physics" section and
ScriptReference/Rigidbody,ScriptReference/Physics.Raycast. For the added gotchas:ScriptReference/CollisionDetectionMode,ScriptReference/Physics-queriesHitTriggers,ScriptReference/MonoBehaviour.OnControllerColliderHit,ScriptReference/Physics.SyncTransforms,ScriptReference/Rigidbody.WakeUp, and the Manual pages "Introduction to rigid body physics" (sleeping) and "Introduction to Mesh colliders" (concave vs convex).
Related skills
physics-tuningβ engine-agnostic feel: fixed timestep, mass/drag, CCD, stability.unity-csharp-scriptingβ theFixedUpdate/Updatesplit these patterns rely on.unity-navmeshβ agent movement that is not force-driven.