Quick answer: Track presence with Enter/Exit + your own timer. Or set rigidbody.sleepThreshold = 0. Or make the body Kinematic.

Healing zone over a sleeping body. Heal stops firing. PhysX put the body to sleep, OnTriggerStay no longer ticks for it.

The Fix

public class HealZone : MonoBehaviour {
    readonly HashSet<Health> _inside = new();

    void OnTriggerEnter(Collider c) {
        if (c.TryGetComponent(out Health h)) _inside.Add(h);
    }
    void OnTriggerExit(Collider c) {
        if (c.TryGetComponent(out Health h)) _inside.Remove(h);
    }

    void FixedUpdate() {
        foreach (var h in _inside)
            h.Heal(Time.fixedDeltaTime * 10f);
    }
}

Enter/Exit fire reliably regardless of sleep. Iterate the membership set on your own timer. Sleep stays enabled, optimization preserved.

Verifying

Body lies still in zone. Heal continues per FixedUpdate tick. With OnTriggerStay alone: heal stops once body sleeps.

“Track membership. Tick yourself. Sleep stays helpful.”

Related Issues

For BuoyancyEffector2D, see buoyancy. For CharacterController step, see step edges.

Membership set. FixedUpdate ticks. Heal flows.