<feat> 로봇 동기화 (제어기 <-> 3d)

This commit is contained in:
SOOBEEN HAN
2025-11-04 11:36:19 +09:00
parent 8724f09a34
commit 23e3a34837
13 changed files with 1957 additions and 293 deletions

View File

@@ -1,9 +1,12 @@
using System;
using UnityEngine;
using UnityEngine.XR.Interaction.Toolkit;
using UnityEngine.XR.Interaction.Toolkit.Interactors;
// Presenter가 InteractionView를 제어하기 위한 인터페이스
public interface IInteractionView
{
event Action<Vector3, Quaternion> OnRobotGrabbed;
// VR 컨트롤러가 로봇을 잡았다 놨을 때 발생
event Action<RobotData> OnRobotReleased;
// VR 컨트롤러가 특정 포인트를 클릭했을 때 발생
@@ -20,38 +23,139 @@ public interface IInteractionView
void HideDragArrow();
}
// (이 스크립트는 VR 컨트롤러 로직이 있는 곳에 붙어야 합니다)
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> OnPointDragUpdate;
public event Action<int> OnPointDragEnd;
private XRBaseInteractor interactor;
private bool isInitialized = false;
private bool isGrabbingPoint = false;
private int currentGrabbedPointIndex = -1;
public bool isGrabbingRobot = false;
void Start()
{
// Ray Interactor와 Direct Interactor 모두 처리할 수 있도록 XRBaseInteractor로 받음
interactor = GetComponent<NearFarInteractor>();
if (interactor == null)
{
Debug.LogError("InteractionView requires an XRBaseInteractor (Ray or Direct) on the same GameObject.", this);
return;
}
}
// --- 실시간 스트리밍을 위한 Update ---
void Update()
{
// 컨트롤러로 로봇을 잡고있는지 감지
// if (IsGrabbingRobot()) { ... }
if (isInitialized)
{
if (isGrabbingPoint)
{
Vector3 currentControllerPosition = interactor.attachTransform.position;
OnPointDragUpdate?.Invoke(currentGrabbedPointIndex, currentControllerPosition);
}
else if(isGrabbingRobot)
{
Vector3 currentHandleTransform = interactor.attachTransform.position;
Quaternion currentControllerRotation = interactor.attachTransform.rotation;
OnRobotGrabbed?.Invoke(currentHandleTransform, currentControllerRotation);
}
}
else
{
if (interactor == null)
{
interactor = GetComponentInChildren<NearFarInteractor>(true);
}
if (interactor != null && interactor.gameObject.activeInHierarchy)
{
InitializeInteraction();
}
}
}
// 컨트롤러 그랩 버튼을 뗐을 때
// if (OnGrabRelease())
// {
// RobotData currentPose = GetCurrentRobotPose();
// OnRobotReleased?.Invoke(currentPose); // 2. "위치 확정?" 팝업 요청
// }
private void InitializeInteraction()
{
// XRI 이벤트 구독
interactor.selectEntered.AddListener(HandleGrabStart);
interactor.selectExited.AddListener(HandleGrabEnd);
// 컨트롤러로 포인트를 클릭했을 때
// if (OnPointClick(out int clickedPointIndex))
// {
// OnPointClicked?.Invoke(clickedPointIndex); // 8. "이동/삭제?" 팝업 요청
// }
// '클릭'을 감지하려면 interactor.activated 이벤트를 구독해야 함
// 컨트롤러로 포인트를 꾹 누르기 시작(드래그 시작)
// if (OnPointHold(out int draggedPointIndex))
// {
// OnPointDragStart?.Invoke(draggedPointIndex); // 5. 드래그 시작
// }
isInitialized = true;
AppManager.Instance.RegisterView(this);
Debug.Log("InteractionView 초기화 완료. Interactor 이벤트 구독 시작.");
}
private void OnDestroy()
{
if (interactor != null)
{
interactor.selectEntered.RemoveListener(HandleGrabStart);
interactor.selectExited.RemoveListener(HandleGrabEnd);
}
}
// --- XRI 이벤트 핸들러 ---
// "잡기" 버튼을 눌렀을 때
private void HandleGrabStart(SelectEnterEventArgs args)
{
// 잡은 대상 오브젝트
GameObject grabbedGO = args.interactableObject.transform.gameObject;
//// 잡은 것이 "포인트"인지 확인 (RobotPoint 스크립트 탐색)
//RobotPoint point = grabbedGO.GetComponent<RobotPoint>();
//if (point != null)
//{
// isGrabbingPoint = true;
// currentGrabbedPointIndex = point.pointIndex;
// // Presenter에게 "드래그 시작" 이벤트 전송
// OnPointDragStart?.Invoke(currentGrabbedPointIndex);
//}
// 잡은 것이 "로봇"인지 확인
if (grabbedGO.CompareTag("RobotArm"))
{
isGrabbingRobot = true;
}
}
// "잡기" 버튼을 뗐을 때
private void HandleGrabEnd(SelectExitEventArgs args)
{
// "포인트"를 놓고 있는 중이었다면
if (isGrabbingPoint)
{
// Presenter에게 "드래그 끝" 이벤트 전송 (팝업 트리거용)
OnPointDragEnd?.Invoke(currentGrabbedPointIndex);
}
// "로봇"을 놓고 있는 중이었다면
else if (isGrabbingRobot)
{
// Presenter에게 "로봇 놓기" 이벤트 전송 (팝업 트리거용)
RobotData currentPose = GetCurrentRobotPoseFromController();
OnRobotReleased?.Invoke(currentPose);
}
// 상태 초기화
isGrabbingPoint = false;
currentGrabbedPointIndex = -1;
}
private RobotData GetCurrentRobotPoseFromController()
{
// 이 View는 Presenter의 변환 로직(ConvertVrToRobotPose)을 알 수 없으므로,
// 현재 컨트롤러 위치/회전을 기반으로 '가짜' RobotData를 만듦
// Presenter가 이 데이터를 받아 어차피 다시 변환(또는 무시)해야 함
return new RobotData(); // 임시 데이터
}
// --- Presenter가 호출할 함수들 ---