using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; public class TwoHandGrabInteractable : XRGrabInteractable { public List secondHandGrabPoints = new List(); //두번째 손 잡이용 XRSimpleInteractable들 private XRBaseInteractor secondInteractor; //두 번째 손의 Interactor private Quaternion attachInitialRotation; //첫 번째 손의 원래 회전값 public enum TwoHandRotationType { None, First, Second } //어느 손의 기준으로 총을 회전할 것인가? public TwoHandRotationType twoHandRotationType; private Quaternion initialRotationOffset; //두번째 손으로 잡을 때, 회전각의 차이값을 저장 void Start() { //두 번째 손을 잡았을 때 / 손았을 때 실행할 리스너 함수 등록 foreach (var item in secondHandGrabPoints) { item.onSelectEntered.AddListener(OnSecondHandGrab); item.onSelectExited.AddListener(OnSecondHandRelease); } } //사물을 잡고 있는 동안 계쏙 실행 public override void ProcessInteractable(XRInteractionUpdateOrder.UpdatePhase updatePhase) { //양 손으로 잡고 있을 때만 회전값을 계산하도록 if(selectingInteractor && secondInteractor) { //회전값을 계산 //오브젝트의 Pivot중심점이 아닌, 첫 번째 손을 잡은 AttachTransform을 기준으로 회전하기 위해 잡은 손의 attachTransform의 회전각을 변경해줌 selectingInteractor.attachTransform.rotation = GetTwoHandRotation() * initialRotationOffset; } base.ProcessInteractable(updatePhase); } private Quaternion GetTwoHandRotation() { Quaternion targetRotation; switch (twoHandRotationType) { default: case TwoHandRotationType.None: //회전하지 않음 targetRotation = Quaternion.LookRotation(secondInteractor.transform.position - selectingInteractor.transform.position); break; case TwoHandRotationType.First: targetRotation = Quaternion.LookRotation(secondInteractor.transform.position - selectingInteractor.transform.position, selectingInteractor.attachTransform.up); break; case TwoHandRotationType.Second: targetRotation = Quaternion.LookRotation(secondInteractor.transform.position - selectingInteractor.transform.position, secondInteractor.attachTransform.up); break; } return targetRotation; } public override bool IsSelectableBy(XRBaseInteractor interactor) { //이미 다른 Interactor가 잡고 있는가? //현재 잡고 있는 Interactor가 있고, 그게 지금 새로 잡으려는 interactor가 아닌 경우에만 true bool isAlreadyGrabbed = selectingInteractor && !interactor.Equals(selectingInteractor); //'다른 Interactor'가 잡고 있지 않을 때'라는 조건 추가 return base.IsSelectableBy(interactor) && !isAlreadyGrabbed; } public void OnSecondHandGrab(XRBaseInteractor interactor) { print("Second Hand Grab"); secondInteractor = interactor; //두번째 Interactor 설정 //Quaternion의 회전값의 차이를 구하기 위해, 한 Quaternion의 Inverse값에 다른 Quaternion을 곱해줌 initialRotationOffset = Quaternion.Inverse(GetTwoHandRotation()) * selectingInteractor.attachTransform.rotation; } public void OnSecondHandRelease(XRBaseInteractor interactor) { print("Second Hand Release"); secondInteractor = null; //두번쨰 Interactor 비워줌 } protected override void OnSelectEntered(XRBaseInteractor interactor) { base.OnSelectEntered(interactor); print("First Hand Enter"); attachInitialRotation = interactor.attachTransform.localRotation; //첫 번째 손의 원래 회전값 저장 } protected override void OnSelectExited(XRBaseInteractor interactor) { base.OnSelectExited(interactor); print("First Hand Exit"); secondInteractor = null; //첫번째 손을 놓으면, 두번째 손도 놓게 interactor.attachTransform.localRotation = attachInitialRotation; //첫 번째 손의 회전값 리셋 } }