using UnityEngine; using UnityEngine.Events; /// /// VR 손이 콜라이더에 닿을(OnTriggerEnter) 때마다 작동하는 버튼. /// XR UI 포인터/포크 상호작용이 불안정할 때, 트리거 콜라이더로 직접 눌리도록 한다. /// [RequireComponent(typeof(Collider))] public class CollisionButton : MonoBehaviour { [Header("Hand Detection")] [Tooltip("이 태그를 가진 콜라이더를 손으로 인식합니다.")] [SerializeField] private string handTag = "PlayerHand"; [Tooltip("태그가 달라도 XRHandMarker가 붙어 있으면 손으로 인식합니다.")] [SerializeField] private bool detectByHandMarker = true; [Header("Press Behavior")] [Tooltip("한 번 눌린 뒤 다시 눌리기까지의 최소 간격(초). 중복/연타 입력을 막습니다.")] [SerializeField] private float cooldown = 0.4f; [Tooltip("꺼두면 손이 닿아도 반응하지 않습니다.")] [SerializeField] private bool interactable = true; [Header("Events")] [Tooltip("손이 닿아 눌릴 때마다 발생합니다.")] public UnityEvent onPressed; [Header("Debug")] [SerializeField] private bool showDebugLog = false; // timeScale=0(일시정지)에서도 동작하도록 unscaled 시간 사용 private float _lastPressTime = -999f; // 에디터에서 컴포넌트를 처음 추가할 때 콜라이더를 트리거로 자동 설정 private void Reset() { Collider col = GetComponent(); if (col != null) col.isTrigger = true; } private void Awake() { Collider col = GetComponent(); if (col != null && !col.isTrigger) { col.isTrigger = true; if (showDebugLog) Debug.Log("[CollisionButton] Collider가 트리거가 아니어서 강제로 트리거로 설정했습니다.", this); } } private void OnTriggerEnter(Collider other) { if (!interactable) return; if (!IsHand(other)) return; // 양손 콜라이더가 거의 동시에 들어오거나 빠르게 재진입할 때 중복 발동 방지 if (Time.unscaledTime - _lastPressTime < cooldown) return; Press(); } private void Press() { _lastPressTime = Time.unscaledTime; if (showDebugLog) Debug.Log("[CollisionButton] 손이 닿아 버튼이 눌렸습니다.", this); onPressed?.Invoke(); } private bool IsHand(Collider other) { if (other == null) return false; if (!string.IsNullOrEmpty(handTag) && other.CompareTag(handTag)) return true; if (detectByHandMarker && other.GetComponentInParent() != null) return true; return false; } // 런타임에 활성/비활성 토글이 필요할 때 (UnityEvent 등에서 호출) public void SetInteractable(bool value) => interactable = value; }