298 lines
9.3 KiB
C#
298 lines
9.3 KiB
C#
using System;
|
|
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 class InteractionView : MonoBehaviour, IInteractionView
|
|
{
|
|
public event Action<Vector3, Quaternion> OnRobotGrabbed;
|
|
public event Action<RobotData> OnRobotReleased;
|
|
public event Action<int> OnPointClicked;
|
|
public event Action<int> OnPointDragStart;
|
|
public event Action<int, Vector3, Quaternion> OnPointDragUpdate;
|
|
public event Action<int> OnPointDragEnd;
|
|
|
|
[SerializeField]private NearFarInteractor nearFarInteractor;
|
|
private XRBaseInteractor baseInteractor;
|
|
private IXRRayProvider rayProvider;
|
|
|
|
private bool isInitialized = false;
|
|
private bool isGrabbingPoint = false;
|
|
private int currentGrabbedPointIndex = -1;
|
|
|
|
public bool isGrabbingRobot = false;
|
|
|
|
void Start()
|
|
{
|
|
nearFarInteractor = GetComponent<NearFarInteractor>();
|
|
|
|
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<NearFarInteractor>(true);
|
|
baseInteractor = nearFarInteractor as XRBaseInteractor;
|
|
rayProvider = nearFarInteractor as IXRRayProvider;
|
|
}
|
|
if (nearFarInteractor != null && nearFarInteractor.gameObject.activeInHierarchy)
|
|
{
|
|
InitializeInteraction();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Vector3 currentTargetPosition = Vector3.zero;
|
|
Quaternion currentTargetRotation = Quaternion.identity;
|
|
|
|
currentTargetPosition = rayProvider.rayEndPoint;
|
|
currentTargetRotation = baseInteractor.attachTransform.rotation;
|
|
|
|
|
|
if (isGrabbingPoint)
|
|
{
|
|
OnPointDragUpdate?.Invoke(currentGrabbedPointIndex, currentTargetPosition, currentTargetRotation);
|
|
}
|
|
else if (isGrabbingRobot)
|
|
{
|
|
OnRobotGrabbed?.Invoke(currentTargetPosition, currentTargetRotation);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void InitializeInteraction()
|
|
{
|
|
// XRI 이벤트 구독
|
|
baseInteractor.selectEntered.AddListener(HandleGrabStart);
|
|
baseInteractor.selectExited.AddListener(HandleGrabEnd);
|
|
//interactor.activated.AddListener(OnActivated);
|
|
//interactor.deactivated.AddListener(OnDeactivated);
|
|
|
|
isInitialized = true;
|
|
AppManager.Instance.RegisterView(this);
|
|
}
|
|
|
|
private void OnDestroy()
|
|
{
|
|
if (baseInteractor != null)
|
|
{
|
|
baseInteractor.selectEntered.RemoveListener(HandleGrabStart);
|
|
baseInteractor.selectExited.RemoveListener(HandleGrabEnd);
|
|
//interactor.activated.RemoveListener(OnActivated);
|
|
//interactor.deactivated.RemoveListener(OnDeactivated);
|
|
}
|
|
}
|
|
|
|
// --- XRI 이벤트 핸들러 ---
|
|
|
|
// "잡기" 버튼을 눌렀을 때
|
|
private void HandleGrabStart(SelectEnterEventArgs args)
|
|
{
|
|
GameObject grabbedGO = args.interactableObject.transform.gameObject;
|
|
|
|
// 잡은 것이 "포인트"인지 확인
|
|
//RobotPoint point = grabbedGO.GetComponent<RobotPoint>();
|
|
//if (point != null)
|
|
//{
|
|
// isGrabbingPoint = true;
|
|
// isGrabbingRobot = false;
|
|
// currentGrabbedPointIndex = point.pointIndex;
|
|
|
|
// // (Presenter의 HandlePointDragStart 호출)
|
|
// OnPointDragStart?.Invoke(currentGrabbedPointIndex);
|
|
//}
|
|
// 2. 잡은 것이 "로봇 핸들"인지 확인
|
|
if (grabbedGO.CompareTag("RobotArm"))
|
|
{
|
|
isGrabbingPoint = false;
|
|
isGrabbingRobot = true;
|
|
|
|
// (로봇 자체를 잡는 것은 -1 인덱스로 Presenter에게 알림)
|
|
currentGrabbedPointIndex = -1;
|
|
|
|
// (로봇 잡기도 "PointDragStart" 이벤트로 통합하여 Presenter에 알림)
|
|
OnPointDragStart?.Invoke(currentGrabbedPointIndex);
|
|
}
|
|
|
|
//if (!enableSelectToDrag) return;
|
|
//BeginDrag(args.interactorObject);
|
|
}
|
|
|
|
// "잡기" 버튼을 뗐을 때
|
|
private void HandleGrabEnd(SelectExitEventArgs args)
|
|
{
|
|
//if (!enableSelectToDrag) return;
|
|
//EndDrag();
|
|
//// "포인트"를 놓고 있는 중이었다면
|
|
//if (isGrabbingPoint)
|
|
//{
|
|
// // Presenter에게 "드래그 끝" 이벤트 전송 (팝업 트리거용)
|
|
// OnPointDragEnd?.Invoke(currentGrabbedPointIndex);
|
|
//}
|
|
//// "로봇"을 놓고 있는 중이었다면
|
|
//else if (isGrabbingRobot)
|
|
//{
|
|
// // Presenter에게 "로봇 놓기" 이벤트 전송 (팝업 트리거용)
|
|
// RobotData currentPose = GetCurrentRobotPoseFromController();
|
|
// OnRobotReleased?.Invoke(currentPose);
|
|
//}
|
|
|
|
// 상태 초기화
|
|
isGrabbingPoint = false;
|
|
isGrabbingRobot = false;
|
|
currentGrabbedPointIndex = -1;
|
|
}
|
|
|
|
// ---- Drag lifecycle ----
|
|
//private void BeginDrag(IXRInteractor interactor)
|
|
//{
|
|
// currentInteractor = interactor;
|
|
// isDragging = true;
|
|
|
|
// startPosition = transform.position;
|
|
// //pathLine.enabled = true;
|
|
|
|
// uiController?.UpdateStatus("드래그 중...");
|
|
// if (communicationScript != null) communicationScript.isMoving = false;
|
|
|
|
// // ← 드래그 루프 시작
|
|
// StartDragMoveLoop();
|
|
//}
|
|
|
|
//private void EndDrag()
|
|
//{
|
|
// if (!isDragging) return;
|
|
// isDragging = false;
|
|
// uiController?.UpdateStatus("완료!");
|
|
// communicationScript.isMoving = false;
|
|
// // ← 루프 중지
|
|
// StopDragMoveLoop();
|
|
|
|
// currentInteractor = null;
|
|
//}
|
|
|
|
//private void StopDragMoveLoop()
|
|
//{
|
|
// if (dragLoopCts != null)
|
|
// {
|
|
// dragLoopCts.Cancel();
|
|
// dragLoopCts.Dispose();
|
|
// dragLoopCts = null;
|
|
// }
|
|
//}
|
|
|
|
|
|
//private void StartDragMoveLoop()
|
|
//{
|
|
// StopDragMoveLoop(); // 중복 방지
|
|
// dragLoopCts = new CancellationTokenSource();
|
|
// _ = DragMoveLoopAsync(dragLoopCts.Token);
|
|
//}
|
|
|
|
//private async Task DragMoveLoopAsync(CancellationToken token)
|
|
//{
|
|
// // 드래그 동안 100ms 주기로 전송
|
|
// while (!token.IsCancellationRequested && isDragging)
|
|
// {
|
|
// try
|
|
// {
|
|
// // 로봇이 아직 이동 중이 아니라면(대기 상태) 최신 dragPosition으로 지령 전송
|
|
// if (communicationScript != null && !communicationScript.isMoving)
|
|
// {
|
|
// await MovingTask(); // 내부에서 StratMovement(dragPosition) 호출 및 isMoving 갱신 :contentReference[oaicite:4]{index=4}
|
|
// }
|
|
|
|
// await Task.Delay(10, token); // 100ms 주기
|
|
// }
|
|
// catch (TaskCanceledException) { /* 정상 취소 */ }
|
|
// }
|
|
//}
|
|
|
|
//// ---- Per-frame ----
|
|
//void Update()
|
|
//{
|
|
// if (isDragging && currentInteractor != null)
|
|
// {
|
|
// communicationScript.isMoving = false;
|
|
// // 1) Ray Interactor: 현재 3D Raycast 히트 포인트가 있으면 그대로 사용
|
|
// if (currentInteractor is XRRayInteractor ray &&
|
|
// ray.TryGetCurrent3DRaycastHit(out RaycastHit hit))
|
|
// {
|
|
// dragPosition = hit.point;
|
|
// }
|
|
// else
|
|
// {
|
|
// // 2) Direct Interactor 또는 Ray 히트가 없을 때: 컨트롤러(또는 attachTransform) 위치 사용
|
|
// var t = currentInteractor.transform;
|
|
// var attach = currentInteractor.GetAttachTransform(null);
|
|
// dragPosition = attach != null ? attach.position : t.position;
|
|
// }
|
|
|
|
// uiController?.UpdateCoordinates(dragPosition); // 기존 UI 갱신 유지 :contentReference[oaicite:2]{index=2}
|
|
// }
|
|
//}
|
|
|
|
//private async Task MovingTask()
|
|
//{
|
|
// if (communicationScript == null) return;
|
|
// bool ok = await communicationScript.StratMovement(dragPosition); // 기존 호출 그대로 사용 :contentReference[oaicite:3]{index=3}
|
|
// if (ok) communicationScript.isMoving = true;
|
|
//}
|
|
|
|
private RobotData GetCurrentRobotPoseFromController()
|
|
{
|
|
// 이 View는 Presenter의 변환 로직(ConvertVrToRobotPose)을 알 수 없으므로,
|
|
// 현재 컨트롤러 위치/회전을 기반으로 '가짜' RobotData를 만듦
|
|
// Presenter가 이 데이터를 받아 어차피 다시 변환(또는 무시)해야 함
|
|
return new RobotData(); // 임시 데이터
|
|
}
|
|
|
|
// --- Presenter가 호출할 함수들 ---
|
|
public void ShowGhostRobot(RobotData pose)
|
|
{
|
|
/* 반투명 로봇2 활성화 및 위치 설정 */
|
|
}
|
|
|
|
public void HideGhostRobot()
|
|
{
|
|
/* 반투명 로봇2 비활성화 */
|
|
}
|
|
|
|
public void ShowDragArrow(Vector3 position)
|
|
{
|
|
/* 드래그용 화살표 UI 활성화 및 위치 설정 */
|
|
}
|
|
|
|
public void HideDragArrow()
|
|
{
|
|
/* 드래그용 화살표 UI 비활성화 */
|
|
}
|
|
}
|