unityUI在Camera模式下拖动偏移量过大

UI拖动自动吸附,我的代码可以在画布的overly模式下正常运行,但是一换到camera模式,UI偏移量就很大,鼠标动一下就飞出去了。代码如下,说是要加一个z轴的距离但我真的不会阿哭

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TuoDong : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler
{
    public GameObject Move;
    public GameObject StartT;

    private void Start()
    {
        Move = GameObject.Find("Canvas/BG");

    }
    public void OnBeginDrag(PointerEventData eventData)
    {
        StartT = transform.parent.gameObject;
        transform.GetComponent<CanvasGroup>().blocksRaycasts = false;
    }

    public void OnDrag(PointerEventData eventData)
    {
        transform.position = Input.mousePosition;
        transform.SetParent(Move.transform);
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        GameObject go = eventData.pointerCurrentRaycast.gameObject;
        if(go==null)
        {
            transform.SetParent(StartT.transform);
            Debug.Log("cg");
            transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        }else if(go!=null &&go.transform.tag == "背包格子")
        {
            transform.SetParent(go.transform);
            transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        }else if(go!= null && go.transform.tag!= "背包格子"&&go.transform.parent.tag == "物品模板")
        {
            Transform tf = go.transform.parent.parent.transform;
            go.transform.parent.SetParent(StartT.transform);

            transform.SetParent(tf);
            transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        }else if(go!=null && go.transform.tag != "背包格子" && go.transform.parent.tag != "物品模板")
        {
            transform.SetParent(StartT.transform);
            transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        }
    }

   

}


TechWhizKid参考GPT回答:

  • 问题出在代码把UI元素的位置直接设为了鼠标的屏幕坐标。这在Overlay模式下可以正常工作,因为Overlay模式下,Canvas的尺寸是与屏幕尺寸一致的。但是在Camera模式下,Canvas的尺寸可能并不与屏幕尺寸一致,这时候直接用屏幕坐标就会出现问题。
  • 这个问题你要把屏幕坐标转换为Canvas的坐标,修改OnDrag函数如下:
public void OnDrag(PointerEventData eventData)
{
    Vector2 localPoint;
    RectTransformUtility.ScreenPointToLocalPointInRectangle(Move.transform as RectTransform, eventData.position, eventData.pressEventCamera, out localPoint);
    transform.position = Move.transform.TransformPoint(localPoint);
    transform.SetParent(Move.transform);
}


  • RectTransformUtility.ScreenPointToLocalPointInRectangle函数将屏幕坐标转换为了Canvas的坐标。它的参数分别是:目标矩形,屏幕点的位置,事件的相机,和输出的本地位置。然后我们用TransformPoint函数将这个本地坐标转换为世界坐标,并将其赋给transform的position。这样就能在Camera模式下正常拖动UI元素了。

你在摄像机模式下UI元素的深度(z轴)距离不正确,导致鼠标移动时UI元素移动幅度太大,,要解决摄像机模式下UI拖拽时偏移过大的问题,关键是控制好UI元素的缩放、位置和z轴深度。

看来您遇到了一个关于UI在Camera模式下拖动的问题。根据您的代码,我们可以发现您尝试在拖动过程中设置UI偏移量并使用transform.parent来移动UI到新的位置。
然而,当您在Camera模式下拖动UI时,这个偏移量可能不足以移动UI到您想要的位置。您可以尝试添加以下代码:

将Camera模式下的Camera对象设为私有,从而防止其他代码对其进行修改。
将CullingMask设置为屏蔽画布外部的碰撞,这样就可以防止物体穿过Camera。
下面是一个可能的改进版本:


using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
public class TuoDong : MonoBehaviour,IBeginDragHandler,IDragHandler,IEndDragHandler
{
    public GameObject Move;
    public GameObject StartT;
    private Camera mainCamera;

    private void Start()
    {
        mainCamera = Camera.main;
    }
    public void OnBeginDrag(PointerEventData eventData)
    {
        StartT = transform.parent.gameObject;
        mainCamera.gameObject.SetActive(false);
        transform.GetComponent<CanvasGroup>().blocksRaycasts = false;
    }

    public void OnDrag(PointerEventData eventData)
    {
        mainCamera.transform.position = Input.mousePosition;
        mainCamera.gameObject.SetActive(true);
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        GameObject go = eventData.pointerCurrentRaycast.gameObject;
        if(go==null)
        {
            transform.SetParent(StartT.transform);
            Debug.Log("cg");
            transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        }else if(go!=null &&go.transform.tag == "背包格子")
        {
            transform.SetParent(go.transform);
            transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        }else if(go!= null && go.transform.tag != "背包格子"&&go.transform.parent.tag == "物品模板")
        {
            Transform tf = go.transform.parent.parent.transform;
            go.transform.parent.SetParent(StartT.transform);
 
            transform.SetParent(tf);
            transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        }else if(go!=null && go.transform.tag != "背包格子" && go.transform.parent.tag != "物品模板")
        {
            transform.SetParent(StartT.transform);
            transform.GetComponent<CanvasGroup>().blocksRaycasts = true;
        }
    }
}

注意:在Camera模式下使用Transform.parent并不能移动对象的绝对位置,只能将对象移动到指定父物体的位置。您可以在移动前设置变量并在变量改变时进行修改,例如:


public Transform myParent;

public void Update() {
    if(myParent != null) {
        transform.SetParent(myParent);
    }
}

然后在OnDrag中调用Update方法,如下所示:

public void OnDrag(PointerEventData eventData)
{
    myParent = eventData.pointerCurrentRaycast.gameObject.transform;
    mainCamera.gameObject.SetActive(true);
}

最后,在每次拖动前调用myParent的SetActive(true)方法,如下所示:


if(myParent != null) {
    myParent.SetActive(true);
}


我希望这些改进可以帮助您解决问题。

Unity解决UI拖拽偏移问题的方法

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

// UGUI拖动图片,脚本挂在Image上即可
public class SyqTest : MonoBehaviour, IPointerDownHandler,IDragHandler
{
    Vector3 offPos;//存储按下鼠标时的图片-鼠标位置差
    public void OnPointerDown(PointerEventData eventData)
    {
        offPos = transform.position- Input.mousePosition ;
    }

    public void OnDrag(PointerEventData eventData)
    {
        //修改图片为鼠标当前位置并加上位置差
        transform.position = offPos + Input.mousePosition;
    }

}


可能是因为在Camera模式下,UI元素的位置是以世界坐标系来计算的,而不是屏幕坐标系。所以当你将UI元素的位置设置为Input.mousePosition时,它会出现偏移量很大的情况。

解决这个问题的一种方法是将屏幕坐标转换为世界坐标,然后再将UI元素的位置设置为转换后的坐标。你可以使用Camera.main.ScreenToWorldPoint方法来进行坐标转换。

你有做坐标转换的处理吗。camera模式下的坐标系与overly模式下的坐标系是不同的哦。在camera模式下,UI元素的坐标系是相对于相机坐标系的,而在overly模式下,UI元素的坐标系是相对于画布坐标系的。
解决这个问题的方法是,在切换模式时,根据相机坐标系与画布坐标系之间的转换关系,对UI元素的坐标进行相应的调整。通过设置UI元素的anchoredPosition属性来控制UI元素在camera模式下的位置。通过监听UI元素的位置变化事件,并在事件回调函数中计算UI元素在camera模式下的正确位置,然后将anchoredPosition属性设置为此位置即可。

试试使用相机 transform 属性来获取相机变换的信息,然后使用该信息来更新你的UI元素的变换