~4 min read

Physics — Rigidbody, Collider and Collisions

How to move objects with physics and react to collisions.

Иллюстрация: Physics — Rigidbody, Collider and Collisions

Unity uses NVIDIA’s PhysX for 3D physics (for 2D — Box2D). This means: rigid body simulation, collisions, forces, joints. All of it works out of the box; your job is to configure the components correctly.

Three classes of participants

  1. Static — a GameObject with a Collider but no Rigidbody. It does not move, ideal for walls, floors, static geometry.
  2. Kinematic — a Rigidbody with isKinematic = true. Moves only through your script (via MovePosition / MoveRotation), does not react to forces.
  3. Dynamic — an ordinary Rigidbody. Reacts to gravity, forces, collisions.
Moving a static collider is bad

If an object has no Rigidbody, Unity caches it in the so-called “static collider tree”. Moving such a collider every frame forces PhysX to rebuild the tree — expensive. Need to move something without physics? Add a Rigidbody with isKinematic = true.

Rigidbody

Key fields:

  • mass — mass in kg.
  • linearVelocity (formerly velocity) — current linear velocity in m/s. The old name velocity is marked [Obsolete] in Unity 6.
  • angularVelocity — angular velocity in rad/s.
  • linearDamping / angularDamping — the new names in Unity 6 scripting (formerly drag / angularDrag). The old names drag/angularDrag still work and are not marked [Obsolete]; in the Inspector the properties are still displayed as “Linear Drag” / “Angular Drag”.
  • useGravity — whether to apply Physics.gravity (default (0, -9.81, 0)).
  • isKinematic — whether it is controlled only by scripts.
  • interpolationNone / Interpolate / Extrapolate. Smooths movement between physics steps. For the player you usually set Interpolate.
  • collisionDetectionModeDiscrete / Continuous / ContinuousDynamic / ContinuousSpeculative. For fast objects (bullets, balls) the Continuous variants are important to avoid “tunneling” through thin colliders.
`velocity` → `linearVelocity` in Unity 6

In Unity 6 the velocity field is marked [Obsolete] (the compiler will emit a warning) — use linearVelocity in new code. For drag/angularDrag no Obsolete marker is set yet, but in new projects linearDamping/angularDamping are idiomatic. angularVelocity was not renamed.

public class Ball : MonoBehaviour
{
    private Rigidbody _rb;

    private void Awake() {
        _rb = GetComponent<Rigidbody>();
    }

    private void FixedUpdate() {
        // Impulse — an instantaneous change in velocity
        if (Input.GetKey(KeyCode.Space)) {
            _rb.AddForce(Vector3.up * 10f, ForceMode.Impulse);
        }
    }
}

Force modes

AddForce takes a ForceMode:

ModeMeaningFormula
ForceA force applied continuouslyΔv = (F/m) * dt
AccelerationAcceleration ignoring massΔv = a * dt
ImpulseAn instantaneous impulseΔv = F/m
VelocityChangeAn instantaneous change in velocityΔv = F

For a jump you usually use Impulse or VelocityChange. For continuous thrust (a rocket engine) — Force.

Collider — the shape for physics

A Collider describes the collision geometry. There are several types:

  • BoxCollider, SphereCollider, CapsuleCollider — primitives. Cheap, precise.
  • MeshCollider — an arbitrary mesh. Expensive. Must be convex if the object is dynamic.
  • TerrainCollider — for terrain.
  • WheelCollider — specialized, for vehicles (with suspension and tire friction).
Use primitives where possible

Complex static geometry? A single MeshCollider is enough. A dynamic object with a complex shape? Assemble it from several BoxCollider/SphereCollider — performance is orders of magnitude higher than with a single MeshCollider.

Triggers vs collisions

A Collider has an isTrigger flag. If it is enabled, the object does not block others — but it generates OnTrigger* events. Without isTrigger it is a physical collision, generating OnCollision*.

// Collecting coins via a trigger
private void OnTriggerEnter(Collider other) {
    if (other.CompareTag("Player")) {
        ScoreManager.Instance.Add(1);
        Destroy(gameObject);
    }
}

// Reacting to a collision
private void OnCollisionEnter(Collision collision) {
    var contact = collision.GetContact(0);
    Debug.Log($"Hit at {contact.point}, force: {collision.impulse.magnitude:F2}");
    AudioSource.PlayClipAtPoint(_hitSound, contact.point);
}

Event invocation rules

Not intuitive, but critical to understand:

Object AObject BOnCollisionOnTrigger
Static colliderStatic collider
Static colliderDynamic RigidbodyYes (on both)Yes, if isTrigger
Dynamic RigidbodyDynamic RigidbodyYes (on both)Yes, if isTrigger
Kinematic RigidbodyStatic colliderYes, if isTrigger
Kinematic RigidbodyDynamic RigidbodyYesYes, if isTrigger
Kinematic RigidbodyKinematic RigidbodyYes, if isTrigger

Remember the main point: for OnCollisionEnter at least one of the objects must be a non-kinematic Rigidbody. For OnTriggerEnter a single Rigidbody of any type is enough.

Layers and the Layer Collision Matrix

Every GameObject has a Layer (0..31). In Project Settings → Physics → Layer Collision Matrix you enable/disable interactions between layers. Example use:

  • The Player layer does not collide with Trigger.
  • The Bullet layer collides with Enemy, but not with other Bullets.

This is more efficient than filtering in OnCollisionEnter — PhysX will not even fire the event if the layers do not interact.

Raycast and physics

We already saw this in the input chapter. The full API:

// A simple raycast
if (Physics.Raycast(origin, direction, out RaycastHit hit, maxDistance, layerMask)) { }

// Multiple hits
RaycastHit[] hits = Physics.RaycastAll(ray, maxDistance, layerMask);

// A "thick" ray — SphereCast / CapsuleCast / BoxCast
Physics.SphereCast(origin, radius, direction, out hit, maxDistance);

// Not a ray, but an area check
Collider[] inSphere = Physics.OverlapSphere(center, radius, layerMask);

layerMask is a bitmask of the layers the ray passes through. Convenient with LayerMask.GetMask("Enemy", "Wall").

CharacterController vs Rigidbody for the player

There are two approaches to controlling a character:

  1. CharacterController — a special component with a capsule shape. Does not use a Rigidbody, does not react to forces. You have full control via Move(). Ideal for first-person shooters and platformers — where you need predictability rather than simulation.
  2. Rigidbody + CapsuleCollider — a physical character. Realistic collisions, but it requires careful tuning of damping, max-slope handling, anti-slide.
// CharacterController
public class FpsMove : MonoBehaviour
{
    private CharacterController _cc;
    private Vector3 _velocity;
    [SerializeField] private float speed = 5f;
    [SerializeField] private float gravity = -20f;

    private void Awake() => _cc = GetComponent<CharacterController>();

    private void Update() {
        float h = Input.GetAxis("Horizontal");
        float v = Input.GetAxis("Vertical");
        Vector3 move = transform.right * h + transform.forward * v;
        _cc.Move(move * speed * Time.deltaTime);

        if (_cc.isGrounded && _velocity.y < 0) _velocity.y = -2f;
        _velocity.y += gravity * Time.deltaTime;
        _cc.Move(_velocity * Time.deltaTime);
    }
}

We will examine this scheme in more detail in the practical chapter.

In the next chapter — the camera and Cinemachine.