You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity拖拽系统GetClosetSlot函数无法识别UI Plane问题求助

拖拽系统UI识别问题排查与解决

问题描述

我正在制作Unity拖拽系统,遇到一个问题:通过GetClosetSlot()函数识别UI Slot时,点击UI Plane外返回Null符合预期,但点击内部仍返回Null。使用Unity 2021.3.23f1 LTS版本,代码基本和教程一致,不知道怎么排查。

相关脚本

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

public class InventoryManager : MonoBehaviour
{
    [SerializeField] private GameObject SlotHandler;
    [SerializeField] private ItemClass itemToAdd;
    [SerializeField] private ItemClass itemToRemove;

    [SerializeField] SlotClass[] startItems;
    SlotClass[] items;

    private GameObject[] Slots;

    private void Start()
    {
        Slots = new GameObject[SlotHandler.transform.childCount];
        items = new SlotClass[Slots.Length];

        for (int i = 0; i < items.Length; i++)
        {
            items[i] = new SlotClass();
        }
        for (int i = 0; i < startItems.Length; i++)
        {
            items[i] = startItems[i];
        }

        for (int i = 0; i < SlotHandler.transform.childCount; i++)
        {
            Slots[i] = SlotHandler.transform.GetChild(i).gameObject;
        }

        refreshUI();

        addItem(itemToAdd);
        removeItem(itemToRemove);
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Debug.Log(GetClosetSlot());
        }
    }

    #region Inventory Utils
    public void refreshUI()
    {
        for (int i = 0; i < Slots.Length; i++)
        {
            try
            {
                Slots[i].transform.GetChild(0).GetComponent<Image>().sprite = items[i].GetItem().itemSprite;
                Slots[i].transform.GetChild(0).GetComponent<Image>().enabled = true;
                Slots[i].transform.GetChild(1).GetComponent<TextMeshProUGUI>().text = items[i]._GetCantidad() + "";
                if (Slots[i].transform.GetChild(1).GetComponent<TextMeshProUGUI>().text == "1")
                {
                    Slots[i].transform.GetChild(1).GetComponent<TextMeshProUGUI>().text = string.Empty;
                }
            }
            catch
            {
                Slots[i].transform.GetChild(0).GetComponent<Image>().sprite = null;
                Slots[i].transform.GetChild(0).GetComponent<Image>().enabled = false;
                Slots[i].transform.GetChild(1).GetComponent<TextMeshProUGUI>().text = string.Empty;
            }
        }
    }
    public bool addItem(ItemClass item)
    {
        SlotClass slot = Contains(item);

        if (slot != null && slot.GetItem()._isStackable)
        {
            slot.MasCantidad(1);
        }
        else
        {
            for (int i = 0; i < items.Length; i++)
            {
                if (items[i].GetItem() == null)
                {
                    items[i].Addition(item, 1);
                    break;
                }
            }
        }

        refreshUI();
        return true;
    }
    public bool removeItem(ItemClass item)
    {
        SlotClass Temp = Contains(item);

        if (Temp != null)
        {
            if (Temp._GetCantidad() > 1)
            {
                Temp.menosCantidad(1);
            }
            else
            {
                int slotToRemoveIndex = 0;

                for (int i = 0; i < items.Length; i++)
                {
                    if (items[i].GetItem() == item)
                    {
                        slotToRemoveIndex = i;
                        break;
                    }
                }
                items[slotToRemoveIndex].clear();
            }

        }
        else
        { 
            return false; 
        }

        refreshUI();
        return true;
    } 
    public SlotClass Contains(ItemClass item)
    {
        for (int i = 0; i < items.Length; i++)
        {
            if (items[i].GetItem() == item)
            {
                return items[i];
            }
        }

        return null;
    }
    #endregion Invetory Utils

    #region Moving Stuff
    private SlotClass GetClosetSlot()
    {
        for (int i = 0; i < Slots.Length; i++)
        {
            if (Vector2.Distance(Slots[i].transform.position, Input.mousePosition) < -10)
                return items[i];
        }

        return null;
    }
    #endregion
}

问题排查与解决

1. 核心错误:距离判断逻辑完全颠倒

GetClosetSlot()中的Vector2.Distance(...) < -10是致命错误——距离值永远是非负数,这个条件永远不会成立,导致函数永远返回Null。

2. 替换为可靠的UI检测方式

改用Unity官方推荐的RectTransformUtility.RectangleContainsScreenPoint方法,直接检测鼠标是否在Slot的Rect范围内,代码修改如下:

private SlotClass GetClosetSlot()
{
    for (int i = 0; i < Slots.Length; i++)
    {
        RectTransform slotRect = Slots[i].GetComponent<RectTransform>();
        if (RectTransformUtility.RectangleContainsScreenPoint(slotRect, Input.mousePosition))
        {
            return items[i];
        }
    }
    return null;
}

这种方式不受UI缩放、锚点设置影响,比距离判断精准得多。

3. 额外验证点

  • 确认每个Slot GameObject上存在RectTransform组件(UI元素默认自带,若手动删除需重新添加)
  • 检查Slot的Image组件是否勾选了Raycast Target(要接收点击检测必须勾选,在Inspector的Image面板中)
  • 确认Slot没有被其他UI元素遮挡(可通过Scene视图的Gizmos查看射线检测区域)

内容的提问来源于stack exchange,提问作者Fox_65

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 12:59:53