Quick answer: Stay events stop firing for sleeping bodies. Make the inside body wake periodically, set Rigidbody.sleepThreshold = 0, or drive the “is inside” logic from Enter/Exit + a flag.

A damage zone deals per-tick damage from OnTriggerStay. The player walks in, takes one tick, then no more — the rigidbody went to sleep and stay events stopped.

Sleeping Bodies Skip Stay

PhysX (Unity’s 3D physics) puts idle rigidbodies to sleep to save CPU. Sleeping bodies don’t generate contact/trigger stay events — only Enter/Exit when they wake.

Fix 1: Track Enter/Exit Yourself

readonly HashSet<Collider> _inside = new();

void OnTriggerEnter(Collider c) => _inside.Add(c);
void OnTriggerExit(Collider c)  => _inside.Remove(c);

void FixedUpdate()
{
    foreach (var c in _inside) ApplyDamageTick(c);
}

Reliable regardless of sleep state. Use this for damage zones, healing pads, anything that needs continuous “inside” logic.

Fix 2: Prevent Sleep

Set rb.sleepThreshold = 0 on bodies you need stay events from. Costs a little CPU per body; only do it for the few that matter.

2D Has the Same Behavior

Physics2D triggers behave the same. Same fixes apply to OnTriggerStay2D.

Verifying

Stand in the damage zone — ticks continue indefinitely. Walk in and out — Enter/Exit track correctly. No tick after exit.

“Sleeping bodies skip Stay. Track Enter/Exit and apply per-FixedUpdate yourself.”

The Enter/Exit + set approach is also dramatically cheaper than Stay for crowded triggers — you iterate your own small set instead of every physics contact.