| # 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): |
| ```csharp |
| _rb.AddForce(Vector3.up * jumpForce, ForceMode.VelocityChange); |
| _rb.AddForceAtPosition(force, wheel.position, ForceMode.Force); |
| ``` |
|
|
| 2. **Direct velocity set** (preferred for arcade controllers): |
| ```csharp |
| 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. |
|
|
| ```csharp |
| private void OnTriggerEnter(Collider other) |
| { |
| if (other.CompareTag("Player")) |
| Debug.Log("Player entered the zone"); |
| } |
| ``` |
|
|
| ## Raycasting |
|
|
| ```csharp |
| // 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: |
|
|
| ```csharp |
| 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). |
|
|