Unity UGUI图片拖拽与区域限制

3 篇文章 0 订阅

最近有个卡牌装备的问题,实现可以将卡牌在装备框内移动缩放,并且可以将卡牌拖动到其他的装备框进行交换,或者卸下操作。

一、让图片跟随鼠标移动

要让图片随鼠标拖拽移动,首先需要接收IBeginDragHandler, IDragHandler,IEndDragHandler,中的拖拽事件。

一般项目中会有一个EventTrigger,像我当前的项目,有实现类似UGUI源码的UIEventTrigger,统一管理ui的操作。

例如,OnDrag(PointerEventData eventData),OnBeginDrag,OnEndDrag,这三个拖拽事件。

1.我们需要拿到PointerEventData中鼠标点击的屏幕坐标position。

2.通过RectTransformUtility.ScreenPointToWorldPointInRectangle,转换成世界坐标,然后做下一步的操作。

3.OnBeginDrag计算被拖拽图片与拖拽点的offset

public void OnBeginDrag(PointerEventData eventData)
{
        //开始拖拽时获得拖拽点与被拖拽图的偏移
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, eventData.position, uiCamera, out dragOffset);
}

4.OnDrag计算被拖拽的距离

public void OnDrag(PointerEventData eventData)
{
        Vector3 pos;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, eventData.position, uiCamera, out pos);
        rect.position = pos + dragOffset;
        //判断拖拽范围
}

5.OnEndDrag松手检测,满足卸下,交换需求

public void OnEndDrag(PointerEventData eventData)
{
        //拖拽结束后,检查抬起点下的交互物体
        //伪代码 需要被检查的装备框 在范围内为true
        foreach(var rect in rects)
        {
            if (RectTransformUtility.RectangleContainsScreenPoint(rect, eventData.position, uiCamera))
            {
                //处理交互事件
            }
        }
}

二、限制图片可移动范围

拖拽限制参考Unity UI拖拽及拖拽范围限制功能的实现

参考文章判断拖拽范围时利用被拖拽图与父亲的pivot之间的距离计算可以拖拽的移动范围。(红色的为范围,蓝色为被拖拽体)

而本篇文章利用另外一种方法,利用顶点的坐标限制移动范围,刚好可以适应策划的需求,限制ui在范围内,而这个ui比父节点还要大。

其实就是限制被拖拽图的顶点在父节点的外面即可,这时只要限制左上和右下,或者左下和右上即可。

具体方法就是判断顶点的x,y坐标,通过RectTransform.GetWorldCorners(corners),可获得顶点坐标。

public void OnDrag(PointerEventData eventData)
{
        Vector3 pos;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, eventData.position, uiCamera, out pos);
        Vector3 lastPos = rect.position;
        rect.position = pos + dragOffset;
        //判断拖拽范围
        int state = 0;
        if (!CanDrag(out state))
        {
            Vector3 nowPos = rect.position;
            //state=1 只能左右移动
            rect.position = new Vector3(nowPos.x, lastPos.y, nowPos.z);
            //state=2 只能上下移动
            rect.position = new Vector3(lastPos.x, nowPos.y, nowPos.z);
            //state=3 不能移动
            rect.position = lastPos;
        }
}
    bool CanDrag(out int state)
{
        state = 1;
        rect.GetWorldCorners(corners);
        //判断顶点与父顶点之间的关系
        //左上点在父左上点右方或者下方
        //右下点在父右下点左方或者上方
        return true;
}

三、拖拽结束后检测松手位置完成各种需求

这里有多种操作:

卸下(拖动到了空白区域)

交换(拖动到了另外的装备格子)

装备(将未装备的拖动到了格子)

关键接口RectTransformUtility.RectangleContainsScreenPoint,判断抬起坐标是否在格子的范围内

public void OnEndDrag(PointerEventData eventData)
{
        //拖拽结束后,检查抬起点下的交互物体
        //伪代码 需要被检查的装备框 在范围内为true
        foreach(var rect in rects)
        {
            if (RectTransformUtility.RectangleContainsScreenPoint(rect, eventData.position, uiCamera))
            {
                //处理交互事件
            }
        }
}

四、部分代码

public class DragUI : MonoBehaviour
{
    private RectTransform parentRect;
    private RectTransform rect;
    private Camera uiCamera;
    private UIEventTrigger eventTrigger;
    private Vector3 dragOffset;
    private Vector3[] pCorners;
    private Vector3[] corners;
    private void Start()
    {
        rect = GetComponent<RectTransform>(); //rect = 被拖拽的图片对应组件
        //uiCamera = 所对应的ui摄像机
        eventTrigger = GetComponent<UIEventTrigger>();
        eventTrigger.onBeginDrag += OnBeginDrag;
        eventTrigger.onDrag += OnDrag;
        eventTrigger.onEndDrag += OnEndDrag;
        parentRect.GetWorldCorners(pCorners);
    }
    public void OnBeginDrag(PointerEventData eventData)
    {
        //开始拖拽时获得拖拽点与被拖拽图的偏移
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, eventData.position, uiCamera, out dragOffset);
    }
    public void OnDrag(PointerEventData eventData)
    {
        Vector3 pos;
        RectTransformUtility.ScreenPointToWorldPointInRectangle(rect, eventData.position, uiCamera, out pos);
        Vector3 lastPos = rect.position;
        rect.position = pos + dragOffset;
        //判断拖拽范围
        int state = 0;
        if (!CanDrag(out state))
        {
            Vector3 nowPos = rect.position;
            //state=1 只能左右移动
            rect.position = new Vector3(nowPos.x, lastPos.y, nowPos.z);
            //state=2 只能上下移动
            rect.position = new Vector3(lastPos.x, nowPos.y, nowPos.z);
            //state=3 不能移动
            rect.position = lastPos;
        }
    }
    bool CanDrag(out int state)
    {
        state = 1;
        rect.GetWorldCorners(corners);
        //判断顶点与父顶点之间的关系
        //左上点在父左上点右方或者下方
        //右下点在父右下点左方或者上方
        return true;
    }
    public void OnEndDrag(PointerEventData eventData)
    {
        //拖拽结束后,检查抬起点下的交互物体
        //伪代码 需要被检查的装备框 在范围内为true
        foreach(var rect in rects)
        {
            if (RectTransformUtility.RectangleContainsScreenPoint(rect, eventData.position, uiCamera))
            {
                //处理交互事件
            }
        }
    }
}

 

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漫步云巅Kim

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值