最新背包代码:

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. 【Alpha】Daily Scrum Meeting——blog1

    团队成员 吴吉键 201421122007(组长) 魏修祺 201421122008 孙劲林 201421122022 1. 会议当天照片 忘记拍了,能补上不? 2. 每个人的工作 3. 燃尽图

  2. Mina使用总结(一)MinaServer

    我们先看一个最简单的Mina Server服务端代码,该段代码实现了服务端Server启动并监听客户端请求 package com.bypay.mina.server; import java.io. ...

  3. Django之模板配置(template)

    Django模板系统 官方文档 jinja2模块中文 jinja2模块官方 常用语法 只需要记两种特殊符号: {{  }}和 {% %} 变量相关的用{{}},逻辑相关的用{%%}. 变量 在Djan ...

  4. macaca自动化初体验

     1.安装#cnpm i -g macaca-cli macaca-ios# Install Tools And Driver2.检查安装环境#macaca doctor ANT_HOME未设置,下载 ...

  5. Hadoop学习之路(八)在eclispe上搭建Hadoop开发环境

    一.添加插件 将hadoop-eclipse-plugin-2.7.5.jar放入eclipse的plugins文件夹中 二.在Windows上安装Hadoop2.7.5 版本最好与Linux集群中的 ...

  6. 《Java程序设计》第12周课堂实践总结

    <Java程序设计>第12周课堂实践总结 实践一 教材代码检查-p98 要求 修改教材P98 Score2.java, 让执行结果数组填充是自己的学号: 提交在IDEA或命令行中运行结查截 ...

  7. select、poll 和epoll区别

    阻塞 I/O(blocking IO) 当用户进程调用了recvfrom这个系统调用,kernel就开始了IO的第一个阶段:准备数据(对于网络IO来说,很多时候数据在一开始还没有到达.比如,还没有收到 ...

  8. linux文件系统初始化过程(6)---执行init程序

    一.目的 内核加载完initrd文件后,为挂载磁盘文件系统做好了必要的准备工作,包括挂载了sysfs.proc文件系统,加载了磁盘驱动程序驱动程序等.接下来,内核跳转到用户空间的init程序,由ini ...

  9. block本质探寻二之变量捕获

    一.代码 说明:本文章须结合文章<block本质探寻一之内存结构>和<class和object_getClass方法区别>加以理解: //main.m #import < ...

  10. Linux(Redhat)安装python虚拟环境

    哇!安装的好烦啊,最后发现是自己网络的原因.静心总结一下吧!!! python是3.6 centos 6 64位 1.安装python https://blog.csdn.net/O_OKKk/art ...