Unity中做连线选择题在相机模式下产生偏移

Unity中做连线选择题
在网上找到一个教程,但是我的画布模式是camera,使用的时候会产生偏移,如下图,鼠标和线不在同一指向附代码(鼠标此时指向的是右侧第一个),该怎么调整呢(我猜有可能是我坐标转换的问题,但是不会调),还有重置键,点击之后可以出现连线(现在是线会消失但是不可以重新连),最后点击提交出现新的界面判断对错

img

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

public class line : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler, IEndDragHandler
{
    [Header("线宽度")]
    public float lineWidth = 3f;
    [Header("线颜色")]
    public Color lineColor = Color.white;
    [Header("限制多选")]
    bool isUP = true;
    //连线
    GameObject lineObj = null;
    RectTransform lineObjRT = null;
    Image lineObjImg;
    //初始点
    Vector3 startPos = Vector3.zero;
    Vector3 endPos = Vector3.zero;
    // 最后落脚的物体
    GameObject GetObj;

    public void Decide()
    {
        if (GetObj != null)
        {
            if (GetObj.name == transform.name)
            {
                Debug.Log("回答正确");
                lineObjImg.color = Color.green;
            }
            else
            {
                lineObjImg.color = Color.red;
                Debug.Log("回答错误");
            }
        }
        else
        {
            Debug.Log("回答错误");
            //  DestroyImmediate(lineObjRT.gameObject);
        }
    }
    public void OnDrag(PointerEventData eventData)
    {
        if (isUP)
        {
            endPos = Input.mousePosition;
            Vector3 durationPos = endPos - startPos;
            lineObjRT.sizeDelta = new Vector3(durationPos.magnitude, lineWidth,transform.position.z);
            float angle = Mathf.Atan2(durationPos.y, durationPos.x) * Mathf.Rad2Deg;
            lineObjRT.localRotation = Quaternion.Euler(0, 0, angle);
        }
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (isUP)
        {
            if (eventData.pointerEnter != null)
            {
                print(eventData.pointerEnter.name);
                endPos = eventData.pointerEnter.transform.position;
                Vector3 durationPos = endPos - startPos;
                lineObjRT.sizeDelta = new Vector3(durationPos.magnitude, lineWidth,transform.position.z);
                float angle = Mathf.Atan2(durationPos.y, durationPos.x) * Mathf.Rad2Deg;
                lineObjRT.localRotation = Quaternion.Euler(0, 0, angle);

                isUP = false;
            }
            else
            {

                print("未选中,结果为空");
            }
        }
    }
    public void OnPointerDown(PointerEventData eventData)
    {


        //限制多选
        if (isUP)
        {
            lineObj = new GameObject("LineObj");
            lineObj.SetActive(false);

            lineObjRT = lineObj.AddComponent<RectTransform>();
            lineObjRT.pivot = new Vector2(0, 0.5f);
            lineObjRT.localScale = Vector3.one;

            lineObjImg = lineObj.AddComponent<Image>();
            lineObjImg.color = lineColor;
            lineObjImg.raycastTarget = false;

            lineObjRT.SetParent(transform);

            startPos = transform.position;

            lineObjRT.position = startPos;
            lineObjRT.sizeDelta = Vector2.zero;
            lineObj.SetActive(true);
        };


    }
    public void OnPointerUp(PointerEventData eventData)
    {
        if (isUP)
        {
            if (eventData.pointerEnter != null)
            {
                GetObj = eventData.pointerEnter;



                //添加数据
                Line_chose.dic_add.Add(int.Parse(transform.name), int.Parse(eventData.pointerEnter.name));
                Line_chose.number++;

            }
            if (eventData.pointerEnter == null)
            {
                DestroyImmediate(lineObjRT.gameObject);
            }
        }
        if (eventData.button == PointerEventData.InputButton.Right)
        {
            if (Line_chose.dic_add.ContainsKey(int.Parse(transform.name)))
            {
                //移除数据
                Line_chose.dic_add.Remove(int.Parse(transform.name));
                Line_chose.number--;
            }
            DestoryAll();
            isUP = true;
        }

    }
    //销毁自身所有的线
    public void DestoryAll()
    {
        for (int i = 0; i < transform.childCount; i++)
        {
            Destroy(transform.GetChild(i).gameObject);
        }

    }
}

