Unity拖动背包物品/技能图标位置互换

40 篇文章 8 订阅

Chinar blog www.chinar.xin

游戏拖动物品/图标位置互换


本文提供全流程,中文翻译。

Chinar 的初衷是将一种简单的生活方式带给世人

使有限时间 具备无限可能

Chinar —— 心分享、心创新!

助力快速用 UGUI 完成图标互换,数据互换

为初学者节省宝贵的时间,避免采坑!

Chinar 教程效果:
在这里插入图片描述



全文高清图片,点击即可放大观看 (很多人竟然不知道)


1

Intro —— 简介

我们游戏中非常常见的一个功能:拖动技能图标,互换技能位置和背包中拖动游戏物品到道具栏,互换位置等等…

Chinar 今天带大家通过 UGUI最简单的方式实现该需求

我提供了2个场景,2种实现方法,请自行选择

为了美观,我加上了Dotween的一个动画

删掉动画代码,整体实现代码不超过50行即可实现

举个例子
在这里插入图片描述


2

Event Tigger —— 事件触发器组件

UI怎么搭建设计我就不说了,基本都是格子里放物品,实在不懂就看下图

(贴心的 Chinar 也准备了 Demo 供您参考)

直接看下图标记,我们让物品自己管理自己

设置tag —— 格子=Grid;物品=Good;

用tag便于我们管理与扩展,可自行定义多种标签,执行不同操作

挂上代码,手动添加监听函数,运行即可看到效果

举个例子
在这里插入图片描述

代码

using System;
using DG.Tweening;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;


public class ChinarDragImage : MonoBehaviour
{
    private Transform beginParentTransform; //记录开始拖动时的父级对象        
    /// <summary>
    /// UI界面的顶层,这里我用的是 Canvas
    /// (这个变量在开发中设置到单例中较好,不然每一个物品都会初始化查找
    /// GameObject.Find("Canvas").transform;)
    /// </summary>
    private Transform topOfUiT;


    void Start()
    {
        topOfUiT = GameObject.Find("Canvas").transform;
    }


    /// <summary>
    /// 开始拖动时
    /// </summary>
    public void Begin(BaseEventData data)
    {
        if (transform.parent == topOfUiT) return;
        beginParentTransform = transform.parent;
        transform.SetParent(topOfUiT);
    }


    /// <summary>
    /// 拖动中
    /// </summary>
    /// <param name="_">UI事件数据</param>
    public void OnDrag(BaseEventData _)
    {
        transform.position = Input.mousePosition;
        if (transform.GetComponent<Image>().raycastTarget) transform.GetComponent<Image>().raycastTarget = false;
    }


    /// <summary>
    /// 结束时
    /// </summary>
    public void End(BaseEventData data)
    {
        PointerEventData _ = data as PointerEventData;
        if (_ == null) return;
        GameObject go = _.pointerCurrentRaycast.gameObject;
        if (go.tag == "Grid") //如果当前拖动物体下是:格子 -(没有物品)时
        {
            SetPosAndParent(transform, go.transform);
            transform.GetComponent<Image>().raycastTarget = true;
        }
        else if (go.tag == "Good") //如果是物品
        {
            SetPosAndParent(transform, go.transform.parent);                              //将当前拖动物品设置到目标位置
            go.transform.SetParent(topOfUiT);                                             //目标物品设置到 UI 顶层
            if (Math.Abs(go.transform.position.x - beginParentTransform.position.x) <= 0) //以下 执行置换动画,完成位置互换 (关于数据的交换,根据自己的工程情况,在下边实现)
            {
                go.transform.DOMoveY(beginParentTransform.position.y, 0.3f).OnComplete(() =>
                {
                    go.transform.SetParent(beginParentTransform);
                    transform.GetComponent<Image>().raycastTarget = true;
                }).SetEase(Ease.InOutQuint);
            }
            else
            {
                go.transform.DOMoveX(beginParentTransform.position.x, 0.2f).OnComplete(() =>
                {
                    go.transform.DOMoveY(beginParentTransform.position.y, 0.3f).OnComplete(() =>
                    {
                        go.transform.SetParent(beginParentTransform);
                        transform.GetComponent<Image>().raycastTarget = true;
                    }).SetEase(Ease.InOutQuint);
                });
            }
        }
        else //其他任何情况,物体回归原始位置
        {
            SetPosAndParent(transform, beginParentTransform);
            transform.GetComponent<Image>().raycastTarget = true;
        }
    }


    /// <summary>
    /// 设置父物体,UI位置归正
    /// </summary>
    /// <param name="t">对象Transform</param>
    /// <param name="parent">要设置到的父级</param>
    private void SetPosAndParent(Transform t, Transform parent)
    {
        t.SetParent(parent);
        t.position = parent.position;
    }
}

