85 lines
3.1 KiB
C#
85 lines
3.1 KiB
C#
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using Platformer.Mechanics;
|
|
|
|
namespace EerieVillage.Skills.Effectors
|
|
{
|
|
/// <summary>
|
|
/// 투사체 기본 컴포넌트. Line 궤적 직선 이동·단일 적 타격 후 소멸.
|
|
/// BT12-Dev Phase 2-B §4-2.
|
|
/// 파생: <see cref="HomingProjectile"/> (A15 추적 화염구).
|
|
/// </summary>
|
|
public class Projectile : MonoBehaviour
|
|
{
|
|
protected ActiveSkillData _data;
|
|
protected ActiveSkillRuntime _runtime;
|
|
protected PlayerSkillInventory _inventory;
|
|
protected Vector2 _direction;
|
|
protected float _speed = 12f;
|
|
protected float _lifetime = 3f;
|
|
|
|
// 동일 투사체로 동일 Collider 중복 타격 방지
|
|
protected readonly HashSet<Collider2D> _hitTargets = new HashSet<Collider2D>();
|
|
|
|
/// <summary>
|
|
/// ProjectileSpawner.Trigger 에서 Instantiate 직후 호출.
|
|
/// </summary>
|
|
public virtual void Initialize(ActiveSkillRuntime runtime, PlayerSkillInventory inventory, Vector2 direction)
|
|
{
|
|
_runtime = runtime;
|
|
_data = runtime.ActiveData;
|
|
_inventory = inventory;
|
|
_direction = direction.normalized;
|
|
_hitTargets.Clear();
|
|
|
|
// Phase 2-B: 풀링 미도입 — Invoke 기반 자동 소멸
|
|
Invoke(nameof(SelfDestruct), _lifetime);
|
|
}
|
|
|
|
protected virtual void Update()
|
|
{
|
|
transform.position += (Vector3)(_direction * _speed * Time.deltaTime);
|
|
}
|
|
|
|
protected virtual void OnTriggerEnter2D(Collider2D other)
|
|
{
|
|
if (_hitTargets.Contains(other)) return;
|
|
|
|
// Enemy 레이어 한정.
|
|
// Phase 2-D fallback (2026-05-09): TagManager에 "Enemy" 레이어 미등재 시 LayerMask.NameToLayer 반환값 = -1.
|
|
// 레이어 매칭 실패 시 EnemyController 컴포넌트 존재 여부로 대체 판정.
|
|
int enemyLayer = LayerMask.NameToLayer("Enemy");
|
|
bool isEnemy = (enemyLayer != -1 && other.gameObject.layer == enemyLayer)
|
|
|| other.GetComponent<EnemyController>() != null;
|
|
if (!isEnemy) return;
|
|
|
|
var health = other.GetComponent<Health>();
|
|
if (health == null || !health.IsAlive) return;
|
|
|
|
_hitTargets.Add(other);
|
|
|
|
// 유효 대미지 산출 (balance/01 v0.2 §3 공식 — ActiveSkillRuntime.CalculateEffectiveDamage())
|
|
int damage = _runtime.CalculateEffectiveDamage();
|
|
|
|
// 피해 적용
|
|
health.Decrement(damage);
|
|
|
|
// 부가 효과 (DoT·Stun·Slow·DebuffStack) — StatusApplier 위임
|
|
var enemy = other.GetComponent<EnemyController>();
|
|
if (enemy != null)
|
|
{
|
|
StatusApplier.Apply(_data, enemy);
|
|
}
|
|
|
|
// 단일 적 타격 후 소멸 (관통 미지원 — Phase 2 범위 내)
|
|
SelfDestruct();
|
|
}
|
|
|
|
protected void SelfDestruct()
|
|
{
|
|
CancelInvoke(nameof(SelfDestruct));
|
|
Destroy(gameObject);
|
|
}
|
|
}
|
|
}
|