Unity3D--UGUI背包系统(三)

作者: Wei_Boom | 来源:发表于2016-04-01 02:00 被阅读8214次

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

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。
运行一下,已经完成对背包的整理和对物品的拖放了。

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

相关文章

  • Unity3D--UGUI背包系统(三)

    之前完成了一个背包以及添加物品,但是物品并不具备“物品”所该有的功能,除开每个游戏所需的特定的效果之外,也缺乏基本...

  • Unity3D--UGUI背包系统(一)

    与以前的ngui所比较的话,ugui感觉更为简单方便,同样也与ngui有很多相同的功能,这里我们先来初步制作ugu...

  • Unity3D--UGUI背包系统(二)

    之前我们创建了一个简单的背包框架,但是却没有物品。这里呢,我们提供一个简单的添加物品的一个思路。 首先,我们创建一...

  • Unity3D--UGUI背包系统(一)

    新建一个项目,创建一Image对象,同时会生成Canvas和EventSystem,修改Image的名字为Bg,我...

  • 21UGUI背包系统

    一、UGUI背包系统展示## 二、背包系统的搭建## 三、加载预支物的制作## 四、预支物基类的建立以及各种相应的...

  • 背包系统(2)

    显示物品的描述信息 用一个单例存放信息 usingUnityEngine; usingSystem.Collect...

  • NGUI背包系统

    NGUI背包系统实现装备的拾取、拖拽,交换以及数量的叠加 步骤一:实现游戏装备的拖拽 首先导入NGUI插件,导入后...

  • 18NGUI之背包系统

    NGUI背包系统的制作## 一、背包系统的搭建## 二、格子里面物品(预制物的制作)## 格子里面的物体需要实现可...

  • Unity背包系统设计

    背包系统设计思路 基本思路:玩家在场景中捡到东西——放入背包中对应Item栏——点击装备武器放入人物装备槽(改变s...

  • 5.3背包系统(1)

    基类脚本 usingUnityEngine; usingSystem.Collections; publiccla...

网友评论

  • 彬彬的笔记录:PS:Findchild老版本了,更新用Find();
  • 不浪漫的罪名:go.transform.SetParent(_i);这句一直在报错,怎么解决
  • 7b14a79c74cc:受益匪浅 感谢楼主
  • a681dbf50c19:请问按照您的方法在按下鼠标时设置卡片的父节点为gridManager然后不管我将该卡片移到哪里 最后他都会自动跳到gridManager的锚点位置? 请问这是什么原因 希望楼主可以给我一个做好的demo我好找找出错原因 邮箱806859504@qq.com 谢谢
  • 9e2e40c6a638:请问移动物品时 离开背包范围 物品就会被遮挡 要怎样才能不被遮挡呢
    9e2e40c6a638:@9e2e40c6a638 解决了
  • 9e2e40c6a638:请问(Parent of RectTransform is being set with parent property. Consider using the SetParent method instead, with the worldPositionStays argument set to false. This will retain local orientation and scale rather than world orientation and scale, which can prevent common UI scaling issues.)
    这个是什么错
    出现在抬起鼠标时 OnPointerUp()的 if(hit.collider.gameObject.tag=="Grid"&&hit.collider.gameObject.transform.FindChild("Sword(Clone)")==null) 里

    就是这句transform.parent=hit.transform;
    现在拖动完放开的时候 位置老是出错
    a681dbf50c19:@9e2e40c6a638 我也是同样的错误 请问ItemDrag应该放在哪个object上啊?我放在的是每一个格子上
    9e2e40c6a638:@9e2e40c6a638 哦哦 我找到原因了 我把drag脚本挂到每个格子上了 。。。 是我思考不够。
  • 9ccd3bd2fd8f:你好!请问为什么我拖动的是所有的格子OTZ :joy:
    Wei_Boom:@想回深山做妖怪 每一个格子都是单独的对象,所以检查一下是否是拖动了整个层级面板,或者将所有格子合并成一个对象了,具体看看你的代码和布局吧 :smiley:
  • 07addefcfc82:正要做游戏的背包系统,谢谢分享
  • 19e967ee9247:点赞~!!!!楼主写的东西都还算基础,新手受益匪浅~!!!!
    Wei_Boom: @风中旅人 谢谢,多指教~
  • 芝了那个麻:马住有用~

本文标题:Unity3D--UGUI背包系统(三)

本文链接:https://www.haomeiwen.com/subject/tvfylttx.html