Unity — — UGUI之背包物品拖放
最新背包代码:
Unity3D — — UGUI之简易背包
Unity版本:2017.3
功能:用UGUI实现简单的背包物品拖放/交换功能
一、简介
在UGUI下,物品的拖放脚本实现主要依赖于UnityEngine.EventSystems下的三个接口 IBeginDragHandler, IDragHandler, IEndDragHandler; 其次还有IPointerEnterHandler,IPointerExitHandler
等接口来实现鼠标移入移出等操作的监控,同时引用这些接口后,对应的方法也是必须要实现的
简单介绍下这几个方法:
官方API解释:PointerEventData - - Event payload associated with pointer (mouse / touch) events.
Drag类:
OnBeginDrag(PointerEventData eventData) :当点击物体后开始执行此方法
OnDrag(PointerEventData eventData) :在拖拽中过程中执行
OnEndDrag(PointerEventData eventData) :拖拽结束时执行(松开鼠标的那下)
Pointer类:
OnPointerEnter(PointerEventData eventData) :当鼠标进入时执行
其余的类似OnPointerExit方法基本类似
Drop类:(待研究)
IDropHandler下的OnDrop(PointerEventData eventData)
这个方法笔者没有过多研究,由于拖放物品结束后的功能(交换/摧毁等)由EndDrag方法实现了,未发现OnDrop的具体用法
二、功能实现
注:由于未导入具体的物品信息,因此目前只是实现简单的GameObject间的拖放关系
(1)背包内物体的拖放,并在结束后指定到相应的格子下
(2)当物品未在格子内或者超出背包范围时,归位到原本的位置
(3)两个物体间互相交换
大致样子如下:
代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEngine.EventSystems;
using UnityEngine.UI; public class InventoryItem : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler,IPointerEnterHandler
{
private Transform originalSlot;
private GameObject parent;
private GameObject item;
private float x_item;
private float y_item;
private Vector2 itemSize;
private bool isDragging = false; //默认设为false,否则OnPointerEnter每帧都会调用,会有bug /// <summary>
/// 添加CanvasGroup组件,在物品拖动时blocksRaycasts设置为false;
/// 让鼠标的Pointer射线穿过Item物体检测到UI下层的物体信息
/// </summary>
private CanvasGroup itemCanvasGroup; public string objectTag=null; private void Start()
{
itemCanvasGroup = this.GetComponent<CanvasGroup>();
item = this.transform.gameObject; x_item = item.GetComponent<Image>().GetPixelAdjustedRect().width; //Image的初始长宽
y_item = item.GetComponent<Image>().GetPixelAdjustedRect().height;
parent = GameObject.FindGameObjectWithTag("SlotGrid");
} public void OnPointerEnter(PointerEventData eventData)
{
//当鼠标在最外层时(移出背包,Canvas外)
//让物品回到原位
if(eventData.pointerCurrentRaycast.depth== && isDragging==true)
{
SetOriginalPos(this.gameObject);
return;
} //Debug.Log(eventData.pointerCurrentRaycast.depth);
objectTag = eventData.pointerCurrentRaycast.gameObject.tag;
Debug.Log("Raycast = "+objectTag); if(objectTag!=null && isDragging==true)
{ if (objectTag == Tags.InventorySlot) //如果是空格子,则放置Item
{
SetCurrentSlot(eventData);
}
else if (objectTag == Tags.InventoryItem) //交换物品
{
SwapItem(eventData);
}
else //如果都不是则返回原位
{
SetOriginalPos(this.gameObject);
}
}
} //把Item回归到原来位置
public void SetOriginalPos(GameObject gameobject)
{ gameobject.transform.SetParent(originalSlot);
gameobject.GetComponent<RectTransform>().anchoredPosition = originalSlot.GetComponent<RectTransform>().anchoredPosition;
itemCanvasGroup.blocksRaycasts = true;
} //交换两个物体
//由于拖放中,正被拖放的物体没有Block RayCast
//具体思路:
//1.记录当前射线照射到的物体(Item2)
//2.获取Item2的parent的位置信息,并把item1放过去
//3.把Item2放到Item1所在的位置
public void SwapItem(PointerEventData eventData)
{
GameObject targetItem = eventData.pointerCurrentRaycast.gameObject; //下面这两个方法不可颠倒,否则执行顺序不一样会出bug
//BUG:先把Item2放到了Item1的位置,此时Item1得到的位置信息是传递后的Item2的(原本Item1的位置)
//因此会把Item1也放到Item2下,变成都在原本Item1的Slot内
SetCurrentSlot(eventData);
SetOriginalPos(targetItem);
} //设置Item到当前鼠标所在的Slot
public void SetCurrentSlot(PointerEventData eventData)
{
//如果Slot为空
if (eventData.pointerCurrentRaycast.gameObject.tag==Tags.InventorySlot)
{
Transform currentSlot= eventData.pointerCurrentRaycast.gameObject.transform;
this.transform.SetParent(currentSlot);
//如果只是transform position,图片会默认在左上角顶点处的Anchor
//因此这里用anchoredPosition让Item图片填充满Slot
this.GetComponent<RectTransform>().anchoredPosition = currentSlot.GetComponent<RectTransform>().anchoredPosition;
}
else if(eventData.pointerCurrentRaycast.gameObject.tag == Tags.InventoryItem)
{
Transform currentSlot = eventData.pointerCurrentRaycast.gameObject.transform.parent;
this.transform.SetParent(currentSlot);
this.GetComponent<RectTransform>().anchoredPosition = currentSlot.GetComponent<RectTransform>().anchoredPosition;
}
} public void OnBeginDrag(PointerEventData eventData)
{
originalSlot = this.GetComponent<Transform>().parent; //每次拖拽开始前记录初始位置
isDragging = true;
itemCanvasGroup.blocksRaycasts = true;
item.transform.SetParent(parent.transform, false); // 将item设置到当前UI层级的最下面(最表面,防止被同一层级的UI覆盖)
item.transform.SetAsLastSibling(); item.GetComponent<RectTransform>().SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, x_item);
item.GetComponent<RectTransform>().SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, y_item);
} public void OnDrag(PointerEventData eventData)
{
itemCanvasGroup.blocksRaycasts = false;
DragPos(eventData);
//OnPointerEnter(eventData);
} public void OnEndDrag(PointerEventData eventData)
{
OnPointerEnter(eventData);
itemCanvasGroup.blocksRaycasts = true;
isDragging = false;
} //获取鼠标当前位置,并赋给item
private void DragPos(PointerEventData eventData)
{
RectTransform RectItem = item.GetComponent<RectTransform>();
Vector3 globalMousePos;
if (RectTransformUtility.ScreenPointToWorldPointInRectangle(item.transform as RectTransform, eventData.position, eventData.pressEventCamera, out globalMousePos))
{
RectItem.position = globalMousePos;
}
}
InventoryItem
Unity官方的的实现代码:
官方的的代码实现的是拖动物体时生成一个新的Gamobject
下面是官方代码加自己的一些注释
public bool dragOnSurfaces = true; private GameObject m_DraggingIcon;
private RectTransform m_DraggingPlane; public void OnBeginDrag(PointerEventData eventData)
{
//找到有Canvas组件的物体
var canvas = FindInParents<Canvas>(gameObject); if (canvas == null)
return; //We have clicked something that can be dragged.
// What we want to do is create an icon for this.
//给实例化的新GameObject命名
m_DraggingIcon = new GameObject(this.name);
//放到指定路径
m_DraggingIcon.transform.SetParent(canvas.transform, false); //Move the transform to the end of the local transform list.
//Puts the panel to the front as it is now the last UI element to be drawn.
m_DraggingIcon.transform.SetAsLastSibling(); //给新GameObject添加<Image>组件
var image = m_DraggingIcon.AddComponent<Image>();
//把当前脚本所挂载的物体的图片赋给新GameObject
image.sprite = GetComponent<Image>().sprite;
image.SetNativeSize(); if (dragOnSurfaces)
m_DraggingPlane = transform as RectTransform;
else
m_DraggingPlane = canvas.transform as RectTransform; SetDraggedPosition(eventData);
} public void OnDrag(PointerEventData data)
{
if (m_DraggingIcon != null)
SetDraggedPosition(data);
} private void SetDraggedPosition(PointerEventData data)
{ if (dragOnSurfaces && data.pointerEnter != null && data.pointerEnter.transform as RectTransform != null)
m_DraggingPlane = data.pointerEnter.transform as RectTransform; var rt = m_DraggingIcon.GetComponent<RectTransform>();
Vector3 globalMousePos;
if (RectTransformUtility.ScreenPointToWorldPointInRectangle(m_DraggingPlane, data.position, data.pressEventCamera, out globalMousePos))
{
rt.position = globalMousePos;
rt.rotation = m_DraggingPlane.rotation;
}
} public void OnEndDrag(PointerEventData eventData)
{
if (m_DraggingIcon != null)
Destroy(m_DraggingIcon);
} //实现不断往相应的上层parent查找所需组件
//Component: Base class for everything attached to GameObjects.
static public T FindInParents<T>(GameObject go) where T : Component
{
//如果go为null,返回null
if (go == null) return null; //查找go身上相应组件(Canvas)
//找到后返回comp
var comp = go.GetComponent<T>();
if (comp != null)
return comp; //查找t的parent
//循环查找,不断往上层找parent,直到找到相应组件(Canvas)
Transform t = go.transform.parent;
while (t != null && comp == null) //t有上层parent && 第1步里未找到组件
{
comp = t.gameObject.GetComponent<T>();
t = t.parent;
}
return comp;
}
UnityAPI手册内的代码
三、实现
如图是整个背包的UI层级,每个Slot和里面的Item都是Prefab,把脚本挂在InventoryItem上即可实现
Unity — — UGUI之背包物品拖放的更多相关文章
- Unity——可复用背包工具
Unity可复用背包工具 Demo展示 设计思路 游戏中有非常多的背包样式,比如玩家道具背包,商城,装备栏,技能栏等:每个形式的背包都单独写一份逻辑会非常繁琐,所以需要有一套好用的背包工具: 这些背包 ...
- Unity UGUI —— 无限循环List
还记得大学毕业刚工作的时候是做flash的开发,那时候看到别人写的各种各样的UI组件就非常佩服,后来自己也慢慢尝试着写,发现其实也就那么回事.UI的开发其实技术的成分相对来说不算多,但是一个好的UI是 ...
- Unity UGUI图文混排源码(三) -- 动态表情
这里是根据图文混排源码(二)进一步修改的,其他链接也不贴了,就贴一个链接就好了,第一次看这文章的同学可以先去看看其他几篇文章 Unity UGUI图文混排源码(二):http://blog.csdn. ...
- Unity UGUI图文混排源码(二)
Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...
- Unity UGUI图文混排源码(一)
Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...
- Unity UGUI实现图文混排
目前在unity实现图文混排的好像都是通过自定义字体然后在文本获取字符的位置,用图片替换掉图片标签,这样对于支持英文来说,并没有什么影响.然后对于中文来说就是一个相当麻烦的事了,毕竟图文混排多用于游戏 ...
- Unity UGUI
超详细的基础教程传送门:(持续更新中) Unity UGUI之Canvas&EventSystem:http://blog.csdn.net/qq992817263/article/detai ...
- Unity UGUI Layout自动排版组件用法介绍
Unity UGUI布局组件 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...
- Curved UI - VR Ready Solution To Bend Warp Your Canvas 1.7,1.8,2.2,2.3 四种版本压缩包(Unity UGUI曲面插件),可以兼容VRTK
Curved UI - VR Ready Solution To Bend Warp Your Canvas 1.7,1.8,2.2,2.3 四种版本压缩包(Unity UGUI曲面插件) 可以兼容V ...
随机推荐
- CSS盒子模型之CSS3可伸缩框属性(Flexible Box)
CSS盒子模型(下) 一.CSS3可伸缩框(Flexible Box) 可伸缩框属性(Flexible Box)是css3新添加的盒子模型属性,有人称之为弹性盒模型,它的出现打破了我们经常使用的浮动布 ...
- vue 校验插件 veeValidate使用
1.内置的校验规则 after{target} - 比target要大的一个合法日期,格式(DD/MM/YYYY) alpha - 只包含英文字符 alpha_dash - 可以包含英文.数字.下 ...
- jQuery 3D圆盘旋转焦点图 支持鼠标滚轮
之前我们分享过很多炫酷实用的jQuery焦点图插件了,今天介绍的这款jQuery焦点图非常特别,所有图片围成一个圆圈,组成一个立体视觉的圆盘,并且可以旋转选择圆盘中的图片.另外,这款jQuery 3D ...
- 安装VMware,Linux
不是每一个程序员都必须玩过linux,只是博主觉得现在的很多服务器都是linux系统的,而自己属于那种前端也搞,后台也搞,对框架搭建也感兴趣,但是很多生产上的框架和工具都是安装在服务器上的,而且有不少 ...
- css自问自答(二)
css自问自答(二) 7.掌握定位的一些属性 position 和 display 属性,以及如何浮动(float)和清除(clear)元素,z-index属性 三个属性控制: position 属性 ...
- Oracle 数据库纯dos代码操作
1. 安装成功后进入DOS界面操作 在进行以下操作时,需启动Oracle服务. A.进入sql界面:开始--运行--cmd:输入sqlplus 回车 提示输入正确的用户名和密码 B.开始—>所有 ...
- 创建一个接口Shape,其中有抽象方法area,类Circle 、Rectangle实现area方法计算其面积并返回。又有Star实现Shape的area方法,其返回值是0,Star类另有一返回值boolean型方法isStar;在main方法里创建一个Vector,根据随机数的不同向其中加入Shape的不同子类对象(如是1,生成Circle对象;如是2,生成Rectangle对象;如是3,生成S
题目补充: 创建一个接口Shape,其中有抽象方法area,类Circle .Rectangle实现area方法计算其面积并返回. 又有Star实现Shape的area方法,其返回值是0,Star类另 ...
- Usaco2008 Jan
[Usaco2008 Jan] https://www.luogu.org/problemnew/show/P2419 题目描述 N (1 ≤ N ≤ 100) cows, conveniently ...
- 基于vue-cli3和追书神器制作的移动端小说阅读网站,附接口和源码
项目简介 基于node express+mysql+vue-cli3和追书神器接口制作的移动端小说阅读网站,**仅供参考学习!不用于任何商业用途!** 闲暇时间用vue练练手,就想写个小说网站来看看, ...
- vue 目录结构解析
├── README.md 项目介绍├── index.html 入口页面├── build 构建脚本目录│ ├── webpack.base.conf.js webpack基础配置,开发环境,生产环 ...