using UnityEngine; using Platformer.Mechanics; using Platformer.Gameplay; using static Platformer.Core.Simulation; namespace EerieVillage.Skills.Effectors { /// /// A11 정령불 Effector — Category D (Minion). /// PD 지시 2026-05-13: /// - 15초마다 (BaseCooldown 15) Player 자식 spawn /// - 8초 유지 (FX_Rotating shield) /// - 지속 시간 동안 적 투사체 SelfDestruct·근접 적 매 초 5 피해 /// public class SpiritFireSpawner : IEffector { public void Trigger(ActiveSkillRuntime runtime, PlayerSkillInventory inventory) { var data = runtime.ActiveData; Vector2 spawnPos = (Vector2)inventory.transform.position + data.OffsetXY; GameObject shieldGo; if (data.OnHitFxPrefab != null) { shieldGo = Object.Instantiate(data.OnHitFxPrefab, spawnPos, Quaternion.identity, inventory.transform); shieldGo.transform.localScale *= data.HitFxScale; // PD 지시 2026-05-13 — ParticleSystem 명시 Play (playOnAwake 영역 정합·재발 안전망) foreach (var ps in shieldGo.GetComponentsInChildren(true)) { ps.Play(true); } } else { shieldGo = new GameObject("SpiritFire_Fallback"); shieldGo.transform.SetParent(inventory.transform, false); } shieldGo.hideFlags = HideFlags.DontSave; float duration = data.MinionLifetime > 0.1f ? data.MinionLifetime : 8f; float radius = data.AuraRadius > 0.1f ? data.AuraRadius : 2.5f; int damage = data.BaseDamage > 0 ? data.BaseDamage : 5; var instance = shieldGo.AddComponent(); instance.Init(inventory.transform, duration, radius, damage); } } /// /// 정령불 인스턴스 — Player 자식 부착·duration 동안 OverlapCircle 영역 적 투사체 SelfDestruct·근접 적 매 초 5 피해. /// public class SpiritFireInstance : MonoBehaviour { Transform _player; float _spawnTime; float _duration; float _radius; int _damage; float _lastDamageTime; public void Init(Transform player, float duration, float radius, int damage) { _player = player; _duration = duration; _radius = radius; _damage = damage; _spawnTime = Time.unscaledTime; } void Update() { if (Time.unscaledTime - _spawnTime >= _duration) { Destroy(gameObject); return; } Vector2 center = _player != null ? (Vector2)_player.position : (Vector2)transform.position; // 적 투사체 SelfDestruct (Projectile 컴포넌트 영역 적 발사·향후 Enemy 측 투사체 구현 시 정합) var allProjectiles = Object.FindObjectsByType(FindObjectsSortMode.None); foreach (var p in allProjectiles) { if (p == null) continue; float d = Vector2.Distance(center, p.transform.position); if (d <= _radius) { // PD 명시 — 적 투사체만 SelfDestruct. 현 Projectile = Player 발사 only → 영향 X 영역 (방어 코드). // 향후 Enemy 측 Projectile 분리 시 friendly check 추가 필요. } } // 매 1초 근접 적 피해 if (Time.unscaledTime - _lastDamageTime >= 1f) { _lastDamageTime = Time.unscaledTime; ApplyDamageAround(center); } } void ApplyDamageAround(Vector2 center) { var cf = new ContactFilter2D { useTriggers = false }; var results = new Collider2D[32]; int n = Physics2D.OverlapCircle(center, _radius, cf, results); for (int i = 0; i < n; i++) { var c = results[i]; if (c == null) continue; var e = c.GetComponent(); if (e == null) continue; var h = c.GetComponent(); if (h == null || !h.IsAlive) continue; h.DecrementBypassInvuln(_damage); if (!h.IsAlive) Schedule().enemy = e; } } } }