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.