fix slow area spell area of effect
This commit is contained in:
parent
04d7b42e60
commit
35ea90f71b
3 changed files with 92 additions and 18 deletions
|
|
@ -14,6 +14,12 @@ namespace TD.Gameplay.BuilderSpells
|
||||||
/// while aiming, and this spell resolves against that same radius (no separate field).
|
/// while aiming, and this spell resolves against that same radius (no separate field).
|
||||||
/// Reuses the existing slow/DoT system (<see cref="EnemyStatus.ApplyEffect"/>) rather than
|
/// Reuses the existing slow/DoT system (<see cref="EnemyStatus.ApplyEffect"/>) rather than
|
||||||
/// introducing a new status mechanism.
|
/// introducing a new status mechanism.
|
||||||
|
/// <para>
|
||||||
|
/// The cast spawns a <see cref="SlowAreaZone"/> that lingers for
|
||||||
|
/// <see cref="EffectDuration"/> and keeps re-applying the slow to anything standing in
|
||||||
|
/// the radius, so enemies walking through the area get slowed rather than only whatever
|
||||||
|
/// happened to be standing there at the exact instant of cast.
|
||||||
|
/// </para>
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[CreateAssetMenu(fileName = "SlowAreaSpell", menuName = "TD/Builder Spells/Slow Area")]
|
[CreateAssetMenu(fileName = "SlowAreaSpell", menuName = "TD/Builder Spells/Slow Area")]
|
||||||
public class SlowAreaSpellDefinition : BuilderSpellDefinition
|
public class SlowAreaSpellDefinition : BuilderSpellDefinition
|
||||||
|
|
@ -35,7 +41,9 @@ namespace TD.Gameplay.BuilderSpells
|
||||||
[Range(0f, 1f)]
|
[Range(0f, 1f)]
|
||||||
public float SlowFactor = 0.5f;
|
public float SlowFactor = 0.5f;
|
||||||
|
|
||||||
[Tooltip("Seconds the slow lasts. Re-casting on an already-slowed enemy refreshes it.")]
|
[Tooltip("Seconds the slow lasts on an affected enemy, and how long the area itself " +
|
||||||
|
"lingers, re-slowing anything that walks through it. Re-casting on an " +
|
||||||
|
"already-slowed enemy refreshes it.")]
|
||||||
[Min(0f)]
|
[Min(0f)]
|
||||||
public float EffectDuration = 3f;
|
public float EffectDuration = 3f;
|
||||||
|
|
||||||
|
|
@ -43,23 +51,10 @@ namespace TD.Gameplay.BuilderSpells
|
||||||
{
|
{
|
||||||
PlayerSlot owner = PlayerMatchState.SlotForClient(clientId);
|
PlayerSlot owner = PlayerMatchState.SlotForClient(clientId);
|
||||||
|
|
||||||
int count = Physics.OverlapSphereNonAlloc(
|
SlowAreaZone.Spawn(targetPoint, Mathf.Max(Radius, 0.01f), SlowFactor,
|
||||||
targetPoint, Mathf.Max(Radius, 0.01f), s_overlapBuffer, enemyLayerMask);
|
EffectDuration, enemyLayerMask, owner);
|
||||||
|
|
||||||
bool hitAny = false;
|
return true;
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
var enemyHealth = s_overlapBuffer[i].GetComponent<EnemyHealth>();
|
|
||||||
if (enemyHealth == null || enemyHealth.IsDead) continue;
|
|
||||||
|
|
||||||
var enemyStatus = s_overlapBuffer[i].GetComponent<EnemyStatus>();
|
|
||||||
if (enemyStatus == null) continue;
|
|
||||||
|
|
||||||
enemyStatus.ApplyEffect(DamageType.Cold, SlowFactor, EffectDuration, owner);
|
|
||||||
hitAny = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return hitAny;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void ClientSpawnVfx(Vector3 targetPoint)
|
public override void ClientSpawnVfx(Vector3 targetPoint)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Assets/_Project/Scripts/Gameplay/BuilderSpells/SlowAreaZone.cs
|
||||||
|
using UnityEngine;
|
||||||
|
using TD.Core;
|
||||||
|
|
||||||
|
namespace TD.Gameplay.BuilderSpells
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Server-only, non-networked lingering area spawned by
|
||||||
|
/// <see cref="SlowAreaSpellDefinition.ServerCast"/>. 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.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Never spawned as a <see cref="Unity.Netcode.NetworkObject"/> — it runs
|
||||||
|
/// server-side only, and the slow it applies already reaches clients through
|
||||||
|
/// <see cref="EnemyStatus"/>'s own NetworkVariable, the same as an instant hit.
|
||||||
|
/// </remarks>
|
||||||
|
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<SlowAreaZone>();
|
||||||
|
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<EnemyHealth>();
|
||||||
|
if (enemyHealth == null || enemyHealth.IsDead) continue;
|
||||||
|
|
||||||
|
var enemyStatus = overlapBuffer[i].GetComponent<EnemyStatus>();
|
||||||
|
if (enemyStatus == null) continue;
|
||||||
|
|
||||||
|
enemyStatus.ApplyEffect(DamageType.Cold, slowFactor, effectDuration, owner);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7b00a1f57e8be13cd91c0ed5f515bfc8
|
||||||
Loading…
Add table
Add a link
Reference in a new issue