Files
WhiteMan_Unity2D/Assets/02_Scripts/Combat/AttackHitbox.cs

67 lines
2.2 KiB
C#

using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(CircleCollider2D))]
public class AttackHitbox : MonoBehaviour
{
private CircleCollider2D _collider;
private int _damage;
private Vector2 _hitVelocity;
private string _hitReactionState;
private LayerMask _targetLayer;
private readonly HashSet<IDamageable> _alreadyHit = new();
private void Awake()
{
_collider = GetComponent<CircleCollider2D>();
// 플레이어 몸체는 적과 물리 충돌하지 않으므로, 공격 판정은 이 트리거만 사용한다.
_collider.isTrigger = true;
_collider.enabled = false;
}
public void Activate(ActionData data, Vector2 localPosition, Vector2 hitVelocity, LayerMask targetLayer)
{
transform.localPosition = localPosition;
_collider.radius = data.Radius;
_damage = data.Damage;
_hitVelocity = hitVelocity;
_hitReactionState = data.HitReactionAnimationState;
_targetLayer = targetLayer;
_alreadyHit.Clear();
_collider.enabled = true;
// 판정이 켜진 순간 이미 범위 안에 있던 적도 같은 프레임에 잡아낸다.
ScanImmediateOverlap();
}
public void Deactivate()
{
_collider.enabled = false;
_alreadyHit.Clear();
}
private void ScanImmediateOverlap()
{
Collider2D[] hits = Physics2D.OverlapCircleAll(transform.position, _collider.radius, _targetLayer);
foreach (var hit in hits)
TryDamage(hit);
}
private void OnTriggerEnter2D(Collider2D other) => TryDamage(other);
private void OnTriggerStay2D(Collider2D other) => TryDamage(other);
private void TryDamage(Collider2D other)
{
if ((_targetLayer.value & (1 << other.gameObject.layer)) == 0) return;
// 피격 콜라이더는 자식에 있고, 데미지 처리는 루트에 있을 수 있다.
if (!other.TryGetComponent<IDamageable>(out var target))
target = other.GetComponentInParent<IDamageable>();
if (target == null) return;
if (_alreadyHit.Contains(target)) return;
_alreadyHit.Add(target);
target.TakeDamage(_damage, _hitVelocity, _hitReactionState);
}
}