133 lines
5.0 KiB
C#
133 lines
5.0 KiB
C#
using System.Collections.Generic;
|
||
using UnityEngine;
|
||
using Platformer.Mechanics;
|
||
using Platformer.Gameplay;
|
||
using static Platformer.Core.Simulation;
|
||
|
||
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;
|
||
|
||
// BT12-Dev 2026-05-10 (PD #1·#2) — 거리 제한·벽 충돌 영역
|
||
protected Vector2 _spawnPosition;
|
||
protected float _maxRange;
|
||
|
||
// 동일 투사체로 동일 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();
|
||
|
||
// BT12-Dev 2026-05-10 (PD #1) — 거리 제한 영역 영역 spawn 위치 저장
|
||
_spawnPosition = transform.position;
|
||
|
||
// 최대 거리 = Camera 영역 영역 영역 × 1.5 (PD #1 명시)
|
||
// Camera ortho size 3.5·aspect 16:9 → height 7·width ~12.44 → maxRange ~18.66 unit
|
||
var cam = Camera.main;
|
||
if (cam != null && cam.orthographic)
|
||
{
|
||
float camWidth = cam.orthographicSize * 2f * cam.aspect;
|
||
_maxRange = camWidth * 1.5f;
|
||
}
|
||
else
|
||
{
|
||
_maxRange = 20f; // fallback
|
||
}
|
||
|
||
// Phase 2-B: 풀링 미도입 — Invoke 기반 자동 소멸 (거리 제한 영역 영역 영역 영역 영역 안전망)
|
||
Invoke(nameof(SelfDestruct), _lifetime);
|
||
}
|
||
|
||
protected virtual void Update()
|
||
{
|
||
transform.position += (Vector3)(_direction * _speed * Time.deltaTime);
|
||
|
||
// BT12-Dev 2026-05-10 (PD #1) — 거리 제한 영역 영역 SelfDestruct
|
||
if (Vector2.Distance(transform.position, _spawnPosition) >= _maxRange)
|
||
{
|
||
SelfDestruct();
|
||
}
|
||
}
|
||
|
||
protected virtual void OnTriggerEnter2D(Collider2D other)
|
||
{
|
||
if (_hitTargets.Contains(other)) return;
|
||
|
||
// PD 지시 2026-05-09 후속 방어 — 자기(Player) hit·자기 자신·hit 방어.
|
||
if (other.GetComponent<PlayerController>() != null) return;
|
||
|
||
// Enemy 레이어 한정.
|
||
int enemyLayer = LayerMask.NameToLayer("Enemy");
|
||
bool isEnemy = (enemyLayer != -1 && other.gameObject.layer == enemyLayer)
|
||
|| other.GetComponent<EnemyController>() != null;
|
||
|
||
if (isEnemy)
|
||
{
|
||
var health = other.GetComponent<Health>();
|
||
if (health == null || !health.IsAlive) return;
|
||
|
||
_hitTargets.Add(other);
|
||
|
||
// 유효 대미지 산출 — BT12-Dev 2026-05-10 임시 (PD 지시): 기본 공격력 5 하한 강제.
|
||
int damage = Mathf.Max(_runtime.CalculateEffectiveDamage(), 5);
|
||
|
||
// 피해 적용
|
||
health.Decrement(damage);
|
||
|
||
// 부가 효과 (DoT·Stun·Slow·DebuffStack) — StatusApplier 위임
|
||
var enemy = other.GetComponent<EnemyController>();
|
||
if (enemy != null)
|
||
{
|
||
StatusApplier.Apply(_data, enemy);
|
||
}
|
||
|
||
// Enemy 즉사 시 EnemyDeath 체인 발동
|
||
if (!health.IsAlive && enemy != null)
|
||
{
|
||
Schedule<EnemyDeath>().enemy = enemy;
|
||
}
|
||
|
||
// 단일 적 타격 후 소멸 (관통 미지원 — Phase 2 범위 내)
|
||
SelfDestruct();
|
||
return;
|
||
}
|
||
|
||
// BT12-Dev 2026-05-10 (PD #2) — 벽 충돌 시 SelfDestruct.
|
||
// Layer 0 (Default·Ground) · Layer 16 (Foreground·발판) 영역 영역 Tilemap·Composite·Box collider 영역 정합.
|
||
// 레이저 영역 영역 영역 영역 영역 X — 본 Projectile 영역 영역 (영역 영역 영역 영역 X) — 모든 Projectile 영역 SelfDestruct.
|
||
int otherLayer = other.gameObject.layer;
|
||
bool isWall = (otherLayer == 0 || otherLayer == 16);
|
||
if (isWall)
|
||
{
|
||
SelfDestruct();
|
||
}
|
||
}
|
||
|
||
protected void SelfDestruct()
|
||
{
|
||
CancelInvoke(nameof(SelfDestruct));
|
||
Destroy(gameObject);
|
||
}
|
||
}
|
||
}
|