Physics Systems (2D and 3D)¶
Component Equivalents¶
| 3D | 2D |
|---|---|
| Rigidbody | Rigidbody2D |
| Collider (Box, Sphere, Capsule, Mesh) | Collider2D (Box, Circle, Capsule, Polygon, Composite) |
| OnCollisionEnter/Stay/Exit | OnCollisionEnter2D/Stay2D/Exit2D |
| OnTriggerEnter/Stay/Exit | OnTriggerEnter2D/Stay2D/Exit2D |
| Physics.Raycast | Physics2D.Raycast |
| PhysicsMaterial | PhysicsMaterial2D |
Rigidbody Types¶
- Dynamic: Fully simulated. Responds to forces, gravity, and collisions. Use for players, projectiles, physics objects.
- Kinematic: Not affected by forces or gravity. Moves only via script (
MovePosition,MoveRotation). Use for platforms, doors, elevators. - Static: Does not move at all. Use for walls, floors, terrain colliders. A Collider without a Rigidbody is implicitly static.
Collision Detection¶
Collision Callbacks (require both objects to have colliders, at least one with Rigidbody)¶
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("Ground"))
{
_isGrounded = true;
}
}
Trigger Callbacks (one collider must have "Is Trigger" enabled)¶
private void OnTriggerEnter(Collider other)
{
if (other.TryGetComponent<ICollectible>(out var collectible))
{
collectible.Collect();
}
}
Raycasting¶
Basic Raycast¶
if (Physics.Raycast(transform.position, transform.forward, out RaycastHit hit, 100f))
{
Debug.Log($"Hit: {hit.collider.name} at {hit.point}");
}
NonAlloc Raycasting (zero-allocation)¶
Pre-allocate a results buffer and reuse it every frame:
private readonly RaycastHit[] _raycastResults = new RaycastHit[10];
private void FixedUpdate()
{
int count = Physics.RaycastNonAlloc(
transform.position, transform.forward,
_raycastResults, 100f
);
for (int i = 0; i < count; i++)
{
ProcessHit(_raycastResults[i]);
}
}
Other NonAlloc variants: Physics.SphereCastNonAlloc, Physics.BoxCastNonAlloc, Physics.OverlapSphereNonAlloc, Physics.OverlapBoxNonAlloc.
LayerMask Filtering¶
[SerializeField] private LayerMask _groundLayer;
private bool CheckGround()
{
return Physics.Raycast(transform.position, Vector3.down, 1.1f, _groundLayer);
}
Physics Rules¶
- ALWAYS use FixedUpdate for physics code (forces, velocity, MovePosition)
- NEVER move a Rigidbody with
transform.positiondirectly; useRigidbody.MovePositionor apply forces - NEVER scale physics objects non-uniformly; it causes unstable collision behavior
- Use
Physics.SyncTransforms()only when you must read physics state immediately after moving transforms - Use Continuous collision detection for fast-moving objects to prevent tunneling
Joints¶
3D Joints¶
- HingeJoint: Rotation around a single axis (doors, wheels)
- SpringJoint: Elastic connection between two bodies
- FixedJoint: Rigid connection (welding objects together)
- CharacterJoint: Ragdoll limb connections
- ConfigurableJoint: Full control over all axes
2D Joints¶
- HingeJoint2D, SpringJoint2D, FixedJoint2D, DistanceJoint2D, SliderJoint2D
Physics Materials¶
Control friction and bounciness:
Friction: 0.0 (ice) to 1.0 (rubber)
Bounciness: 0.0 (no bounce) to 1.0 (full bounce)
Friction Combine: Average, Minimum, Maximum, Multiply
Bounce Combine: Average, Minimum, Maximum, Multiply
Common Gotchas¶
- A Collider without a Rigidbody is static. Moving it forces Unity to rebuild the physics world (expensive).
- Triggers do not generate collision contacts. Use OnTriggerEnter, not OnCollisionEnter.
- Scale affects collider size. Non-uniform scale on mesh colliders is especially problematic.
- 2D and 3D physics are completely separate systems. A Rigidbody2D does not interact with a 3D Collider.
- Rigidbody.isKinematic prevents all physics forces. Use it for scripted movement.