using System.Collections.Generic; using UnityEngine; public class ClamBiteDetector : MonoBehaviour { [Header("References")] [SerializeField] private ClamOpenClose clam; [SerializeField] private RaftHealth health; [SerializeField] private MemoryFragmentReset memoryFragment; [Header("Bite Damage")] [SerializeField] private int biteDamage = 20; [Header("Bite Zone")] [SerializeField] private Collider biteZoneCollider; [Tooltip("조개가 닫히는 동안 이미 한 번 물렸으면 추가 판정을 막습니다.")] [SerializeField] private bool biteOncePerClose = true; [Header("Target Tags")] [SerializeField] private string handTag = "PlayerHand"; [SerializeField] private string fragmentTag = "MemoryFragment"; [Header("Debug")] [SerializeField] private bool showDebugLog = true; private bool hasBittenThisClose; private readonly HashSet collidersInside = new(); private void Awake() { if (biteZoneCollider == null) biteZoneCollider = GetComponent(); if (biteZoneCollider != null) { biteZoneCollider.isTrigger = true; biteZoneCollider.enabled = false; } if (clam == null) clam = GetComponentInParent(); if (health == null) health = FindFirstObjectByType(); if (memoryFragment == null) memoryFragment = FindFirstObjectByType(); } private void OnEnable() { if (clam != null) { clam.onCloseStarted.AddListener(EnableBiteWindow); clam.onClosed.AddListener(DisableBiteWindow); clam.onOpened.AddListener(ResetBiteState); } } private void OnDisable() { if (clam != null) { clam.onCloseStarted.RemoveListener(EnableBiteWindow); clam.onClosed.RemoveListener(DisableBiteWindow); clam.onOpened.RemoveListener(ResetBiteState); } } private void OnTriggerEnter(Collider other) { collidersInside.Add(other); if (IsBiteWindowOpen()) TryBite(other); } private void OnTriggerStay(Collider other) { collidersInside.Add(other); if (IsBiteWindowOpen()) TryBite(other); } private void OnTriggerExit(Collider other) { collidersInside.Remove(other); } private void EnableBiteWindow() { hasBittenThisClose = false; if (biteZoneCollider != null) biteZoneCollider.enabled = true; if (showDebugLog) Debug.Log("[ClamBiteDetector] 조개 물림 판정 ON", this); foreach (Collider col in collidersInside) { if (col != null) TryBite(col); } } private void DisableBiteWindow() { if (biteZoneCollider != null) biteZoneCollider.enabled = false; collidersInside.Clear(); if (showDebugLog) Debug.Log("[ClamBiteDetector] 조개 물림 판정 OFF", this); } private void ResetBiteState() { hasBittenThisClose = false; } private bool IsBiteWindowOpen() { if (biteZoneCollider == null) return false; return biteZoneCollider.enabled; } private void TryBite(Collider other) { if (other == null) return; if (biteOncePerClose && hasBittenThisClose) return; bool isHand = other.CompareTag(handTag) || other.GetComponentInParent() != null; bool isFragment = other.CompareTag(fragmentTag) || other.GetComponentInParent() != null; if (!isHand && !isFragment) return; hasBittenThisClose = true; if (health != null) health.TakeDamage(biteDamage); if (memoryFragment != null) memoryFragment.ResetFragment(); if (showDebugLog) { Debug.Log($"[ClamBiteDetector] 조개에게 물림. 데미지 {biteDamage}, 기억의 조각 리셋", this); } } }