using System; using System.Collections.Generic; using UnityEngine; namespace Code.OfficeGame.BattleMode.HitBoxes { public class EntityHitBoxes : MonoBehaviour { [Serializable] public struct HitBoxPartCollider { public HitBoxPartType PartType; public BoxCollider Collider; } [SerializeField] private HitBoxPartCollider[] bodyParts; private LayerMask _hitBoxLayerMask; private readonly Dictionary _colliderMap = new(); private readonly Collider[] _hitResults = new Collider[8]; // Список уже поражённых целей за один взмах, чтобы один удар не наносил урон 8 раз за 8 активных кадров private readonly HashSet _alreadyHitTargets = new(); private HitBoxPartType? _activePart; private void Awake() { foreach (var part in bodyParts) { part.Collider.enabled = false; _colliderMap[part.PartType] = part.Collider; } _hitBoxLayerMask = LayerMask.GetMask("HitBox"); } public void EnableHitbox(HitBoxPartType part) { if (_activePart == part) return; _alreadyHitTargets.Clear(); _activePart = part; if (_colliderMap.TryGetValue(part, out var col)) { col.enabled = true; } } public void DisableAllHitboxes() { if (_activePart.HasValue && _colliderMap.TryGetValue(_activePart.Value, out var col)) { col.enabled = false; } _activePart = null; _alreadyHitTargets.Clear(); } public void CheckHitsForCurrentFrame(Action onNewTargetHit) { if (!_activePart.HasValue) return; BoxCollider box = _colliderMap[_activePart.Value]; Transform boxTransform = box.transform; // Вычисляем точный мировой центр и размер коллайдера на кости в текущем кадре анимации Vector3 worldCenter = boxTransform.TransformPoint(box.center); Vector3 worldHalfExtents = Vector3.Scale(box.size * 0.5f, boxTransform.lossyScale); int hitsCount = Physics.OverlapBoxNonAlloc( worldCenter, worldHalfExtents, _hitResults, boxTransform.rotation, _hitBoxLayerMask, QueryTriggerInteraction.Collide); for (int i = 0; i < hitsCount; i++) { Collider hitCol = _hitResults[i]; // Игнорируем самого себя if (hitCol.transform.root == transform.root) continue; // Если за этот взмах мы ещё не били этого врага — засчитываем попадание! if (_alreadyHitTargets.Add(hitCol.gameObject)) { onNewTargetHit?.Invoke(hitCol); } } } } public enum HitBoxPartType { Head, Chest, Arm, Leg } }