using System; using System.Collections; using System.Threading; using System.Threading.Tasks; using UnityEngine; using UnityEngine.XR.Interaction.Toolkit; using UnityEngine.XR.Interaction.Toolkit.Interactables; using UnityEngine.XR.Interaction.Toolkit.Interactors; public interface IInteractionView { } public enum HandSide { Left, Right } public class InteractionView : MonoBehaviour, IInteractionView { public event Action OnRobotGrabbed; public event Action OnRobotReleased; public event Action OnPointClicked; public event Action OnPointDragStart; public event Action OnPointDragUpdate; public event Action OnPointDragEnd; [SerializeField]private NearFarInteractor nearFarInteractor; public HandSide handSide; private XRBaseInteractor baseInteractor; private IXRRayProvider rayProvider; [SerializeField] [Tooltip("µå·¡±× ½Ã À§Ä¡¸¦ Ç¥½ÃÇÒ ¹ÝÅõ¸í ·Îº¿ ¸ðµ¨")] private GameObject ghostRobot; [SerializeField] [Tooltip("µå·¡±×¿ë ¸¶¿ì½º À̹ÌÁö")] private GameObject dragArrow; [SerializeField] private float clickTimeThreshold = 0.5f; [SerializeField] private float dragMovementThreshold = 0.05f; private Coroutine clickOrDragCoroutine = null; private Vector3 startGrabPosition; private bool isInitialized = false; private bool isGrabbingPoint = false; private int currentGrabbedPointIndex = -1; Vector3 currentTargetPosition = Vector3.zero; Quaternion currentTargetRotation = Quaternion.identity; public bool isGrabbingRobot = false; //void Start() //{ // nearFarInteractor = GetComponentInChildren(); // if (nearFarInteractor == null) // { // Debug.LogError("InteractionView: 'nearFarInteractor'°¡ ÇÒ´çµÇÁö ¾Ê¾Ò½À´Ï´Ù", this); // return; // } // baseInteractor = nearFarInteractor as XRBaseInteractor; // rayProvider = nearFarInteractor as IXRRayProvider; // if (baseInteractor == null) // { // Debug.LogError("NearFarInteractor¸¦ XRBaseInteractor·Î º¯È¯ÇÒ ¼ö ¾ø½À´Ï´Ù.", this); // return; // } // InitializeInteraction(); //} void Update() { if (!isInitialized || rayProvider == null) { if (nearFarInteractor == null) { nearFarInteractor = GetComponentInChildren(true); baseInteractor = nearFarInteractor as XRBaseInteractor; rayProvider = nearFarInteractor as IXRRayProvider; } if (nearFarInteractor != null) { InitializeInteraction(); } } else { currentTargetPosition = rayProvider.rayEndPoint; currentTargetRotation = baseInteractor.attachTransform.rotation; if (isGrabbingRobot) { OnRobotGrabbed?.Invoke(currentTargetPosition, currentTargetRotation); return; } if (isGrabbingPoint) { OnPointDragUpdate?.Invoke(currentGrabbedPointIndex, currentTargetPosition, currentTargetRotation); } else if (clickOrDragCoroutine != null) { float distance = Vector3.Distance(startGrabPosition, currentTargetPosition); if (distance > dragMovementThreshold) { StartDragMode(); } } } } private void InitializeInteraction() { // XRI À̺¥Æ® ±¸µ¶ baseInteractor.selectEntered.AddListener(HandleGrabStart); baseInteractor.selectExited.AddListener(HandleGrabEnd); isInitialized = true; AppManager.Instance.RegisterView(this); } private void OnDestroy() { if (baseInteractor != null) { baseInteractor.selectEntered.RemoveListener(HandleGrabStart); baseInteractor.selectExited.RemoveListener(HandleGrabEnd); } } // --- XRI À̺¥Æ® Çڵ鷯 --- private void HandleGrabStart(SelectEnterEventArgs args) { GameObject grabbedGO = args.interactableObject.transform.gameObject; RobotPoint point = grabbedGO.GetComponent(); if (point != null) { isGrabbingPoint = true; isGrabbingRobot = false; currentGrabbedPointIndex = point.pointIndex; // ŸÀÌ¸Ó ½ÃÀÛ startGrabPosition = rayProvider.rayEndPoint; if (clickOrDragCoroutine != null) StopCoroutine(clickOrDragCoroutine); clickOrDragCoroutine = StartCoroutine(ClickOrDragTimer()); //OnPointDragStart?.Invoke(currentGrabbedPointIndex); } else if (grabbedGO.CompareTag("RobotArm")) { isGrabbingPoint = false; isGrabbingRobot = true; currentGrabbedPointIndex = -1; OnPointDragStart?.Invoke(currentGrabbedPointIndex); } } private void HandleGrabEnd(SelectExitEventArgs args) { if (isGrabbingRobot) { OnRobotReleased?.Invoke(new RobotData()); } else { if (clickOrDragCoroutine != null) { StopCoroutine(clickOrDragCoroutine); clickOrDragCoroutine = null; OnPointClicked?.Invoke(currentGrabbedPointIndex, currentTargetPosition); } else if (isGrabbingPoint) { OnPointDragEnd?.Invoke(currentGrabbedPointIndex); } } // »óÅ ÃʱâÈ­ clickOrDragCoroutine = null; isGrabbingPoint = false; isGrabbingRobot = false; currentGrabbedPointIndex = -1; } // Ŭ¸¯/µå·¡±× ±¸ºÐÇϴ ŸÀÌ¸Ó ÄÚ·çÆ¾ private IEnumerator ClickOrDragTimer() { yield return new WaitForSeconds(clickTimeThreshold); if (clickOrDragCoroutine != null) { Debug.Log("½Ã°£ Ãʰú·Î µå·¡±× ½ÃÀÛ (OnPointDragStart)"); StartDragMode(); } } // ŸÀÌ¸Ó ÁßÁöÇÏ°í µå·¡±× ¸ðµå·Î Àüȯ private void StartDragMode() { if (clickOrDragCoroutine != null) { StopCoroutine(clickOrDragCoroutine); clickOrDragCoroutine = null; } isGrabbingPoint = true; OnPointDragStart?.Invoke(currentGrabbedPointIndex); } // ·Îº¿ ÁÂÇ¥°è(mm)¸¦ Unity ¿ùµå ÁÂÇ¥°è(m)·Î º¯È¯ private Vector3 ConvertRobotDataToVector3(RobotData pose) { float x = Convert.ToSingle(pose.x / -1000.0); float y = Convert.ToSingle(pose.z / 1000.0); float z = Convert.ToSingle(pose.y / -1000.0); return new Vector3(x, y, z); } // ·Îº¿ ¿ÀÀÏ·¯ °¢(rx,ry,rz)À» Unity ÄõÅʹϾðÀ¸·Î º¯È¯ private Quaternion ConvertRobotDataToQuaternion(RobotData pose) { return Quaternion.Euler(pose.rx, pose.ry, pose.rz); } // °í½ºÆ® ·Îº¿ÀÇ À§Ä¡/ȸÀü ¼³Á¤ public void ShowGhostRobot() { if (ghostRobot == null) { Debug.LogWarning("Ghost RobotÀÌ Inspector¿¡ ÇÒ´çµÇÁö ¾Ê¾Ò½À´Ï´Ù."); return; } ghostRobot.SetActive(true); } // °í½ºÆ® ·Îº¿ ºñȰ¼ºÈ­ public void HideGhostRobot() { if (ghostRobot != null) { ghostRobot.SetActive(false); } } // µå·¡±× È­»ìÇ¥ Ȱ¼ºÈ­ ¹× À§Ä¡ ¼³Á¤ public void ShowDragArrow(Vector3 position) { if (dragArrow == null) { Debug.LogWarning("Drag Arrow°¡ Inspector¿¡ ÇÒ´çµÇÁö ¾Ê¾Ò½À´Ï´Ù."); return; } dragArrow.SetActive(true); dragArrow.transform.position = position; } // µå·¡±× È­»ìÇ¥ ºñȰ¼ºÈ­ public void HideDragArrow() { if (dragArrow != null) { dragArrow.SetActive(false); } } // ±¤¼± ³¡ À§Ä¡ ¹Ýȯ public Vector3 GetCurrentRayPosition() { if (rayProvider != null) { return rayProvider.rayEndPoint; } if (baseInteractor != null) { return baseInteractor.attachTransform.position; } return transform.position; } }