问题可能出在两个地方:画布模式和重置键。

首先,关于画布模式的偏移问题,你可以尝试调整画布的设置以解决这个问题。在Canvas组件上,将Render Mode(渲染模式)设置为Screen Space - Camera,并将Render Camera(渲染相机)字段设置为你的相机对象。这样,画布将根据相机的视角进行定位,解决偏移问题。

其次,关于重置键不能重新连线的问题,你需要在重置键的点击事件中重置连线的状态。例如,可以在点击重置键时销毁当前的连线对象,同时将线对象设置为null,这样就可以重新连线了。

以下是可能的修改代码示例:

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

public class line : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IDragHandler, IEndDragHandler
{
    [Header("线宽度")]
    public float lineWidth = 3f;
    [Header("线颜色")]
    public Color lineColor = Color.white;
    [Header("限制多选")]
    bool isUP = true;

    //连线
    GameObject lineObj = null;
    RectTransform lineObjRT = null;
    Image lineObjImg;

    //初始点
    Vector3 startPos;

    // 重置键
    public Button resetButton;

    void Start()
    {
        resetButton.onClick.AddListener(ResetLine);
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        startPos = eventData.position;
        lineObj = new GameObject("Line");
        lineObjRT = lineObj.AddComponent<RectTransform>();
        lineObjImg = lineObj.AddComponent<Image>();
        lineObjImg.color = lineColor;
        lineObjRT.pivot = new Vector2(0.5f, 0f);
        lineObjRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, lineWidth);
        lineObjRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, lineWidth);
        lineObj.transform.SetParent(transform);
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (lineObj == null)
            return;
        float angle = Mathf.Atan2(eventData.position.y - startPos.y, eventData.position.x - startPos.x) * Mathf.Rad2Deg;
        lineObjRT.eulerAngles = new Vector3(0, 0, angle);
        float distance = Vector3.Distance(startPos, eventData.position);
        lineObjRT.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, distance);
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (lineObj == null)
            return;
        Destroy(lineObj);
        lineObj = null;
    }

    // 重置连线
    public void ResetLine()
    {
        if (lineObj != null)
        {
            Destroy(lineObj);
            lineObj = null;
        }
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        if (lineObj == null)
            return;
        if (isUP)
        {
            lineObj.transform.SetParent(null);
            lineObj = null;
        }
    }
}

这样,你应该可以解决偏移和重置问题。

首先,偏移的原因可能是坐标系转换的问题,因为鼠标点击的坐标是以屏幕为基准,而连线的终点坐标是在世界坐标系中确定的。因此,在进行坐标系转换时,可能需要对屏幕坐标进行转换,以便与世界坐标系中的坐标匹配。

其次,建议检查以下几点:

  1. 确保画布的位置和大小与相机视图匹配。如果画布和相机的位置或大小不匹配,则可能会导致绘制出现偏移。

  2. 检查是否使用了正确的相机。如果不是,可能会导致坐标转换错误,从而导致偏移。确保使用正确的相机来进行坐标转换。

  3. 检查是否正确设置了画布的缩放比例。如果画布的缩放比例与相机不匹配,则可能会导致绘制出现偏移。

最后,建议在代码中加入调试输出,以帮助定位问题所在。例如,可以输出鼠标点击的屏幕坐标和绘制连线的世界坐标,以便更好地了解偏移的原因,并找出解决方案。

using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System.Collections.Generic;
public class Line : MonoBehaviour, IPointerDownHandler, IDragHandler, IEndDragHandler
{
    public Camera camera;
    public Color lineColor;
    public float lineWidth;
    
    private RectTransform lineObjRT;
    private Image lineObjImg;
    private GameObject lineObj;
    
    private Vector3 startPos;
    private Vector3 endPos;
    
