# 6. Physics 2D - Pitfalls and the Physics Core 2D API
Part of [[Physics 2D]]. Previous: [[5. Physics 2D Kinematic Platformer with Slide]]. 3D counterpart: [[7. Physics Pitfalls]].
> [!note] Verification status
> `Physics2D.simulationMode` / `SimulationMode2D` (`FixedUpdate`, `Update`, `Script`), `useSubStepping`, `maxSubStepCount` checked against the 6000.5 reference. The low-level API is documented as **`UnityEngine.LowLevelPhysics2D`** in the 6000.3 Manual ("New in Unity 6.3") and as the **"Physics Core 2D API", namespace `Unity.U2D.Physics`** in the 6000.5 Manual (both checked 2026-11-07) - i.e. it was renamed between those versions. **Code not compiled in Unity.**
## 6.1 Pitfalls table
| Symptom | Cause | Fix |
|---|---|---|
| `OnCollisionEnter` never fires on a sprite | 3D callback on 2D colliders | Use `OnCollisionEnter2D(Collision2D)` / `OnTriggerEnter2D(Collider2D)` |
| Raycast misses a BoxCollider2D | `Physics.Raycast` (3D) used | `Physics2D.Raycast` - 2D and 3D worlds never see each other |
| Changing Project Settings > Physics layer matrix does nothing | That's the 3D matrix | Project Settings > **Physics 2D** |
| Character catches on tile seams | Many box colliders | Composite Collider 2D (Outlines) - Part 2 |
| Fast bullet passes through thin walls | Discrete detection | `CollisionDetectionMode2D.Continuous` on the bullet, or cast ahead with `Rigidbody2D.Cast` |
| Everything feels floaty / slow | Sprites imported at 100 PPU but world scale is huge (e.g. 10 m tall character) | Keep characters ~1-2 units tall; gravity is in units/s^2 |
| Kinematic player doesn't get collision callbacks with walls | Kinematic vs static contacts off | Enable **Use Full Kinematic Contacts** |
| Kinematic player not carried by a moving platform | Kinematic bodies ignore friction | Add platform velocity in your controller |
| Box falls asleep on a platform and floats when the platform moves away | Sleeping body | Move the platform with `MovePosition` (wakes contacts) or `WakeUp()` riders |
| Queries hit the caster itself | Ray starts inside own collider | `Physics2D.queriesStartInColliders = false` or use `Rigidbody2D.Cast` / `Collider2D.Cast` |
| Jitter when camera follows a body | No interpolation | `Interpolate` on the followed body; follow in LateUpdate or via [[Cinemachine 3]] |
| Overlap query with Z filtering behaves oddly | 2D colliders at different Z still *collide*; Z only matters for depth filtering | Don't use Z for gameplay separation; use layers |
| Physics runs at 50 Hz on a 120 Hz display and looks choppy | Default fixed timestep | Interpolation, or `Physics2D.simulationMode = SimulationMode2D.Update` for simple games (variable step = less deterministic) |
## 6.2 Simulation mode and sub-stepping
`Physics2D.simulationMode` decides **when** 2D physics steps:
- `FixedUpdate` (default) - fixed timestep, deterministic-ish, use with interpolation.
- `Update` - once per frame with `Time.deltaTime`. Smooth, simple, but frame-rate-dependent results.
- `Script` - you call `Physics2D.Simulate(dt)` yourself (rollback netcode, replays, deterministic lockstep, turn-based "simulate until rest").
`Physics2D.useSubStepping` + `maxSubStepCount` + `minSubStepFPS` let the step split itself when the frame rate drops, instead of tunneling.
```csharp
using UnityEngine;
/// Steps 2D physics manually: normal speed, slow-mo, and single-step debugging.
public class ManualPhysics2DStepper : MonoBehaviour
{
[SerializeField, Range(0f, 2f)] float timeScale = 1f;
[SerializeField] float fixedStep = 1f / 60f;
[SerializeField] bool paused;
float _accumulator;
void OnEnable() => Physics2D.simulationMode = SimulationMode2D.Script;
void OnDisable() => Physics2D.simulationMode = SimulationMode2D.FixedUpdate;
void Update()
{
if (paused) return;
_accumulator += Time.unscaledDeltaTime * timeScale;
int guard = 0;
while (_accumulator >= fixedStep && guard++ < 8)
{
Physics2D.Simulate(fixedStep);
_accumulator -= fixedStep;
}
}
[ContextMenu("Step Once")]
void StepOnce() => Physics2D.Simulate(fixedStep);
}
```
> [!warning] Code not compiled in Unity
> Not compiled or play-tested. In Script mode, `FixedUpdate` still runs on its own schedule - controllers that apply movement in `FixedUpdate` (Part 5) won't line up with your manual steps; call their logic from this loop instead. This is the Game Loop pattern from [[Game Programming Patterns (Review)]] made explicit.
## 6.3 The Physics Core 2D API (Box2D v3) - when to look at it
Unity 6.3 added low-level 2D physics APIs built on **Box2D v3**: multithreaded, more deterministic, debug drawing in Editor and runtime, up to 64 collision layers, struct-based objects usable from jobs. In 6000.3 the namespace is `UnityEngine.LowLevelPhysics2D`; the 6000.5 Manual documents it as the **Physics Core 2D API** in `Unity.U2D.Physics`. It **does not interact** with Rigidbody2D/Collider2D - it's a separate world.
Use it when you need thousands of bodies (bullet-hell, sand, crowds), deterministic replays, multiple isolated worlds, or 2D physics on a 3D plane. Stay with components for normal gameplay - everything in Parts 1-5.
Minimal 6000.5 example, following the Manual's "Create an object" page:
```csharp
using UnityEngine;
using Unity.U2D.Physics; // 6000.5 namespace; in 6000.3 use UnityEngine.LowLevelPhysics2D
public class PhysicsCoreCircle : MonoBehaviour
{
// Definitions show up in the Inspector; set the body type to Dynamic there.
public PhysicsBodyDefinition bodyDefinition = PhysicsBodyDefinition.defaultDefinition;
public PhysicsShapeDefinition shapeDefinition = PhysicsShapeDefinition.defaultDefinition;
public float radius = 0.5f;
void Start()
{
PhysicsWorld world = PhysicsWorld.defaultWorld;
PhysicsBody body = world.CreateBody(bodyDefinition);
CircleGeometry circle = new CircleGeometry { radius = radius };
body.CreateShape(circle, shapeDefinition);
// Shapes are drawn by the API's debug renderer; no sprite or GameObject needed.
}
}
```
> [!warning] Code not compiled in Unity
> Not compiled. Mirrors the 6000.5 Manual snippet; object destruction/ownership rules are on the Manual's "Destroy" page - read it before creating objects every Start. Official samples: https://github.com/Unity-Technologies/PhysicsExamples2D
## Docs
- `Physics2D.simulationMode`: https://docs.unity3d.com/6000.5/Documentation/ScriptReference/Physics2D-simulationMode.html
- `SimulationMode2D`: https://docs.unity3d.com/6000.5/Documentation/ScriptReference/SimulationMode2D.html
- Physics 2D settings: https://docs.unity.com/en-us/engine/6000.5/manual/unity-editor/editor-settings-reference/comp-manager-group/class-physics2dsettings
- New in Unity 6.3 (low-level 2D physics): https://docs.unity.com/en-us/engine/6000.3/manual/whats-new/unity63
- Physics Core 2D API intro (6000.5): https://docs.unity.com/en-us/engine/6000.5/manual/unity2d/2d-physics-api/get-started/introduction
- Create an object (6000.5): https://docs.unity.com/en-us/engine/6000.5/manual/unity2d/2d-physics-api/create-objects/physics-object
- Create a world (6000.3, LowLevelPhysics2D): https://docs.unity.com/en-us/engine/6000.3/manual/unity2d/2d-physics-api/create-objects/world