3

Implementing interface —— 实现接口

第二种做法,我预留了很高的扩展性,直接继承自 Button,为扩展留足了接口

拖动效果,我们通过三个 接口来实现
IBeginDragHandler
IDragHandler
IEndDragHandler

其实是上边2中的事件,只是通过继承接口的方式代码来实现

设置tag —— 格子=Grid;物品=Good;

举个例子

代码几乎与2是一样的。只是无需绑定,挂到物品上即可使用

// ========================================================
// 描述:Demo 02 —— 通过继承 + 接口实现 图片拖动替换位置。
// 作者:Chinar 
// 创建时间:2019-04-29 16:39:11
// 版 本:1.0
// ========================================================
using DG.Tweening;
using System;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;



namespace QmDreamer.UI
{
    /// <summary>
    /// 管理UI元素排序:使UI可通过拖动进行位置互换
    /// </summary>
    public class ChinarDragSwapImage : Button, IDragHandler, IBeginDragHandler, IEndDragHandler
    {
        private Transform beginParentTransform; //记录开始拖动时的父级对象        
        /// <summary>
        /// UI界面的顶层,这里我用的是 Canvas
        /// (这个变量在开发中设置到单例中较好,不然每一个物品都会初始化查找
        /// GameObject.Find("Canvas").transform;)
        /// </summary>
        private Transform topOfUiT;


        protected override void Start()
        {
            base.Start();
            topOfUiT = GameObject.Find("Canvas").transform;
        }


        public void OnBeginDrag(PointerEventData _)
        {
            if (transform.parent == topOfUiT) return;
            beginParentTransform = transform.parent;
            transform.SetParent(topOfUiT);
        }


        public void OnDrag(PointerEventData _)
        {
            transform.position = Input.mousePosition;
            if (transform.GetComponent<Image>().raycastTarget) transform.GetComponent<Image>().raycastTarget = false;
        }


        public void OnEndDrag(PointerEventData _)
        {
            GameObject go = _.pointerCurrentRaycast.gameObject;
            if (go.tag == "Grid") //如果当前拖动物体下是:格子 -(没有物品)时
            {
                SetPosAndParent(transform, go.transform);
                transform.GetComponent<Image>().raycastTarget = true;
            }
            else if (go.tag == "Good") //如果是物品
            {
                SetPosAndParent(transform, go.transform.parent);                              //将当前拖动物品设置到目标位置
                go.transform.SetParent(topOfUiT);                                             //目标物品设置到 UI 顶层
                if (Math.Abs(go.transform.position.x - beginParentTransform.position.x) <= 0) //以下 执行置换动画,完成位置互换 (关于数据的交换,根据自己的工程情况,在下边实现)
                {
                    go.transform.DOMoveY(beginParentTransform.position.y, 0.3f).OnComplete(() =>
                    {
                        go.transform.SetParent(beginParentTransform);
                        transform.GetComponent<Image>().raycastTarget = true;
                    }).SetEase(Ease.InOutQuint);
                }
                else
                {
                    go.transform.DOMoveX(beginParentTransform.position.x, 0.2f).OnComplete(() =>
                    {
                        go.transform.DOMoveY(beginParentTransform.position.y, 0.3f).OnComplete(() =>
                        {
                            go.transform.SetParent(beginParentTransform);
                            transform.GetComponent<Image>().raycastTarget = true;
                        }).SetEase(Ease.InOutQuint);
                    });
                }
            }
            else //其他任何情况,物体回归原始位置
            {
                SetPosAndParent(transform, beginParentTransform);
                transform.GetComponent<Image>().raycastTarget = true;
            }
        }


        /// <summary>
        /// 设置父物体,UI位置归正
        /// </summary>
        /// <param name="t">对象Transform</param>
        /// <param name="parent">要设置到的父级</param>
        private void SetPosAndParent(Transform t, Transform parent)
        {
            t.SetParent(parent);
            t.position = parent.position;
        }
    }
}

4

Project —— 项目文件


Unity 版本:2018.3.12

项目文件为 unitypackage 文件包:

下载导入 Unity 即可使用

提取码:9449

举个例子


支持

May Be —— 开发者,总有一天要做的事!


拥有自己的服务器,无需再找攻略

Chinar 提供一站式《零》基础教程

使有限时间 具备无限可能!

先点击领取 —— 阿里全产品优惠券 (享受最低优惠)


Chinar 免费服务器、建站教程全攻略!( Chinar Blog )


Chinar

END

本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究

对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com

对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址

  • 19
    点赞
  • 75
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值