67 lines
2.2 KiB
C#
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>();
|
|
// The player body does not collide with enemies; this trigger is the only attack contact.
|
|
_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;
|
|
|
|
// Catch enemies already inside the hitbox on the same frame it opens.
|
|
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;
|
|
|
|
// Hurtboxes may live on child objects, while damage handling usually lives on the root.
|
|
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);
|
|
}
|
|
}
|