// Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs using UnityEngine; using TD.Core; namespace TD.Gameplay.BuilderSpells { /// /// Server-only, non-networked lingering area spawned by /// . Re-scans its radius on an /// interval for its lifetime and keeps refreshing the slow on anything standing /// inside, so enemies get slowed as they walk through rather than only at the /// instant of cast. /// /// /// Never spawned as a — it runs /// server-side only, and the slow it applies already reaches clients through /// 's own NetworkVariable, the same as an instant hit. /// public class SlowAreaZone : MonoBehaviour { private const float TickInterval = 0.2f; private float radius; private float slowFactor; private float effectDuration; private LayerMask enemyLayerMask; private PlayerSlot owner; private readonly Collider[] overlapBuffer = new Collider[64]; private float tickTimer; public static SlowAreaZone Spawn(Vector3 position, float radius, float slowFactor, float effectDuration, LayerMask enemyLayerMask, PlayerSlot owner) { var zoneObject = new GameObject("SlowAreaZone (Server)"); zoneObject.transform.position = position; var zone = zoneObject.AddComponent(); zone.radius = radius; zone.slowFactor = slowFactor; zone.effectDuration = effectDuration; zone.enemyLayerMask = enemyLayerMask; zone.owner = owner; zone.ApplyToOverlapping(); Destroy(zoneObject, effectDuration); return zone; } private void Update() { tickTimer -= Time.deltaTime; if (tickTimer > 0f) return; ApplyToOverlapping(); } private void ApplyToOverlapping() { tickTimer = TickInterval; int count = Physics.OverlapSphereNonAlloc( transform.position, radius, overlapBuffer, enemyLayerMask); for (int i = 0; i < count; i++) { var enemyHealth = overlapBuffer[i].GetComponent(); if (enemyHealth == null || enemyHealth.IsDead) continue; var enemyStatus = overlapBuffer[i].GetComponent(); if (enemyStatus == null) continue; enemyStatus.ApplyEffect(DamageType.Cold, slowFactor, effectDuration, owner); } } } }