Quick answer: Call Physics2D.SyncTransforms() right before a query if you teleported anything via transform.position in the same frame. Use the NonAlloc overload to avoid GC. Or enable Auto Sync Transforms in Physics 2D settings.

Spawn an enemy at (5, 0). Immediately call OverlapCircleAll at (5, 0). Returns nothing. The physics broadphase hasn’t seen the new transform yet.

The Symptom

Physics queries miss freshly moved or spawned colliders. The same query in the next frame finds them. Or queries hit positions where the collider was last frame, not where it is now.

The Fix

Sync before query.

enemy.transform.position = newPos;
Physics2D.SyncTransforms();   // flush transform changes to broadphase

var hits = new Collider2D[8];
int count = Physics2D.OverlapCircleNonAlloc(newPos, 2f, hits);
for (int i = 0; i < count; i++)
    Process(hits[i]);

SyncTransforms is cheap; call it once per frame after a batch of teleports.

Auto Sync

Project Settings → Physics 2D → Auto Sync Transforms = true. The system syncs before every query automatically. Convenient; slightly slower for projects that move many transforms per frame.

NonAlloc Overloads

Avoid the array-allocating versions in update loops:

// Bad — allocates Collider2D[] every call
var hits = Physics2D.OverlapCircleAll(pt, r);

// Good — reuses caller's buffer
int n = Physics2D.OverlapCircleNonAlloc(pt, r, _hitsBuffer);

Allocate _hitsBuffer once with a reasonable max size (16 or 32). Truncate using the count return.

Verifying

Move a collider and immediately query. Without SyncTransforms: empty result. With: the collider is found. Profiler → check GC alloc dropped after switching to NonAlloc.

“Sync after teleport. NonAlloc for hot paths. Queries return current state.”

Related Issues

For OnTriggerExit not firing on disable, see trigger exit. For Rigidbody2D interpolate, see interpolate.

SyncTransforms. NonAlloc. Queries fresh.