(感觉Csdn代码页面可以再大一点或者加个放大功能 不然得划着看不太舒服)
1.关键接口,三个拖拽相关的
2.关键参数,PointerEventData
一直没仔细看过,其实有包含鼠标相关的很多参数,鼠标点击次数,判断是否拖动等等。这里是使用了pointerCurrentRaycast,也就是当前触碰到的物体的信息,注意是当前,也就是只有一个,所以当我们想要拖动一个道具放到格子中的时候,一定会先触碰到当前道具,所以还需要CanvasGroup组件,当道具开始挪动的时候,将blocksRaycasts设为false,也就是当前道具不能被射线检测,这样就可以检测到道具后面的槽位了
3.关于道具拖动,有两种实现方式
第一种 transform.postion = event.position
第二种 rectTransform.anchoredPosition += eventData.delta;
eventData.delta:鼠标在一帧内的移动距离
这样做会使UI元素在每一帧都根据鼠标的移动更新自己的位置,从而实现了拖拽的效果。
4.基本概念要搞清楚
rectTransform.anchoredPosition:表示Rect Transform的中心点相对于锚点的位置。
event.position:是基于屏幕坐标的,代表了当前鼠标在屏幕上的位置
transform.position它是世界坐标嘛对吧,为什么可以直接使用呢?
其实最稳妥的做法是将event.position通过Camera.ScreenToWorldPoint转换为世界坐标,再给transform.position赋值,在这里没有出错是因为,Canvas 设置为 Screen Space - Overlay 模式时,Canvas的内容会像UI元素一样,直接显示在屏幕的最上层,不受场景中摄像机视角的影响,也就是所有的子元素都是相对于屏幕坐标系的,而不是相对于世界坐标系的。因此,在这种情况下,eventData.position 提供的屏幕坐标可以直接应用于这些 UI 元素的 Transform 组件。
public class UIBagItem : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
{
private Vector3 startVec;
public Image img;
public Text level;
private ItemInfo info;
public Transform itemTrans;
public Transform pastParent;
private RectTransform rectTransform;
void Awake()
{
rectTransform = GetComponent<RectTransform>();
}
public void Init(int id, int level, Transform parent)
{
this.info = DataManager.Instance.itemInfo[id - 1];
this.img.sprite = Resources.Load<Sprite>(Config.bagPath + info.name);
this.level.text = level.ToString();
this.transform.parent = pastParent = parent;
this.rectTransform.anchoredPosition = Vector2.zero;
this.itemTrans = GameObject.Find("ItemTransform").transform;
}
public void OnBeginDrag(PointerEventData eventData)
{
//鼠标点击的点 pointerEventData
this.transform.SetParent(itemTrans);
this.transform.position = eventData.position;
this.GetComponent<CanvasGroup>().blocksRaycasts = false;
}
public void OnDrag(PointerEventData eventData)
{
//eventData.delta 鼠标拖拽的位移量
rectTransform.anchoredPosition += eventData.delta;
Debug.Log(eventData.pointerCurrentRaycast.gameObject.name);
}
public void OnEndDrag(PointerEventData eventData)
{
this.GetComponent<CanvasGroup>().blocksRaycasts = true;
GameObject target = eventData.pointerCurrentRaycast.gameObject;
ItemInfo targetInfo;
//判断是否是道具
if (target.name == "UIBagItem(Clone)")
{
targetInfo = target.GetComponent<UIBagItem>().info;
//再判断是否可以合成
if(this.info.id == targetInfo.id)
{
//可以合成就保存数据
DataManager.Instance.UpdateBagInfo(targetInfo.consumeId, targetInfo.composeId);
//更新UI 将目标位置的UI更新为合成后的UI
target.GetComponent<UIBagItem>().Init(targetInfo.composeId, DataManager.Instance.itemInfo[targetInfo.composeId - 1].level,target.transform.parent);
Destroy(this.gameObject);
}
//不能合成就交换位置
else
{
//本物体父节点
this.transform.SetParent(target.transform.parent);
//目标物体的父节点 = 本物体记录的父节点
target.transform.SetParent(this.pastParent);
//理解为A=B B=C C=A就好了 这里记录一下
Transform tempParent = this.pastParent;
//这里更新本物体记录的父节点
this.pastParent = target.GetComponent<UIBagItem>().pastParent;
//目标物体记录的父节点
target.GetComponent<UIBagItem>().pastParent = tempParent;
//相对于父物体的位置为0所以这样写
this.rectTransform.anchoredPosition = Vector2.zero;
//相对于父物体的位置为0所以这样写
target.GetComponent<UIBagItem>().rectTransform.anchoredPosition = Vector2.zero;
//不为0的话就把偏移值赋值上去
}
}
//为什么这里判断标签 是因为格子都是复制出来的 名字后面会有个数
else if (target.tag == "BagSlot")
{
this.transform.SetParent(target.gameObject.transform);
this.rectTransform.anchoredPosition = Vector2.zero;
}
//其他区域 直接归原位
else
{
this.transform.SetParent(this.pastParent);
}
}
}