系列文章目录
麦田物语第十一天
一、背包物品选择高亮显示和动画
本节想要想要实现的内容是当我们点按格子时会有一个高亮显示的状态,表示被选中的一个状态(将slotHightlight设置为可视状态)。
首先点按的事件我们需要调用事件的接口:IPointerClickHandler(引入命名空间UnityEngine.EventSystems),同时利用编辑器完成所需要的函数OnPointerClick,这个接口我之前没有使用过,不是很懂里面的用法,此时就可以打开Unity代码手册(2019.4及其之前的代码手册都有提及),同时我们可以点击参数类型查看可以有哪些参数,此处我们只是获得点按按钮的事件。
接下来编写OnPointerClick函数,首先如果我们点击的UI的ItemAmount为0,那么就直接返回,如果不为0,那么切换被选择的状态即可。但是不能直接在此处直接执行将Highlight可视的方法,因为我们需要控制每次只有一个格子被选中。
那么我们的解决方法是由于父级物体获得了所有的Slot_UI,那么我们可以通过父级物体使得每次只有一个格子被选中,话不多说,开始实现吧!
在InventoryUI脚本中,我们添加UpdateSLotHightlight方法,并以每一个Slot_UI的Index作为参数,当每一个Slot_UI被点击时,就会调用InventoryUi的这个方法,然后判断只存在一个格子的高亮显示。接着就是编写代码了,我们要循环遍历每一个格子,如果传进来的参数与一个格子的Index相同并且处于被选择的状态,那么我们就将这个Slot_UI的高亮显示出来,反之就关闭这个Slot_UI的高亮同时将其isSelected变量设为false。
InventoryUI的UpdateSLotHightlight方法如下
/// <summary>
/// 更新Slot高亮显示
/// </summary>
/// <param name="index">Slot序号</param>
public void UpdateSlotHightlight(int index)
{
foreach (var slot in playerSlots)
{
if (slot.isSelected && slot.slotIndex == index)
{
slot.slotHighlight.gameObject.SetActive(true);
}
else
{
slot.isSelected = false;
slot.slotHighlight.gameObject.SetActive(false);
}
}
}
SlotUI的部分代码如下
namespace MFarm.Inventory
{
public class SlotUI : MonoBehaviour,IPointerClickHandler
{
[Header("组件获取")]
[SerializeField] private Image slotImage;
[SerializeField] private Text amountText;
[SerializeField] public Image slotHighlight;
[SerializeField] private Button button;
[Header("格子类型")]
public SlotType slotType;
public bool isSelected;
//物品信息
public ItemDetails itemDetails;
public int itemAmount;
public int slotIndex;
public void OnPointerClick(PointerEventData eventData)
{
if (itemAmount == 0) return;
isSelected = !isSelected;
inventoryUI.UpdateSlotHightlight(slotIndex);
}
}
}
最后一步我们要实现高亮的动画效果,这个制作动画的步骤之前已经提及过了,首先我们需要个Slot_UI的Hightlight添加Animator,同时在合适的位置创建Animator Controller,接着点击Animation窗口,创建动画并放在合适的位置,将ui_selected_hightlight的几个序列帧拖入Animation中,同时调整播放时间,最后将Animator Controller添加到Slot_UI的Hightlight的Animator组件上就完成啦!!!
二、创建 DragItem 实现物品拖拽跟随显示
在本小节我们要实现开始拖拽物品功能。
首先我们需要在SlotUI脚本中添加新的接口,IBeginDragHandler,IDragHandler,IEndDragHandler分别表示开始拖拽,拖拽中,以及结束拖拽的方法,接着利用编辑器实现这些接口。
当我们开始拖拽时,我们希望我们拖拽过程中的被拖拽物品可以显示出来,同时在拖拽结束UI消失。这个本来麦扣老师是直接将ui进行拖拽的,但是这次我们想要通过新的方法来实现。
方法如下:
我们在MainCanvas物体下添加Canvas(DrawCanvas),首先更改Canvas的Pixel Prefect参数(由Inherit改成Off,即关闭继承父级的canvas),勾选Override Sorting,同时调整Sort Order为3(父级默认的顺序是0,调整成3之后使得我们可以在父级Canvas之上看到他),最后移除Canvas Scaler(因为有父级的Canvas)。
然后我们在其下方再次创建Image(DrawItemImage),并更改Image的大小20 * 20。在拖拽后我们显示这个Image,同时更改其Image的Source Image,当我们停止拖拽时隐藏这个Image即可。
接下来就是代码编写了,我们需要在InventoryUI脚本中声明DrawItemImage这个变量,而不是在SlotUI脚本中声明这个变量,之后返回Unity对其赋值。
Image的Raycast Target选项如果勾选的话,表示会对鼠标发出的射线进行遮挡,但是我们需要检测射线
所以我们需要取消勾选Slot_Ui和DragItemImage的Raycast Target选项。
其次就是代码的编写:打开SlotUI脚本,
首先编写开始拖拽的代码,先进行是否该Slot_UI是否为空,我们采用itemAmount是否为0来判断,如果不为0,那么取到InventoryUI脚本中的dragItem(被推拽的UI)设置为可见,并将其Image的Source Image更改为该SlotUI的slotImage图片,同时还要将该Image的设置为图片本身的尺寸,最后为了方便角色观察,还要将拖拽的ui进行高亮显示,与之前的代码类似。
public void OnBeginDrag(PointerEventData eventData)
{
if (itemAmount != 0)
{
inventoryUI.dragItem.enabled = true;
inventoryUI.dragItem.sprite = slotImage.sprite;
inventoryUI.dragItem.SetNativeSize();
isSelected = true;
inventoryUI.UpdateSlotHightlight(slotIndex);
}
}
接着编写拖拽中的代码,只需要将鼠标位置赋值给dragItem的UI位置即可。
public void OnDrag(PointerEventData eventData)
{
inventoryUI.dragItem.transform.position = Input.mousePosition;
}
最后就是编写拖拽结束的代码,我们要做的就是将dragItem隐藏,同时想要获取到我们最终结束时鼠标射线所碰到的UI,故采用Debug进行输出。
public void OnEndDrag(PointerEventData eventData)
{
inventoryUI.dragItem.enabled = false;
Debug.Log(eventData.pointerCurrentRaycast.gameObject);
}
我们开始进行测试,当我们拖拽结束后,你就会发现Console窗口的Debug信息为拖拽结束的Slot_UI的名称,那么下一节我们要做的就是通过拖拽结束后射线的位置实现拖拽后数据及UI的更改。