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
相关产品推荐
相关产品推荐

