using System.Collections.Generic; using UnityEngine; using Platformer.Mechanics; using Platformer.Gameplay; using static Platformer.Core.Simulation; namespace EerieVillage.Skills.Effectors { /// /// A13 천둥발 변경 컨셉 (PD 지시 2026-05-13). /// FX_Lightningball 투사체 — 천천히 전진·관통·경로 닿는 적 매 0.2초마다 영역 데미지. /// /// 기존 Projectile 와 다름: /// - 적 명중 후 SelfDestruct X (관통) /// - 각 적별 마지막 tick 시각 추적·DotInterval (0.2s) 영역 영역 데미지 /// public class PiercingProjectile : Projectile { // 적별 마지막 hit 시각 readonly Dictionary _lastHitTime = new Dictionary(); public override void Initialize(ActiveSkillRuntime runtime, PlayerSkillInventory inventory, Vector2 direction) { base.Initialize(runtime, inventory, direction); _speed = 2.5f; // PD 지시 2026-05-13 — A13 천둥발 천천히 전진 (기본 6 → 2.5) _lifetime = 6f; // 관통이므로 lifetime 길게 _lastHitTime.Clear(); } // 관통이므로 OnTriggerEnter2D 영역 영역 X·OnTriggerStay2D 영역 영역 영역 영역 protected override void OnTriggerEnter2D(Collider2D other) { /* no-op */ } void OnTriggerStay2D(Collider2D other) { // PlayerController·Wall 영역 영역 X if (other.GetComponent() != null) return; int enemyLayer = LayerMask.NameToLayer("Enemy"); bool isEnemy = (enemyLayer != -1 && other.gameObject.layer == enemyLayer) || other.GetComponent() != null; if (!isEnemy) return; var enemy = other.GetComponent(); if (enemy == null) return; var health = other.GetComponent(); if (health == null || !health.IsAlive) return; float interval = (_data.DotInterval > 0.01f) ? _data.DotInterval : 0.2f; float now = Time.time; float last; if (_lastHitTime.TryGetValue(enemy, out last)) { if (now - last < interval) return; } _lastHitTime[enemy] = now; int damage = Mathf.Max(_runtime.CalculateEffectiveDamage(), _data.BaseDamage); // 관통 형 — DoT 처럼 invuln 미갱신 데미지 (다른 적도 동시 영역 영역) health.DecrementBypassInvuln(damage); if (!health.IsAlive) { Schedule().enemy = enemy; } } } }