物品拖拽[u3d_rpg游戏开发之物品管理(五)]

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u3d_20171030/article/details/78868159
之前在网上找了好多方法,总是不适合自己,要么就是不能用之类的,我用的是2017的版本,在这里"全面"解析一下.首先创建一个脚本InventoryItem挂在需要拖拽的Image上,这里的Image是另一个Image的子物体,因为子的Imget我用来显示物品的相应物品的图片,而父的Image我用来显示格子的图片,这样就有了格子里面的物品,可以用来拖动,而且,格子的标签我设为"InventoryItemGird",拖拽结束时就可以通过标签判断是不是格子.

1. 继承接口

u3d的ugui有相应的接口来方便我们实现拖拽功能,除了本来就需要继承的MonoBehaviour外,我们写的脚本再继承三个接口,还得先导入头文件 UnityEngine.EventSystems;

using UnityEngine.EventSystems;
public class InventoryItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
}

2. 实现抽象方法

抽象方法同样是三个

using UnityEngine.EventSystems;
public class InventoryItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    /// <summary>
    /// 实现接口的OnBeginDrag方法,处理开始拖拽时要做的事情
    /// </summary>
    /// <param name="eventData"></param>
    public void OnBeginDrag(PointerEventData eventData)
    {

    }
    /// <summary>
    /// 实现接口的OnDrag方法,处理拖动中要做的事情
    /// </summary>
    /// <param name="eventData"></param>
    public void OnDrag(PointerEventData eventData)
    {

    }
    /// <summary>
    /// 实现接口的OnEndDrag方法,处理结束时的方法
    /// </summary>
    /// <param name="eventData"></param>
    public void OnEndDrag(PointerEventData eventData)
    {

    }
}

3. 去遮挡

拖拽的时候我们会遇到一个问题,就是拖拽物品的父物体是是一个格子,而格子又位于不同的层,如图:

项目来源于siki的黑暗之光

我把格子取名为Inventory-Item-gird-00至Inventory-Item-gird-34共20个格子,这里的第一个格子Inventory-Item-gird-00在其他格子的后面,ui物体越靠下就越显示在摄像机的越靠外层,所以,当Inventory-Item-gird-00下的物品拖拽到Inventory-Item-gird-34格子的位置时,会被其遮挡
我们这里就在最下面再创建一个隐形而不能用画布:Canvas,当我们需要拖动物品时就将该物品的父物体设置为Canvas,拖拽物品就会位于最外层,不会被任何ui遮挡,需要注意的是,当拖拽结束我们需要将父物体设置回来,不然会导致原来格子下的Image没了.
    private Transform imageParent;//拖拽物品的父物体
    private Canvas imageFather;//获取最外层的画布
    private Vector2 drugingRectTransform;//正在被拖拽的图片的原始位置
    public void OnBeginDrag(PointerEventData eventData)
    {
        imageFather = GameObject.Find("Canvas").GetComponent<Canvas>();//获取在最外层的格子
        drugingRectTransform = myImage.rectTransform.position;//获取初始位置
        imageParent = transform.parent;//获取父物体的transform
        transform.SetParent(imageFather.transform);//将物品放在最外层
    }
    /// <summary>
    /// 将一个物体放在另一个物体下
    /// </summary>
    /// <param name="child">作为子物体</param>
    /// <param name="parent">作为父物体</param>
    private void SetParentAndPosition(Transform child, Transform parent)//将child放到parent下作为子物体
    {
        child.SetParent(parent);
        child.position = parent.position;
    }

4. 实现穿透

当我们拖拽结束的时候,我们需要判断鼠标停留的位置是否是一个格子,如果是格子才有可能吧物品放进去,如果不是就要让物品还原位置.那么问题来了,拖拽物品始终在鼠标位置,也就是说判断鼠标停留位置的时候,射线判断到的永远是我们正在拖拽的物品.所以我们我让我们在拖拽中的物品不被鼠标射线检测到,也就是使物品实现穿透.
这个时候我们的物品位于Canvas下,所以我们只需要让Canvas实现穿透就行了,先给其添加一个组件:Canvas Group

CanvasGroup组件

这个组件下的Blocks Raycasts选项就表示所在物体是否会遮挡鼠标射线,这时我们就可以通过代码来控制其开关了.
    /// <summary>
    /// 实现接口的OnBeginDrag方法,处理开始拖拽时要做的事情
    /// </summary>
    /// <param name="eventData"></param>
    public void OnBeginDrag(PointerEventData eventData)
    {
        imageFather = GameObject.Find("Canvas").GetComponent<Canvas>();//获取在最外层的画布
        drugingRectTransform = myImage.rectTransform.position;//获取初始位置
        imageParent = transform.parent;//获取父物体的transform
        transform.SetParent(imageFather.transform);//将物品放在最外层
        GameObject.Find("Canvas").GetComponent<CanvasGroup>().blocksRaycasts = false;//射线可以穿透物体
    }
至此开始拖拽物品的方法完全实现

5. 物品置入

物品置入前还有一个拖拽方法需要实现:
    /// <summary>
    /// 实现接口的OnDrag方法,处理拖动中要做的事情
    /// </summary>
    /// <param name="eventData"></param>
    public void OnDrag(PointerEventData eventData)
    {
        this.GetComponent<RectTransform>().position=Input.mousePosition;//鼠标左键按住拖拽的时候,物体跟着鼠标移动
    }
最后就是拖拽结束的方法了.最后一个交换物品的方法可以不用管,我写给自己看的,所有的思路已经很清晰了.
    /// <summary>
    /// 实现接口的OnEndDrag方法,处理结束时的方法
    /// </summary>
    /// <param name="eventData"></param>
    public void OnEndDrag(PointerEventData eventData)
    {
        SetParentAndPosition(transform, imageParent);//复原父物体
        transform.position = drugingRectTransform;//原图归位
        ExchangeOfGoods(eventData);//交换物品
        GameObject.Find("Canvas").GetComponent<CanvasGroup>().blocksRaycasts = false;//ui事件穿透:置为不能穿透
    }
    /// <summary>
    /// 格子内的物品进行交换
    /// </summary>
    /// <param name="eventData">参数PointerEventData用于获取鼠标终点位置</param>
    private void ExchangeOfGoods(PointerEventData eventData)
    {
        GameObject go = eventData.pointerCurrentRaycast.gameObject;//获取鼠标下的物体
        //如果物体不为空且该物体为物品格子
        if (go != null && go.tag.Equals("InventoryItemGird"))
        {
            InventoryItemGrid fatherOfThis = this.GetComponentInParent<InventoryItemGrid>();//获取起点格子的脚本
            InventoryItemGrid fatherOfThat = go.GetComponent<InventoryItemGrid>();//获取终点格子的脚本
            //如果格子为空格子
            if (fatherOfThat.id == 0)
            {
                fatherOfThat.SetId(fatherOfThis.id,fatherOfThis.num);//向终点格子储存物品
                fatherOfThis.ClearInfo();//清空原来格子信息
            }
            else//两格子交换物品
            {
                InventoryItemGrid temp = fatherOfThat;//临时储存终点格子的脚本
                fatherOfThat.SetId(fatherOfThis.id, fatherOfThis.num);//向终点格子储存物品
                fatherOfThis.SetId(temp.id, temp.num);//向起点格子储存物品
            }
        }
    }

猜你喜欢

转载自blog.csdn.net/u3d_20171030/article/details/78868159
今日推荐