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 )
本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究
对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: ichinar@icloud.com
对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址