diff --git a/Assets/Scripts/BoxController.cs b/Assets/Scripts/BoxController.cs index e2abff1..9a3865e 100644 --- a/Assets/Scripts/BoxController.cs +++ b/Assets/Scripts/BoxController.cs @@ -48,6 +48,7 @@ public class BoxController : MonoBehaviour // 로봇 팔을 부모로 설정하여 따라다니게 함 attachParent = other.transform; transform.SetParent(attachParent); + transform.SetPositionAndRotation(Vector3.zero, Quaternion.identity); // 부착된 동안 물리적 충돌이나 중력을 무시하도록 Rigidbody를 Kinematic으로 설정 if (rb != null) diff --git a/Assets/Scripts/Model/ProgramModel.cs b/Assets/Scripts/Model/ProgramModel.cs index fca2f68..4d12a4e 100644 --- a/Assets/Scripts/Model/ProgramModel.cs +++ b/Assets/Scripts/Model/ProgramModel.cs @@ -524,6 +524,9 @@ public class ProgramModel : IProgramModel public async Task GetMovingState() { - return await tcpClient.SendGetRequestAsync("/project/robot/moving_to_pose_manual"); + string jsonResponse = await tcpClient.SendGetRequestAsync("/project/robot/moving_to_pose_manual"); + string parsingJsonResponse = HttpResponseParser.ExtractJsonFromHttpResponse(jsonResponse); + + return parsingJsonResponse; } } \ No newline at end of file diff --git a/Assets/Scripts/Presenter/ProgramPresenter.cs b/Assets/Scripts/Presenter/ProgramPresenter.cs index 5fcba74..337abba 100644 --- a/Assets/Scripts/Presenter/ProgramPresenter.cs +++ b/Assets/Scripts/Presenter/ProgramPresenter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Net.Sockets; using System.Threading; @@ -76,6 +77,9 @@ public class ProgramPresenter this.controlledRobot = robot; this.controlledRobot.OnPoseUpdateRequest += HandleGETPose; popPos = controlledRobot.GetEndPoint(); + + if (controlledRobot != null) + controlledRobot.StartCoroutine(UpdateRobotMovingStateCoroutine()); } public async Task UpdateMotorStateAsync() @@ -96,6 +100,37 @@ public class ProgramPresenter } } + private IEnumerator UpdateRobotMovingStateCoroutine() + { + var waitForOneSecond = new WaitForSeconds(1.0f); + while (true) + { + Task getTask = model.GetMovingState(); + + yield return new WaitUntil(() => getTask.IsCompleted); + + try + { + if (getTask.IsFaulted) + { + throw getTask.Exception.InnerException; + } + + string currentState = getTask.Result; + + if (pointManagerView.movingAlert != null) + { + pointManagerView.movingAlert.SetActive(currentState == "1"); + } + } + catch (Exception e) + { + Debug.LogWarning($"κ moving Ʈ : {e.Message}"); + } + yield return waitForOneSecond; + } + } + public void OnApplicationStart() { if (controlledRobot != null) @@ -220,7 +255,7 @@ public class ProgramPresenter this.latestTargetPose = ConvertPoseToRobotData(newWorldPos, newWorldRot); - await model.MoveToPoseTcpAsync(newWorldPos); + await model.MoveToPoseTcpAsync(newWorldPos); } catch (Exception e) { @@ -232,9 +267,10 @@ public class ProgramPresenter private void HandleRobotReleased(RobotData pose) { IsDragging = false; - pendingPointData = pose; // ӽ + pendingPointData = this.latestTargetPose; // ӽ currentPopupState = PopupState.ConfirmAddPoint; // - popupView.ShowConfirmPopup(popPos); // ˾ û + + _ = WaitForRobotToStopAndShowPopup(currentPopupState); } private void StopDragMoveLoop() @@ -245,11 +281,11 @@ public class ProgramPresenter } // --- Ʈ Ŭ --- - private void HandlePointClicked(int index) + private void HandlePointClicked(int index, Vector3 newWorldPos) { activePointIndex = index; // ε currentPopupState = PopupState.MoveOrDelete; // - popupView.ShowOptionPopup(popPos); // ˾ û + popupView.ShowOptionPopup(newWorldPos); // ˾ û } // --- Ʈ 巡 --- @@ -283,7 +319,7 @@ public class ProgramPresenter RedrawTemporaryPath(index, latestTargetPose); } - private void HandlePointDragEnd(int index) + private async void HandlePointDragEnd(int index) { IsDragging = false; @@ -291,10 +327,14 @@ public class ProgramPresenter interactionView.HideGhostRobot(); pendingPointData = this.latestTargetPose; - currentPopupState = PopupState.ConfirmModifyPoint; // - popupView.ShowConfirmPopup(popPos); - } + Vector3 popupWorldPos = ConvertRobotDataToVector3(pendingPointData); + await model.MoveToPoseTcpAsync(popupWorldPos); + + currentPopupState = PopupState.ConfirmModifyPoint; // + + popupView.ShowModifyPopup(popPos); + } // --- ˾ ڵ鷯 --- private async void HandlePopupResponse(PopupResponse response) @@ -307,7 +347,7 @@ public class ProgramPresenter case PopupState.ConfirmAddPoint: if (response == PopupResponse.InsConfirm) { - await model.SavePointToProgramAsync(pendingPointData); + await model.SavePointToProgramAsync(pendingPointData, -1); RedrawSceneFromModel(); // } break; @@ -323,27 +363,23 @@ public class ProgramPresenter else if (response == PopupResponse.Cancel) { pointManagerView.UpdatePointPosition(activePointIndex, originalDragPose); // ġ - RedrawSceneFromModel(); // ġ + RedrawTemporaryPath(activePointIndex, originalDragPose); // ġ } break; // ̵/ case PopupState.MoveOrDelete: + RobotData targetPose = model.CurrentProgram.GetStepPose(activePointIndex); + Vector3 pos = ConvertRobotDataToVector3(targetPose); if (response == PopupResponse.Move) { - RobotData targetPose = model.CurrentProgram.GetStepPose(activePointIndex); - Vector3 pos = ConvertRobotDataToVector3(targetPose); - - // ˸ UI ǥ - pointManagerView.movingAlert.SetActive(true); - await model.MoveToPoseTcpAsync(pos); - Debug.Log($"̵ ? : { await model.GetMovingState()}"); // TODO.  ޾ƿ. } else if (response == PopupResponse.Delete) { + popupView.ShowDeletePopup(pos); currentPopupState = PopupState.ConfirmDelete; - popupView.ShowConfirmPopup(popPos); + return; } break; @@ -362,10 +398,42 @@ public class ProgramPresenter activePointIndex = -1; } + private async Task WaitForRobotToStopAndShowPopup(PopupState nextState) + { + while (await model.GetMovingState() == "1") + { + Debug.Log("κ ߱⸦ ٸ ..."); + await Task.Delay(100); + } + + Debug.Log("κ Ϸ. ˾ ǥ."); + currentPopupState = nextState; + + Vector3 popupWorldPos = Vector3.zero; + + if (nextState == PopupState.ConfirmAddPoint) + { + popupWorldPos = ConvertRobotDataToVector3(pendingPointData); + popupView.ShowConfirmPopupFromPoint(popupWorldPos); // ( Ʈ ġ) + } + } + + private async Task WaitForRobotToStop() + { + Debug.Log("κ ̵ Ϸ ..."); + await Task.Delay(200); // ( ޵ ּ ð) + while (await model.GetMovingState() == "1") + { + await Task.Delay(100); + } + Debug.Log("κ Ϸ."); + } + // Model ¸ о View ħ - private void RedrawSceneFromModel() + private async void RedrawSceneFromModel() { if (model.CurrentProgram == null) return; + await model.LoadProgram(model.CurrentProgram.ProgramId); // RobotProgram.Steps (List) List ȯ List poses = model.CurrentProgram.GetAllStepPoses(); diff --git a/Assets/Scripts/View/InteractionView.cs b/Assets/Scripts/View/InteractionView.cs index cba61de..e221017 100644 --- a/Assets/Scripts/View/InteractionView.cs +++ b/Assets/Scripts/View/InteractionView.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Threading; using System.Threading.Tasks; using UnityEngine; @@ -15,7 +16,7 @@ public class InteractionView : MonoBehaviour, IInteractionView { public event Action OnRobotGrabbed; public event Action OnRobotReleased; - public event Action OnPointClicked; + public event Action OnPointClicked; public event Action OnPointDragStart; public event Action OnPointDragUpdate; public event Action OnPointDragEnd; @@ -30,11 +31,18 @@ public class InteractionView : MonoBehaviour, IInteractionView [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() @@ -76,21 +84,29 @@ public class InteractionView : MonoBehaviour, IInteractionView } else { - Vector3 currentTargetPosition = Vector3.zero; - Quaternion currentTargetRotation = Quaternion.identity; - currentTargetPosition = rayProvider.rayEndPoint; currentTargetRotation = baseInteractor.attachTransform.rotation; + if (isGrabbingRobot) + { + OnRobotGrabbed?.Invoke(currentTargetPosition, currentTargetRotation); + return; + } if (isGrabbingPoint) { OnPointDragUpdate?.Invoke(currentGrabbedPointIndex, currentTargetPosition, currentTargetRotation); } - else if (isGrabbingRobot) + else if (clickOrDragCoroutine != null) { - OnRobotGrabbed?.Invoke(currentTargetPosition, currentTargetRotation); + float distance = Vector3.Distance(startGrabPosition, currentTargetPosition); + + if (distance > dragMovementThreshold) + { + StartDragMode(); + } } + } } @@ -110,8 +126,6 @@ public class InteractionView : MonoBehaviour, IInteractionView { baseInteractor.selectEntered.RemoveListener(HandleGrabStart); baseInteractor.selectExited.RemoveListener(HandleGrabEnd); - //interactor.activated.RemoveListener(OnActivated); - //interactor.deactivated.RemoveListener(OnDeactivated); } } @@ -128,7 +142,13 @@ public class InteractionView : MonoBehaviour, IInteractionView isGrabbingRobot = false; currentGrabbedPointIndex = point.pointIndex; - OnPointDragStart?.Invoke(currentGrabbedPointIndex); + // Ÿ̸ + startGrabPosition = rayProvider.rayEndPoint; + if (clickOrDragCoroutine != null) + StopCoroutine(clickOrDragCoroutine); + clickOrDragCoroutine = StartCoroutine(ClickOrDragTimer()); + + //OnPointDragStart?.Invoke(currentGrabbedPointIndex); } else if (grabbedGO.CompareTag("RobotArm")) { @@ -142,21 +162,57 @@ public class InteractionView : MonoBehaviour, IInteractionView private void HandleGrabEnd(SelectExitEventArgs args) { - if (isGrabbingPoint) - { - OnPointDragEnd?.Invoke(currentGrabbedPointIndex); - } - else if (isGrabbingRobot) + 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) { diff --git a/Assets/Scripts/View/PointManagerView.cs b/Assets/Scripts/View/PointManagerView.cs index 39b7ba5..49bd7ed 100644 --- a/Assets/Scripts/View/PointManagerView.cs +++ b/Assets/Scripts/View/PointManagerView.cs @@ -17,6 +17,11 @@ public class PointManagerView : MonoBehaviour, IPointManagerView [Tooltip(" κ IK")] public HybridInverseKinematicsNode kinematicsNode; + void Start() + { + movingAlert.SetActive(false); + } + private Vector3 ConvertRobotDataToVector3(RobotData pose) { float x = Convert.ToSingle(pose.x / -1000.0); // mm -> m diff --git a/Assets/Scripts/View/PopupView.cs b/Assets/Scripts/View/PopupView.cs index 9a990af..23a2afd 100644 --- a/Assets/Scripts/View/PopupView.cs +++ b/Assets/Scripts/View/PopupView.cs @@ -50,27 +50,38 @@ public class PopupView : MonoBehaviour, IPopupView optionPopupPanel.SetActive(false); } - public void ShowConfirmPopup(Transform popPose) + public void ShowConfirmPopupFromRobot(Transform popPose) { - confirmPopupPanel.transform.SetPositionAndRotation(popPose.position, Quaternion.identity); + confirmPopupPanel.transform.position = popPose.position; + confirmPopupPanel.transform.LookAt(Camera.main.transform); + confirmPopupPanel.SetActive(true); + } + + public void ShowConfirmPopupFromPoint(Vector3 popPose) + { + confirmPopupPanel.transform.position = popPose; + confirmPopupPanel.transform.LookAt(Camera.main.transform); confirmPopupPanel.SetActive(true); } public void ShowModifyPopup(Transform popPose) { - modifyPopupPanel.transform.SetPositionAndRotation(popPose.position, Quaternion.identity); + modifyPopupPanel.transform.position = popPose.position; + modifyPopupPanel.transform.LookAt(Camera.main.transform); modifyPopupPanel.SetActive(true); } - public void ShowDeletePopup(Transform popPose) + public void ShowDeletePopup(Vector3 popPose) { - deletePopupPanel.transform.SetPositionAndRotation(popPose.position, Quaternion.identity); + deletePopupPanel.transform.position = popPose; + deletePopupPanel.transform.LookAt(Camera.main.transform); deletePopupPanel.SetActive(true); } - public void ShowOptionPopup(Transform popPose) + public void ShowOptionPopup(Vector3 popPose) { - optionPopupPanel.transform.SetPositionAndRotation(popPose.position, Quaternion.identity); + optionPopupPanel.transform.position = popPose; + optionPopupPanel.transform.LookAt(Camera.main.transform); optionPopupPanel.SetActive(true); }