最新背包代码:

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之背包物品拖放的更多相关文章

  1. Unity——可复用背包工具

    Unity可复用背包工具 Demo展示 设计思路 游戏中有非常多的背包样式,比如玩家道具背包,商城,装备栏,技能栏等:每个形式的背包都单独写一份逻辑会非常繁琐,所以需要有一套好用的背包工具: 这些背包 ...

  2. Unity UGUI —— 无限循环List

    还记得大学毕业刚工作的时候是做flash的开发,那时候看到别人写的各种各样的UI组件就非常佩服,后来自己也慢慢尝试着写,发现其实也就那么回事.UI的开发其实技术的成分相对来说不算多,但是一个好的UI是 ...

  3. Unity UGUI图文混排源码(三) -- 动态表情

    这里是根据图文混排源码(二)进一步修改的,其他链接也不贴了,就贴一个链接就好了,第一次看这文章的同学可以先去看看其他几篇文章 Unity UGUI图文混排源码(二):http://blog.csdn. ...

  4. Unity UGUI图文混排源码(二)

    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...

  5. Unity UGUI图文混排源码(一)

    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304 Unity UGUI图文混排源码(二):ht ...

  6. Unity UGUI实现图文混排

    目前在unity实现图文混排的好像都是通过自定义字体然后在文本获取字符的位置,用图片替换掉图片标签,这样对于支持英文来说,并没有什么影响.然后对于中文来说就是一个相当麻烦的事了,毕竟图文混排多用于游戏 ...

  7. Unity UGUI

    超详细的基础教程传送门:(持续更新中) Unity UGUI之Canvas&EventSystem:http://blog.csdn.net/qq992817263/article/detai ...

  8. Unity UGUI Layout自动排版组件用法介绍

    Unity UGUI布局组件 本文提供全流程,中文翻译. Chinar 坚持将简单的生活方式,带给世人!(拥有更好的阅读体验 -- 高分辨率用户请根据需求调整网页缩放比例) Chinar -- 心分享 ...

  9. 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 ...

随机推荐

  1. 笔记本无密码连接wifi

    用手机可以用wifi万能钥匙破解wifi,就想找电脑版的wifi万能钥匙,然并卵. 就去寻找各种办法,最后找了个巧, 用手机下载wifi万能钥匙连接,并且使用数据线连接上笔记本. 然后手机设置中找到开 ...

  2. chrome://命令

    一些常用的命令: chrome://version 显示当前版本 chrome://flags 实验项目,加“#项目名称”锚点可以直接定位到项目 chrome://settings 设置,下图是设置定 ...

  3. java 输出流 outputstream

    一:输入和输出概念 输入流(inputstream):对于java程序来说,从程序写入文件叫做输出. 输出流(outputstream):对于java程序来说,从文件读取数据,到java程序叫做输入. ...

  4. Spring源码分析(一)基本介绍

    摘要:本文结合<Spring源码深度解析>来分析Spring 5.0.6版本的源代码.若有描述错误之处,欢迎指正. 前言 作为一名开发人员,阅读源码是一个很好的学习方式.本文将结合< ...

  5. NYOJ-171 聪明的kk 填表法 普通dp

    题目链接: http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=171 聪明的kk 时间限制:1000 ms  |  内存限制:65535 KB 难 ...

  6. Linux内存调试工具初探-MEMWATCH(转)

    C 语言作为 Linux 系统上标准的编程语言给予了我们对动态内存分配很大的控制权.这种自由可能会导致严重的内存管理问题,可能导致程序崩溃或随时间的推移导致性能降级. 内存泄漏(即 malloc()  ...

  7. JQuery Validate插件与实现

    菜鸟拙见,望请纠正 一:效果展示:以下是两个注册表单验证,左边使用Jquery validate插件实现,右边是自己用JQuery实现,效果差不多,但个人推荐用插件,毕竟前人栽了树而且长大了后人当然好 ...

  8. mac上cocoapods安装与卸载

    安装 # 安装最新beta版 sudo gem install cocoapods --pre -n /usr/local/bin # 安装最新稳定版 sudo gem install cocoapo ...

  9. 《锋利的JQ》摘抄(一) jq基础篇

    前言:第一次写博客有点紧张233333,我会在博客里放一下在赌这本书过程中遇到的一些有用的知识点,希望等帮助到大家.好了正题开始(只要是我不知道该说啥了= =)  一,资源(在w3cfuns资源中可以 ...

  10. JavaWeb基础—XML学习小结

    一.概述 是什么? 指可扩展标记语言 能干什么? 传输和存储数据 怎么干? 需要自行定义标签. XML 独立于硬件.软件以及应用程序 通常.建立完xml文件后首要的任务是:引入约束文件! 二.XML简 ...