ryzerrr's picture
Upload folder using huggingface_hub
40c0886 verified
|
Raw
History Blame Contribute Delete
4.12 kB

Unity Physics

Unity ships two physics engines: 3D (NVIDIA PhysX) and 2D (Box2D). This document covers 3D physics, which is what the open-world city example uses.

Rigidbody

A Rigidbody puts a GameObject under physics control. There are two ways to move a rigidbody:

  1. Force-based (preferred for realistic motion):

    _rb.AddForce(Vector3.up * jumpForce, ForceMode.VelocityChange);
    _rb.AddForceAtPosition(force, wheel.position, ForceMode.Force);
    
  2. Direct velocity set (preferred for arcade controllers):

    Vector3 v = _rb.velocity;
    v.x = desired.x;
    v.z = desired.z;
    _rb.velocity = v;
    
ForceMode Mass dependent? Use case
Force Yes Continuous pushes (default)
Acceleration No Continuous push ignoring mass
Impulse Yes Instantaneous burst (explosion)
VelocityChange No Instantaneous burst (jump)
  • Set rb.freezeRotation = true when you want to control rotation manually (most third-person controllers).
  • Use rb.interpolation = RigidbodyInterpolation.Interpolate to smooth out stutter when the physics timestep (50 Hz) is slower than the render rate (60+ Hz).
  • Set rb.collisionDetectionMode = CollisionDetectionMode.Continuous for fast-moving objects to prevent tunnelling.

Colliders

  • BoxCollider, SphereCollider, CapsuleCollider, MeshCollider are the built-in shapes.
  • MeshCollider should be convex unless the mesh is static (mark Convex in the inspector) -- rigidbodies require convex colliders.
  • Set isTrigger = true to receive OnTriggerEnter/Stay/Exit without physically blocking movement. Use triggers for pickups, zones, audio volumes.
private void OnTriggerEnter(Collider other)
{
    if (other.CompareTag("Player"))
        Debug.Log("Player entered the zone");
}

Raycasting

// Single hit
if (Physics.Raycast(origin, direction, out RaycastHit hit, maxDistance, layerMask))
{
    Debug.Log(hit.collider.name);
}

// Sphere cast -- great for ground checks on characters
if (Physics.SphereCast(origin, radius, Vector3.down, out RaycastHit hit, distance, mask))
{
    _isGrounded = true;
}

// Overlap sphere -- explosions, area damage
Collider[] hits = Physics.OverlapSphere(center, radius);
foreach (var h in hits)
{
    var hp = h.GetComponentInParent<HealthSystem>();
    if (hp != null) hp.TakeDamage(damage);
}

Use QueryTriggerInteraction.Ignore to skip trigger colliders in physics queries unless you explicitly want them.

Layer masks

Layer masks let you filter physics queries and collisions:

public LayerMask groundMask = ~0; // everything by default

if (Physics.Raycast(origin, dir, out _, distance, groundMask)) { ... }

You can also use LayerMask.GetMask("Ground", "Default") to convert names at runtime, but exposing the mask as a serialised field is cleaner.

Physics step vs frame step

Step Method Frequency Use it for
Physics FixedUpdate Fixed (50 Hz by default) rb.AddForce, wheel torque
Frame Update Variable (frame rate) Input.GetAxis, gameplay
Post-frame LateUpdate After all Updates Camera follow

Never read Input in FixedUpdate -- the input system only updates once per frame, so FixedUpdate may run zero or multiple times per frame.

Collision matrix gotchas

  • Two trigger colliders do not fire OnTriggerEnter unless at least one of their GameObjects has a Rigidbody.
  • A Rigidbody marked IsKinematic will not respond to forces but will push other rigidbodies.
  • Adjust the collision matrix in Project Settings > Physics to skip collision between layers (e.g. Player vs. PlayerBullet).