【问题标题】:How to move a UI GameObject using Mouse Position in 3D World Space?如何在 3D 世界空间中使用鼠标位置移动 UI 游戏对象?
【发布时间】:2020-06-24 12:36:11
【问题描述】:

我一直在尝试使用鼠标的位置移动 UI 元素,试图让它表现得像一个光标。当画布渲染模式设置为 “屏幕空间” 时,我能够移动元素。我也能够将它夹在画布内。

但我希望它在画布渲染模式为 “世界空间” 时也能正常工作。如果我使用与屏幕空间相同的代码,元素会离开其边界并随着角度的变化而变得混乱。

我真的需要帮助。有什么办法吗?

您可以在下图中查看场景的外观。 :https://img.techpowerup.org/200624/screen.png

如果 Raycasting 是解决方案,有人可以帮助我并提供代码或其他东西的 sn-p。

【问题讨论】:

    标签: c# unity3d mouse game-engine


    【解决方案1】:

    你要找的可能是RectTransformUtility.ScreenPointToWorldPointInRectangle

    将屏幕空间点转换为世界空间中的某个位置 给定RectTransform 的平面。

    cam参数应该是与屏幕关联的相机 观点。对于 Canvas 中的 RectTransform 设置为 Screen Space - Overlay 模式,cam参数应该是null

    ScreenPointToWorldPointInRectangle 在事件中使用时 提供PointerEventData 对象的处理程序,正确的相机 可以通过使用PointerEventData.enterEventData获得(对于悬停 功能)或PointerEventData.pressEventCamera(点击 功能)。这将自动使用正确的相机(或 null) 用于给定事件。

    您没有发布您的代码,但您可以在GraphicRaycaster.Raycast 中使用它。类似的东西

    GraphicRaycaster m_Raycaster;
    PointerEventData m_PointerEventData;
    EventSystem m_EventSystem;
    Canvas canvas;
    
    void Start()
    {
        //Fetch the Raycaster from the GameObject (the Canvas)
        m_Raycaster = GetComponent<GraphicRaycaster>();
        //Fetch the Event System from the Scene
        m_EventSystem = GetComponent<EventSystem>();
        canvas = GetComponnet<Canvas>();
    
        //Set up the new Pointer Event
        m_PointerEventData = new PointerEventData(m_EventSystem);
    }
    
    void Update()
    {
        //Check if the left Mouse button is clicked
        if (Input.GetKey(KeyCode.Mouse0))
        {
            //Set the Pointer Event Position to that of the mouse position
            m_PointerEventData.position = Input.mousePosition;
    
            //Create a list of Raycast Results
            List<RaycastResult> results = new List<RaycastResult>();
    
            //Raycast using the Graphics Raycaster and mouse click position
            m_Raycaster.Raycast(m_PointerEventData, results);
    
            //For every result returned, output the name of the GameObject on the Canvas hit by the Ray
            foreach (RaycastResult result in results)
            {
                Debug.Log("Hit " + result.gameObject.name);
    
                // until here it was the API example for GraphicRaycaster.Raycast
                // Now get the first hit object
                var rect = result.gameObject.GetComponent<RectTransform>();
                if(rect)
                {
                    // check which camera to get (main or null for ScreenSpace Overlay)
                    var camera = canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : Camera.main;
                    if(RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, result.screenPosition, camera, out var worldPosition))
                    {
                        cursor3D.transform.position = worldPosition;
                        cursor3D.transform.rotation = result.gameObject.transform.rotation;
                        break;
                    }
                }
            }
        }
    }
    

    还要特别注意

    • 将此脚本附加到您的Canvas GameObject。
    • 还可以通过单击“检查器”窗口中的“添加组件”按钮将 GraphicsRaycaster 组件附加到您的画布。
    • 还要确保您的层次结构中有 EventSystem

    【讨论】:

    • 感谢您的回复。我确实尝试过这段代码,它是一个基于点击的光标控件。所以我删除了检查左键单击的 if 语句。但是这种方法仍然不够准确。红色元素有时会脱离画布,但它比我的代码要好得多。有没有更好的解决方案可以帮助我准确地限制值。我试图用它在 3D 游戏中创建可交互的笔记本电脑。如果您有任何我应该研究的替代解决方案,请告诉我。再次感谢:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-17
    相关资源
    最近更新 更多