Unity3D--UGUI背包系统(三)

之前完成了一个背包以及添加物品,但是物品并不具备“物品”所该有的功能,除开每个游戏所需的特定的效果之外,也缺乏基本的移动拖拽功能等,这篇我们完善一下背包系统。先回顾一下之前的代码,这里我直接贴出来。

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class GridManager : MonoBehaviour {
    public List<GameObject> grid;//格子列表,用来存储所有个物品格子
    public GameObject item;//物品对象,把prefab添加到这里
    void Update () {
        if(Input.GetKeyDown(KeyCode.K)){
            AddItem(item);//调用添加物品的方法
            }
    }
    public void AddItem(GameObject _item){
     //查找每个格子,寻找空格子的物体。
        for(int i=0;i<grid.Count;i++){
            //这里我们通过查找名字来寻找物体,判断格子内是否有物品存在
            //但这样就只能查找命名为该名字的物体,实际中我们可以通过tag或者其他属性来判断
           bool isHaving= grid[i].transform.FindChild("Sword(Clone)");
           //如果当前格子有物品存在         
           if(isHaving)
                continue;             
           else if(!isHaving){
                //当前的空格子
                Transform _i=grid[i].gameObject.GetComponent<RectTransform>();
                //创建一个物品对象
                GameObject go=(GameObject)Instantiate(_item); 
                //把创建的物品对象添加到格子下                        
                go.transform.SetParent(_i);
                //调整物品的位置位于格子中间
                go.transform.localPosition=Vector3.zero;
               break;
           }      
        }
    }

这段代码实现了根据按顺序给每个格子添加物品,如果我们的格子里面有物品,则会跳过,查看下一个格子是否能存放物品。注意,我们暂时没有写背包格子满载的情况,也没有判断物品是否能够叠加的功能。

那么,当一个背包里的东西杂乱无章的时候,我们就需要对其进行整理。这里我们先添加一个函数。

//在开头添加一个存储列表
public List<GameObject> c_grid;//备用列表,用于存储需要整理位置的物品
//整理物品函数
public void ClearUpGrid(){
        for (int i = 0; i < grid.Count; i++)
        {
            bool isHaving= grid[i].transform.FindChild("Sword(Clone)");
            if(isHaving){
                GameObject go=grid[i].transform.FindChild("Sword(Clone)").gameObject;
               c_grid.Add(go);//将当前格子内的物品存储到后备列表里面
               if(i==grid.Count-1)//当所有格子内的物品都存放到备用列表中后
                grid.Clear();//清空当前的背包
            }
        }
        for (int j = 0; j < c_grid.Count; j++)
        {
            //对于每个存储到后备列表中的物品,我们依次添加到格子列表中
            GameObject go=c_grid[j];
            go.transform.SetParent(grid[j].transform);
                //调整物品的位置位于格子中间
            go.transform.localPosition=Vector3.zero;  
            //如果所有的物品都添加到了物品格子列表中,则清空后备列表
            if(j==c_grid.Count)
              c_grid.Clear();
    } 
        }
         

我们再给Update函数添加一句来调用整理背包的函数

 if(Input.GetKeyDown(KeyCode.Space)){
                ClearUpGrid();
            }

分析一下
1、查询每个背包格子,如果有物品存在,则将该物品复制一份到备用列表中。
2、当查询到最后一个背包格子的时候,则清空当前背包格子内的物品
3、查询每个后备列表中的物品,依次添加到背包格子列表中。
4、当后备列表中所有物品都添加完成了,则清空后备列表。

这里也需要注意一下!!我们发现代码中再一次对整个背包列表进行了查询,与之前添加物品函数一样,总共我们就查询了两次,其实我们也可以当背包格子中有物品存在的时候,就将其添加到后备列表中存储,整理的时候直接清空格子再添加。但是当我们背包过大,物品过多的时候,这样子不一定好,因为这样每个物品就占了2个资源,如果我们按照这里的函数来执行的话,就只会在整理的时候占用资源。我们在做背包的时候,需要考虑如何安排这样的代码。这里提供这样的一个方法来参考。

另外,我们这里所有的物品都是一个,所以不存在类别关系,如果要对物品进行分类优先排序,我们需要对每个物品添加类别属性,通过类别属性来自定义优先级,在排序的时候进行优先排序。

背包整理的功能有了,接下来是对每个物品的处理。

首先,我们确定几项要点:
1、物品能够拖动
2、物品拖动后的层级关系
3、物品拖放的位置
4、拖动失败的处理

其实这是一个很简单的问题,我们事先给gridList添加了一个空物体GridManager作为父物体,先给我们的物品添加一个脚本(该脚本偷懒用的别人的)

using UnityEngine;  
using UnityEngine.UI;  
using UnityEngine.EventSystems;  
using System.Collections;  
  
public class ItemDrag : MonoBehaviour, IPointerDownHandler,IPointerUpHandler,IDragHandler {  
      
    // 鼠标起点  
    private Vector2 originalLocalPointerPosition;     
    // 面板起点  
    private Vector3 originalPanelLocalPosition;  
    // 当前面板  
    private RectTransform panelRectTransform;  
    // 父节点,这个最好是UI父节点,因为它的矩形大小刚好是屏幕大小  
    public RectTransform parentRectTransform;  
    //格子列表
    private GameObject gridManager;//在gridlist之上添加的一个新的空物体作为父节点
    private GameObject originalGrid;//记录物品拖动前的位置
    private static int siblingIndex = 0;  
    void Awake () {  
        panelRectTransform = transform as RectTransform;  
        parentRectTransform = GameObject.FindGameObjectWithTag("ScrollRect").GetComponent<RectTransform>() as RectTransform;  
        gridManager=GameObject.Find("GridManager");   
    }  
      
    // 鼠标按下  
    public void OnPointerDown (PointerEventData data) {  
        //记录物品当前所在的格子信息
        originalGrid=panelRectTransform.parent.gameObject;
       //将物品放置在gridManager下,并设置层级,保证物品显示在整个背包层面之上
        panelRectTransform.SetParent(gridManager.transform);
        siblingIndex++;  //层级管理
        panelRectTransform.transform.SetSiblingIndex(siblingIndex);  
        // 记录当前面板起点  
        originalPanelLocalPosition = panelRectTransform.localPosition;  
        // 通过屏幕中的鼠标点,获取在父节点中的鼠标点  
        // parentRectTransform:父节点  
        // data.position:当前鼠标位置  
        // data.pressEventCamera:当前事件的摄像机  
        // originalLocalPointerPosition:获取当前鼠标起点  
        RectTransformUtility.ScreenPointToLocalPointInRectangle (parentRectTransform, data.position, data.pressEventCamera, out originalLocalPointerPosition);  
    }  
    public void OnPointerUp(PointerEventData data){
       // transform.SetParent(gridlist.transform);
        RaycastHit2D hit = Physics2D.Raycast(Input.mousePosition,-Vector2.up); 
        if (hit.collider != null) { //如果射线检测到的gameobject为grid,就把当前物品放在grid节点下 
            if(hit.collider.gameObject.tag=="Grid"&&hit.collider.gameObject.transform.FindChild("Sword(Clone)")==null) 
               transform.parent=hit.transform;
               else
               {
//如果不是格子或没有检测到物体,则将物品放回到原来的格子内
                   transform.parent=originalGrid.transform;
               }
        }
        else
        {
          transform.parent=originalGrid.transform;
        }
    //重置物品位置
      transform.localPosition=Vector3.zero;
    }
    // 拖动  
    public void OnDrag (PointerEventData data) {  
        if (panelRectTransform == null || parentRectTransform == null){
            return;  
        }
        Vector2 localPointerPosition;  
        // 获取本地鼠标位置  
        if (RectTransformUtility.ScreenPointToLocalPointInRectangle (parentRectTransform, data.position, data.pressEventCamera, out localPointerPosition)) {  
            // 移动位置 = 本地鼠标当前位置 - 本地鼠标起点位置  
            Vector3 offsetToOriginal = localPointerPosition - originalLocalPointerPosition;  
            // 当前物品位置 = 物品起点 + 移动位置  
            panelRectTransform.localPosition = originalPanelLocalPosition + offsetToOriginal;  
        }  
       // ClampToWindow ();  
    } 

本段代码是借用他人的代码做修改来使用的。我们注意一下代码。
首先,在脚本开头我们添加了这样一句

using UnityEngine.EventSystems;

这是引用ugui的响应事件,同时也在MonoBehaviour后添加了三个接口。
同时提一下,因为C#不支持多继承,但我们可以通过实现接口的方法来做类似多继承的效果。

public class ItemDrag : MonoBehaviour, IPointerDownHandler,
IPointerUpHandler,IDragHandler

添加后会发现报错,提示我们没有实现接口。这三个接口名分别对应以下三个函数,分别当鼠标按下时,鼠标松开时,以及物品拖动时。

public void OnPointerDown (PointerEventData data) {  }
public void OnPointerUp (PointerEventData data) {  }
public void OnDrag(PointerEventData data) {  

详细的功能在代码里注释有了。
另外关于RectTransformUtility.ScreenPointToLocalPointInRectangle,雨松的博客里也有讲过,是将一个坐标转换的问题,将鼠标的坐标转换为UI的坐标。这段代码呢可以去官网查询一下api了解一下,不仅是背包,包括血条名字的显示,飙血字效果等都会用到的相关方法。

再次注意,光是这样,我们是检测不到碰撞的,通过射线碰撞需要对每个物品格子添加Collider来检测,选中物品列表中的每个grid,添加BoxCollider2D组件,在Scene下调节Collider的大小。现在可以检测了。

别忘了给格子添加Tag为Grid。
运行一下,已经完成对背包的整理和对物品的拖放了。

如果对本篇内容有什么问题或者意见或不对的地方,请及时指出,欢迎交流~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,542评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,822评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,912评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,449评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,500评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,370评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,193评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,074评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,505评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,722评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,841评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,569评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,168评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,783评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,918评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,962评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,781评论 2 354

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,656评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,116评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,409评论 0 17
  • 失去就失去吧,至少你能早点回到现实中, 和一个不爱你的人在一起,迟早都会失去;和一个不同路的人交朋友,迟早会分离;...
    惜笑Q醉蓝颜阅读 422评论 0 0
  • 【导读】:青春痘永远是女人们最痛恨的,祛痘消除痘印总是困扰着我们,今天秀美网小编教你如何去除难看的痘痘和痘印,下面...
    都来米在路上阅读 605评论 0 0