주석추가
This commit is contained in:
@@ -1,22 +1,40 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
// ============================================================================
|
||||
// AttackHitbox
|
||||
// ----------------------------------------------------------------------------
|
||||
// 플레이어(또는 임의 캐릭터)의 공격 판정 콜라이더.
|
||||
// Player의 자식 GameObject로 두고, 액션마다 Activate/Deactivate로 hit window 표현.
|
||||
//
|
||||
// 핵심:
|
||||
// - CircleCollider2D Trigger (물리 충돌 아닌 트리거 감지만)
|
||||
// - 평소엔 disabled, 액션의 HitTiming~HitDuration 동안만 enabled
|
||||
// - 활성 순간 이미 범위 안에 있던 적도 ScanImmediateOverlap으로 즉시 검사
|
||||
// (OnTriggerEnter는 다음 frame에야 발화되므로 짧은 hit window엔 부족함)
|
||||
// - _alreadyHit HashSet으로 같은 적에 중복 데미지 방지
|
||||
// ============================================================================
|
||||
[RequireComponent(typeof(CircleCollider2D))]
|
||||
public class AttackHitbox : MonoBehaviour
|
||||
{
|
||||
// PlayerController가 구독해서 "방금 hit한 적" 추적용 (잡기 타겟 우선 등에 활용).
|
||||
public event System.Action<IDamageable> OnHit;
|
||||
|
||||
private CircleCollider2D _collider;
|
||||
|
||||
// ─── 현재 활성 액션의 데미지/효과 데이터 (Activate에서 세팅) ─────────
|
||||
private int _damage;
|
||||
private Vector2 _hitVelocity;
|
||||
private Vector2 _hitSourcePosition;
|
||||
private Vector2? _hitTargetPosition;
|
||||
private float _hitPositionMinDistance;
|
||||
private bool _correctHitTargetY;
|
||||
private int _hitPositionSolidMask;
|
||||
private float _hitPositionCorrectionDuration;
|
||||
private string _hitReactionState;
|
||||
private LayerMask _targetLayer;
|
||||
private Vector2 _hitVelocity; // 피해자에게 가할 넉백 속도
|
||||
private Vector2 _hitSourcePosition; // 공격자 위치 (피격자 위치 보정 거리 계산용)
|
||||
private Vector2? _hitTargetPosition; // 피격자 강제 이동 목표 위치 (null이면 보정 안 함)
|
||||
private float _hitPositionMinDistance; // 이 거리보다 가까우면 위치 보정 적용
|
||||
private bool _correctHitTargetY; // 위치 보정에서 Y도 보정할지
|
||||
private int _hitPositionSolidMask; // 보정 시 끼이지 않게 검사할 솔리드 레이어
|
||||
private float _hitPositionCorrectionDuration; // 보정 보간 시간 (0이면 즉시)
|
||||
private string _hitReactionState; // 피격자가 재생할 애니메이션 State 이름
|
||||
private LayerMask _targetLayer; // 데미지를 줄 레이어 (보통 Enemy)
|
||||
|
||||
// 한 번 hit한 IDamageable은 이 액션 활성 동안 다시 hit되지 않음.
|
||||
private readonly HashSet<IDamageable> _alreadyHit = new();
|
||||
|
||||
private void Awake()
|
||||
@@ -27,6 +45,8 @@ private void Awake()
|
||||
_collider.enabled = false;
|
||||
}
|
||||
|
||||
// 액션 시작 시 호출. 위치/반경/데미지 등 모든 파라미터 세팅 후 콜라이더 활성화.
|
||||
// _alreadyHit를 클리어해서 새 공격으로 다시 hit 가능하게 함.
|
||||
public void Activate(ActionData data, Vector2 localPosition, Vector2 hitVelocity, Vector2 sourcePosition, Vector2? hitTargetPosition, bool correctHitTargetY, int hitPositionSolidMask, LayerMask targetLayer)
|
||||
{
|
||||
transform.localPosition = localPosition;
|
||||
@@ -48,12 +68,15 @@ public void Activate(ActionData data, Vector2 localPosition, Vector2 hitVelocity
|
||||
ScanImmediateOverlap();
|
||||
}
|
||||
|
||||
// 액션의 HitDuration이 끝나면 호출. 콜라이더 비활성화 + hit 기록 초기화.
|
||||
public void Deactivate()
|
||||
{
|
||||
_collider.enabled = false;
|
||||
_alreadyHit.Clear();
|
||||
}
|
||||
|
||||
// 활성 순간 즉시 검사: Physics2D.OverlapCircleAll로 현재 겹친 콜라이더를 모두 가져와 TryDamage.
|
||||
// 이게 없으면 짧은 hit window (예: HitDuration=0.02)에 OnTriggerEnter가 못 따라옴.
|
||||
private void ScanImmediateOverlap()
|
||||
{
|
||||
Collider2D[] hits = Physics2D.OverlapCircleAll(transform.position, _collider.radius, _targetLayer);
|
||||
@@ -61,9 +84,17 @@ private void ScanImmediateOverlap()
|
||||
TryDamage(hit);
|
||||
}
|
||||
|
||||
// 트리거 이벤트로 들어온 적도 같은 함수로 처리.
|
||||
// Stay까지 받는 이유: 활성 중간에 새로 들어온 적도 잡으려고.
|
||||
private void OnTriggerEnter2D(Collider2D other) => TryDamage(other);
|
||||
private void OnTriggerStay2D(Collider2D other) => TryDamage(other);
|
||||
|
||||
// 데미지 적용 흐름:
|
||||
// 1) 레이어 마스크로 적 여부 확인
|
||||
// 2) Collider 자신 또는 부모에서 IDamageable 검색 (자식 콜라이더 대응)
|
||||
// 3) 이미 hit한 대상은 건너뜀 (HashSet)
|
||||
// 4) 데미지 + 넉백 + 위치 보정 정보를 전달하여 TakeDamage 호출
|
||||
// 5) OnHit 이벤트 발화 (PlayerController가 마지막 hit한 적 기억)
|
||||
private void TryDamage(Collider2D other)
|
||||
{
|
||||
if ((_targetLayer.value & (1 << other.gameObject.layer)) == 0) return;
|
||||
@@ -81,6 +112,10 @@ private void TryDamage(Collider2D other)
|
||||
OnHit?.Invoke(target);
|
||||
}
|
||||
|
||||
// 위치 보정 목표 결정.
|
||||
// 적이 공격자에게 너무 가까우면 (X 거리 < minDistance) hitTargetPosition을 반환,
|
||||
// 충분히 떨어져 있으면 null 반환해서 보정 안 함.
|
||||
// (가까운 적만 끌어당기는 "흡착" 효과 구현)
|
||||
private Vector2? GetCorrectionTargetPosition(Collider2D other)
|
||||
{
|
||||
if (!_hitTargetPosition.HasValue) return null;
|
||||
|
||||
Reference in New Issue
Block a user