    private void Start()
    {
        lineObj = new GameObject("LineObj");
        lineObjRT = lineObj.AddComponent<RectTransform>();
        lineObjImg = lineObj.AddComponent<Image>();
        lineObjImg.color = lineColor;
        lineObjImg.raycastTarget = false;
        lineObj.transform.SetParent(transform);
        camera = Camera.main;
    }
    
    public void OnPointerDown(PointerEventData eventData)
    {
        startPos = camera.ScreenToWorldPoint(Input.mousePosition);
    }
    
    public void OnDrag(PointerEventData eventData)
    {
        endPos = camera.ScreenToWorldPoint(eventData.position);
        
        Vector3 startPosUI = camera.WorldToScreenPoint(startPos);
        Vector3 endPosUI = camera.WorldToScreenPoint(endPos);
        
        lineObjRT.position = startPosUI;
        lineObjRT.sizeDelta = new Vector2((endPosUI - startPosUI).magnitude, lineWidth);
        
        float angle = Mathf.Atan2(endPosUI.y - startPosUI.y, endPosUI.x - startPosUI.x) * Mathf.Rad2Deg;
        lineObjRT.rotation = Quaternion.Euler(0, 0, angle);
    }
    
    public void OnEndDrag(PointerEventData eventData)
    {
        endPos = camera.ScreenToWorldPoint(eventData.position);
        
        Vector3 startPosUI = camera.WorldToScreenPoint(startPos);
        Vector3 endPosUI = camera.WorldToScreenPoint(endPos);
        
        lineObjRT.position = startPosUI;
        lineObjRT.sizeDelta = new Vector2((endPosUI - startPosUI).magnitude, lineWidth);
        
        float angle = Mathf.Atan2(endPosUI.y - startPosUI.y, endPosUI.x - startPosUI.x) * Mathf.Rad2Deg;
        lineObjRT.rotation = Quaternion.Euler(0, 0, angle);
        
        Destroy(lineObj);
        lineObj = new GameObject("LineObj");
        lineObjRT = lineObj.AddComponent<RectTransform>();
        lineObjImg = lineObj.AddComponent<Image>();
        lineObjImg.color = lineColor;
        lineObjImg.raycastTarget = false;
        lineObj.transform.SetParent(transform);
        
        Line_chose.dic_add[int.Parse(transform.name)] = int.Parse(eventData.pointerEnter.name);
    }
    
    public void DestoryAll()
    {
        Destroy(lineObj);
    }
}

你方便发源项目吗,方便的话我下班可以帮你改一下。

Unity控制相机偏移跟随
可以参考下


百度文库安全验证 https://wenku.baidu.com/view/544d62a27d192279168884868762caaedd33ba80.html?_wkts_=1691566825233&bdQuery=Unity%E4%B8%AD%E5%81%9A%E8%BF%9E%E7%BA%BF%E9%80%89%E6%8B%A9%E9%A2%98%E5%9C%A8%E7%9B%B8%E6%9C%BA%E6%A8%A1%E5%BC%8F%E4%B8%8B%E4%BA%A7%E7%94%9F%E5%81%8F%E7%A7%BB

已经自己解决啦,底下的回答我都看了,可能和我用的画布和相机模式有关都会有问题,我在自己的脚本的基础上做了一些修改,且我发现我自己在计算鼠标在屏幕上的位置的时候带错了相机(我把主相机带进去了,但实际上应该是用UIcam)修改如下:

 public void OnDrag(PointerEventData eventData)
    {
        Debug.Log("点击成功");
        if (isUP)
        {
            endPos = Input.mousePosition;   //鼠标终点
            Vector3 worldEndPos = UICam.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, transform.position.z));
            //Debug.Log("Pose" + worldEndPos);
            Vector3 durationPos = worldEndPos - startPos;
            lineObjRT.sizeDelta = new Vector3(6, lineWidth, transform.position.z);
            float angle = Mathf.Atan2(durationPos.y, durationPos.x) * Mathf.Rad2Deg;
            lineObjRT.rotation = Quaternion.Euler(0, 0, angle);
            //Debug.Log("Euler=" + lineObjRT.localRotation);
        }
    }
有需要的大家可以试试~