UGUI 背包-物品信息显示和拖拽功能的实现

物品信息显示和拖拽功能的实现

数据类都做好以后信息我们开始实现当我们的鼠标停放在物品上信息其信息的功能。(也就是提示框)

  • 由于引入到格子的数据字典类。
      更改脚本:
Paste_Image.png
  • 首先我们先进行提示框UI设计的实现。创建一个Image并其添加Text作为文字的显示。设置Image的color的Alpha通道使其透明。
Paste_Image.png
  • 我们应该使提示框根据需要显示文字的多少相应的生成多大,这里我们需要使用一些小技巧。我们设置好Anchors以后,复制一份Text,并将其拖拽出来将Image和Text作为其子物体。(这样当Text(1)大小改变时它的子物体都会跟着它动态的改变,但是Text(1)和Text的文字显示的不一样会造成缺陷,所以我们在显示信息时需要将Text(1)显示的文字同Text一样)
Paste_Image.png
  • 为了实现根据文字的多少自适应大小,我们为这个Text(1)添加ContentSizeFilter内容大小的过滤器组件。并将水平和垂直的Fit都设置为Preferred Size(与文字相对应)
Paste_Image.png
  • 根据文字的多少对应的显示。为了使它显示在鼠标的右下方,我们将其的Pivot轴中心设置在左上方。
Paste_Image.png
  • 为它添加TooltipsUI脚本进行管理其隐藏和显示,以及文本赋值功能。
Paste_Image.png
  • 获取两个Text中的文本显示


    Paste_Image.png
  • 由于获取格子中物品的信息是在每个格子中获取的,所以我们为我们的Grid的预设添加一个GridUI进行控制,为了实现当鼠标进入和移走时,这里我们让GridUI实现IPointerEnterHandler和IPointerExitHandler两个接口的OnPointerEnter和OnPointerExit方法。使在格子上能对鼠标的进入和移走进行检测。

  • 为了进一步的实现,我们这里定义两个委托来对应相应事件的触发。


    Paste_Image.png
Paste_Image.png
  • 在Manager脚本中定义两个回调方法与委托相对应并注册。
Paste_Image.png
  • 定义一个用于控制显示和隐藏的标志位isShow来控制。
Paste_Image.png
  • 由于显示是杂乱无章的为了UI的美感,我们为我们的提示框信息的显示进行样式设计。定义一个方法用于Tooltip中的文字应该如何显示。(不同类型的物品有不同的属性)所以我们的需要用switch判断物品的类型是什么。
Paste_Image.png
  • 通过之前已经做好的ItemModel数据类,来根据对应的格子取出对应的物品Item对象,并在两个回调方法中实现。
Paste_Image.png
Paste_Image.png
  • 重点开始,那我们应该如何使其显示的位置与我们的鼠标相应了,这时就涉及到了坐标系之间的相互转换。(这时我们需要从屏幕坐标到UGUI坐标的转化。)

  • 在Update中每帧检测位置。并进行屏幕坐标到UI坐标的转换。使用Unity工具类中的RectTransformUtility.ScreenPointToLocalPointInRectangle方法。

Paste_Image.png
  • 通过API我们可以知道,它有四个参数:
    • 第一个为RectTransform:我们每一个UGUI对象都具有这个组件,是它们在Canvas中的位置。这时我们需要得到的是在我们UI中的坐标,所以第一个参数自然就是Canvas的RectTransform。

    • 第二个参数为screenPoint屏幕上的坐标,这时也就是我们的Input.MousePosition.

    • 第三个参数为摄像机,由于我们的Canvas的Render Mode为Overlay是没有UI摄像机直接渲染在场景摄像机的最上方,所以这里也就是null。

    • 第四个参数:out Vecter2 position,也就是通过这个方法得到的输出参数。

Paste_Image.png

知道了方法的原理,现在开始转换。

Paste_Image.png
  • 为ToolTipsUI类提供一个SetLocalPosition方法,用于更新位置。
Paste_Image.png
  • 在Manager脚本中的Update中实现。
Paste_Image.png
  • 实现:
Paste_Image.png

拖拽功能的实现。

UGUI中的拖拽功能与NGUI中的不同,NGUI中的拖拽使用Drag脚本组件即可,而UGUI中需要实现IBeginDragHandler等句柄接口来进行实现。

