2026-05-12 16:48:30 +00:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using Platformer.Mechanics;
|
|
|
|
|
|
using Platformer.Gameplay;
|
|
|
|
|
|
using static Platformer.Core.Simulation;
|
|
|
|
|
|
|
|
|
|
|
|
namespace EerieVillage.Skills.Effectors
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// A13 천둥발 변경 컨셉 (PD 지시 2026-05-13).
|
|
|
|
|
|
/// FX_Lightningball 투사체 — 천천히 전진·관통·경로 닿는 적 매 0.2초마다 영역 데미지.
|
|
|
|
|
|
///
|
|
|
|
|
|
/// 기존 Projectile 와 다름:
|
|
|
|
|
|
/// - 적 명중 후 SelfDestruct X (관통)
|
|
|
|
|
|
/// - 각 적별 마지막 tick 시각 추적·DotInterval (0.2s) 영역 영역 데미지
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class PiercingProjectile : Projectile
|
|
|
|
|
|
{
|
|
|
|
|
|
// 적별 마지막 hit 시각
|
|
|
|
|
|
readonly Dictionary<EnemyController, float> _lastHitTime = new Dictionary<EnemyController, float>();
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
2026-05-13 09:05:13 +00:00
|
|
|
|
|
|
|
|
|
|
// PD 정합 2026-05-13 — OnTriggerStay2D 발화 영역 Kinematic Rigidbody2D + useFullKinematicContacts 영역
|
|
|
|
|
|
// Enemy 영역 Kinematic Rb → Kinematic vs Kinematic OnTriggerStay2D 영역 기본 발화 X.
|
|
|
|
|
|
// useFullKinematicContacts=true 영역 영역 발화 정합.
|
|
|
|
|
|
var rb = GetComponent<Rigidbody2D>();
|
|
|
|
|
|
if (rb == null) rb = gameObject.AddComponent<Rigidbody2D>();
|
|
|
|
|
|
rb.bodyType = RigidbodyType2D.Kinematic;
|
|
|
|
|
|
rb.simulated = true;
|
|
|
|
|
|
rb.gravityScale = 0f;
|
|
|
|
|
|
rb.useFullKinematicContacts = true;
|
2026-05-12 16:48:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-05-13 09:05:13 +00:00
|
|
|
|
// PD 정합 2026-05-13 — OnTrigger 영역 폐기 (Kinematic vs Kinematic 발화 영역 영역 X).
|
|
|
|
|
|
// Update 영역 OverlapBox 영역 매 frame 직접 검사·적별 0.2s 간격 영역 (다른 액티브 정합).
|
2026-05-12 16:48:30 +00:00
|
|
|
|
protected override void OnTriggerEnter2D(Collider2D other) { /* no-op */ }
|
|
|
|
|
|
|
2026-05-13 09:05:13 +00:00
|
|
|
|
protected override void Update()
|
2026-05-12 16:48:30 +00:00
|
|
|
|
{
|
2026-05-13 09:05:13 +00:00
|
|
|
|
base.Update(); // 이동·페이드·SyncHitboxToData
|
2026-05-12 16:48:30 +00:00
|
|
|
|
|
2026-05-13 09:05:13 +00:00
|
|
|
|
if (_data == null) return;
|
2026-05-12 16:48:30 +00:00
|
|
|
|
float interval = (_data.DotInterval > 0.01f) ? _data.DotInterval : 0.2f;
|
|
|
|
|
|
float now = Time.time;
|
|
|
|
|
|
|
2026-05-13 09:05:13 +00:00
|
|
|
|
var cf = new ContactFilter2D();
|
|
|
|
|
|
cf.useTriggers = false;
|
|
|
|
|
|
int enemyLayer = LayerMask.NameToLayer("Enemy");
|
|
|
|
|
|
if (enemyLayer >= 0) { cf.SetLayerMask(1 << enemyLayer); cf.useLayerMask = true; }
|
|
|
|
|
|
var results = new Collider2D[16];
|
|
|
|
|
|
// 박스 영역 transform.position + collider.size × localScale 영역 정합
|
|
|
|
|
|
var box = GetComponent<BoxCollider2D>();
|
|
|
|
|
|
Vector2 worldSize = box != null
|
|
|
|
|
|
? new Vector2(box.size.x * Mathf.Abs(transform.lossyScale.x), box.size.y * Mathf.Abs(transform.lossyScale.y))
|
|
|
|
|
|
: (Vector2)_data.HitboxSize;
|
|
|
|
|
|
int n = Physics2D.OverlapBox(transform.position, worldSize, transform.eulerAngles.z, cf, results);
|
|
|
|
|
|
int damage = Mathf.Max(_data.BaseDamage, 1);
|
|
|
|
|
|
for (int i = 0; i < n; i++)
|
2026-05-12 16:48:30 +00:00
|
|
|
|
{
|
2026-05-13 09:05:13 +00:00
|
|
|
|
var c = results[i];
|
|
|
|
|
|
if (c == null) continue;
|
|
|
|
|
|
var enemy = c.GetComponent<EnemyController>();
|
|
|
|
|
|
if (enemy == null) continue;
|
|
|
|
|
|
var health = c.GetComponent<Health>();
|
|
|
|
|
|
if (health == null || !health.IsAlive) continue;
|
|
|
|
|
|
|
|
|
|
|
|
float last;
|
|
|
|
|
|
if (_lastHitTime.TryGetValue(enemy, out last))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (now - last < interval) continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
_lastHitTime[enemy] = now;
|
|
|
|
|
|
|
|
|
|
|
|
health.DecrementBypassInvulnWithHit(damage);
|
|
|
|
|
|
if (!health.IsAlive)
|
|
|
|
|
|
{
|
|
|
|
|
|
Schedule<EnemyDeath>().enemy = enemy;
|
|
|
|
|
|
}
|
2026-05-12 16:48:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|