知道了怎么可以实现拖拽,我们只需要分析拖拽的核心点就可以了,无非就是四种情况

  • 拖拽到没有物品的格子中,将原有的格子中的物品删除,在新到达的格子中实例化这个Item。
  • 拖拽到有物品的格子中(交换),将原有格子中的物品和当前到达格子的物品都删除,重新实例化这两个Item对象,在实例化的时候交换他们的父对象。(这里可以使用对象池提高性能
  • 拖拽到格子以外的地方但是还在背包的Panel中,视为拖拽失误回到原来的格子。
  • 拖拽到格子以外的地方但是在背包的Panel之外,视为需要丢弃物品,直接删除物品对象即可。
将我们的ItemUI预设拖拽出,更名为DragItem,并为它添加一个全新的DragItemUI脚本进行控制,由于我们DragItem具有之前所有的ItemUI的功能,我们让其继承于ItemUI。并实现同TooltipUI脚本相同的功能。
Paste_Image.png
  • 赋值。


    Paste_Image.png
  • 由于拖拽也是对Grid中的子物体进行操作,所以我们在GridUI中使其实现IBeginDragHandler,IDragHandler,IEndDragHandler三个接口分别对应拖拽开始时,拖拽中,拖拽结束时所需要触发的事件。
Paste_Image.png
  • 同Tooltips一样。我们也为它定义两个相应的事件委托:
    • OnLeftBeginDrag为当鼠标左键开始拖拽的事件,Transform参数代表拖拽出物品的格子的transform。
    • OnLeftEndDrag当鼠标左键结束拖拽的事件,第一个参数代表拖拽出物品的格子的transform,第二个Transform参数代表当前鼠标停留的格子的transform
Paste_Image.png
  • 使用接口中的参数PointerEventData eventData,eventData.button来获取按下的键是什么,这里为鼠标左键。
Paste_Image.png
Paste_Image.png
  • 在KnapsackManager中注册相应的事件。
Paste_Image.png

分析拖拽事件的核心实现点:

由于拖拽事件,就是控制这个DragItem的显示和隐藏,并不是真正的在UI场景通过鼠标改变格子中的Item的位置。当我们没有拖拽时这个DragItem就隐藏,开始拖拽时这个Item就显示。(拖拽时原来格子中的物品已经被删除了,我们只是在做不停的删除和实例化操作而已

  • 所以我们需要获取这个DragItem的引用,以及是否开始拖拽的标志位,并在Unity的Inspector面板中进行赋值。


    Paste_Image.png
  • 由于我们拖拽的优先级是高于提示框的显示的,我们在拖拽的时候是不应该显示提示框的,所以我们改变层次结构。

Paste_Image.png
  • 接着进行新注册号的两个Drag的回调方法的实现。
    • GridUI_OnLeftBeginDrag开始拖拽方法:我们在考虑开始拖拽时,我们应该先判断我们当前拖拽的这个格子中是否有物品没有就返回,有的话,就通过ItemModel类拿到它的信息,并使DragItem的样式与之对应。最后按照之后设计好的思想将它删除。
Paste_Image.png
  • GridUI_OnLeftEndDrag:这个回调方法是重中之重,我们之前也理清了思路,当拖拽结束时无非也就是四种情况,所以根据这四种情况去实现即可。
Paste_Image.png
  • 四种情况的if else架构:
Paste_Image.png
  • 第一种情况:由于之前在Drag开始的时候对象已经删除了但是数据字典中的Item对象仍然存在所以需要在实例化新的之前的这个对象以后把原来的数据删除即可。
Paste_Image.png
  • 第一种情况:由于之前在Drag开始的时候对象已经删除了但是数据字典中的Item对象仍然存在,并且拖拽开始时也没有对拖拽结束到达的格子的物品进行删除,所以我们要先将两个物品删除,并将它们原来的信息得到后删除原来在ItemModel中的数据。并重新实例化两个对象,在实例化的时候交换它们的位置即可。
Paste_Image.png
  • 第三种情况:由于之前在Drag开始的时候对象已经删除了但是数据字典中的Item对象仍然存在,这时对游戏对象进行还原操作即可。
Paste_Image.png
  • 第四种情况:由于之前在Drag开始的时候对象已经删除了,这个删除数据字典中的值即可。
Paste_Image.png
  • 最终演示:
Drag.gif

推荐阅读更多精彩内容