【Unity随笔】Unity之ugui简单背包实现与Json读取物品信息

  今天记录一个自己制作背包的过程,不带插件,使用原生的UI系统,物品的信息统一使用Json存储与提取。一般来说,相比于txt和xml,Json更适合用在移动设备上,下文会对Unity封装好的Json工具做详细介绍。
  整体的结构可能不是非常合理,主要是提供一个思路。该背包的使用建立在一个UI框架之上,之后我会找时间写一个自己设计的UI框架,就当抛砖引玉,希望网友有更好的想法,能够提出来,大家互相学习学习。在背包上的更改建议,我会直接在本文进行修改与试验。


(1)背包框架以及说明

这里写图片描述

这里我使用了一个UI框架,这个不用管,UI框架的作用只是为了方便管理,和使得整个结构清晰明了。窗体封装了打开与关闭的公有方法,并无涉及到窗体具体的特有功能,所以这里不讲框架并不会造成做不出背包的问题。

(2)脚本以及说明

UI_PacksackForm.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using MyUI;
using System;
using UnityEngine.EventSystems;

public class UI_PacksackForm : BaseUIForm,UnityEngine.EventSystems.IBeginDragHandler,
    UnityEngine.EventSystems.IDragHandler, UnityEngine.EventSystems.IEndDragHandler{



    /*属性字段*/
    public List<UI_PackCell> DrugCells;              //这个用来存储药品类所有小格子的列表
    public List<UI_PackCell> EquipCells;
    public List<UI_PackCell> SkillCells;
    public List<UI_PackCell> TaskCells;
    private Vector3 _offsetPointerToPack;            //这个鼠标指针点击到背包窗体的中心点的偏移
    private UnityEngine.UI.Button _Btn_ClearUp;      //这个是整理按钮
    private UnityEngine.UI.Button _Btn_Close;        //关闭按钮
    private UnityEngine.UI.ScrollRect _ScrollView;   //这个是ScrollView
    private UnityEngine.UI.Dropdown _DpDn_BackSelect;//背包类型的下拉选择菜单
    public RectTransform DrugContent;                //这是4个不同种类的背包
    public RectTransform EquipContent;
    public RectTransform SkillContent;
    public RectTransform TaskContent;

    private ItemsType _itemsType = ItemsType.Drug;   //背包当前选择的物品种类

    #region 拖拽
    ///开始拖拽
    void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
    {
        Debug.Log("开始拖拽背包");
        Vector3 worldPosition;
        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(transform.GetComponent<RectTransform>(),
            eventData.position, eventData.pressEventCamera, out worldPosition))
        {
            _offsetPointerToPack = worldPosition - transform.GetComponent<RectTransform>().position;
        }

    }
    ///拖拽中
    void IDragHandler.OnDrag(PointerEventData eventData)
    {
        Vector3 worldPosition;
        if (RectTransformUtility.ScreenPointToWorldPointInRectangle(transform.GetComponent<RectTransform>(),
            eventData.position, eventData.pressEventCamera, out worldPosition))
        {
            transform.GetComponent<RectTransform>().position = worldPosition - _offsetPointerToPack;
        }
    }
    ///拖拽结束
    void IEndDragHandler.OnEndDrag(PointerEventData eventData)
    {
        Debug.Log("结束背包拖拽");
    }
    #endregion


    /*公有方法*/
    /// <summary>
    /// 用以注册下拉选项的事件
    /// </summary>
    /// <param name="num"></param>
    public void onValueChange(Int32 num)
    {
        switch(num)
        {
            case 0:
                {
                    DrugContent.gameObject.SetActive(true);
                    EquipContent.gameObject.SetActive(false);
                    SkillContent.gameObject.SetActive(false);
                    TaskContent.gameObject.SetActive(false);
                    _ScrollView.content = DrugContent;
                    _itemsType = ItemsType.Drug;
                }
                break;
            case 1:
                {
                    DrugContent.gameObject.SetActive(false);
                    EquipContent.gameObject.SetActive(true);
                    SkillContent.gameObject.SetActive(false);
                    TaskContent.gameObject.SetActive(false);
                    _ScrollView.content = EquipContent;
                    _itemsType = ItemsType.Equip;
                }
                break;
            case 2:
                {
                    DrugContent.gameObject.SetActive(false);
                    EquipContent.gameObject.SetActive(false);
                    SkillContent.gameObject.SetActive(true);
                    TaskContent.gameObject.SetActive(false);
                    _ScrollView.content = SkillContent;
                    _itemsType = ItemsType.Skil;
                }
                break;
            case 3:
                {
                    DrugContent.gameObject.SetActive(false);
                    EquipContent.gameObject.SetActive(false);
                    SkillContent.gameObject.SetActive(false);
                    TaskContent.gameObject.SetActive(true);
                    _ScrollView.content = TaskContent;
                    _itemsType = ItemsType.Other;
                }
                break;
        }

    }
    /// <summary>
    /// 用以注册整理按钮的事件
    /// </summary>
    public void CleanUp()
    {
        List<UI_PackCell> temp;
        switch (_itemsType)
        {
            case ItemsType.Drug:
                {
                    temp = DrugCells;
                }
                break;
            case ItemsType.Equip:
                {
                    temp = EquipCells;
                }
                break;
            case ItemsType.Skil:
                {
                    temp = SkillCells;
                }
                break;
            case ItemsType.Other:
                {
                    temp = TaskCells;
                }
                break;
            default:
                temp = new List<UI_PackCell>();
                break;
        }
        if (temp.Count > 0)
            for (int i = 0; i < temp.Count; ++i)
            {
                for(int j = i+1; j < temp.Count; ++j)
                {
                    if(temp[i].getGoodsId()<temp[j].getGoodsId()&& temp[j].getGoodsId()>0)
                    {
                        temp[i].Exchange(temp[j]);
                    }
                }
            }

    }

    // Use this for initialization
    void Awake () {
        _DpDn_BackSelect = transform.FindChild("DpDn_PackSelect").GetComponent<UnityEngine.UI.Dropdown>();
        _ScrollView = transform.FindChild("ScrollView").GetComponent<UnityEngine.UI.ScrollRect>();
        _offsetPointerToPack = new Vector3();
        _Btn_ClearUp = transform.FindChild("Btn_ClearUp").GetComponent<UnityEngine.UI.Button>();
        _Btn_Close = transform.FindChild("Btn_Close").GetComponent<UnityEngine.UI.Button>();
        //为整理按钮注册事件
        _Btn_ClearUp.onClick.AddListener(new UnityEngine.Events.UnityAction(CleanUp));
        //为关闭按钮注册事件
        _Btn_Close.onClick.AddListener(new UnityEngine.Events.UnityAction(CloseUIForm));
        //下拉选项的事件注册
        _DpDn_BackSelect.onValueChanged.AddListener(new UnityEngine.Events.UnityAction<int>(onValueChange));
    }
}

UI_PackCell.cs

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

public class UI_PackCell : MonoBehaviour, UnityEngine.EventSystems.IBeginDragHandler,
    UnityEngine.EventSystems.IDragHandler, UnityEngine.EventSystems.IEndDragHandler{

    /*字段属性*/
    public UnityEngine.UI.RawImage _cellRawImage;
    private UnityEngine.UI.Text _Count;
    public byte _goodsId = 0;
    public bool isOccupy = false;   //是否被占用
    private bool isDragging =false; //是否被拖拽


    /*公有方法*/
    /// <summary>
    /// 获取物品的id,id为0则为空
    /// </summary>
    /// <returns></returns>
    public byte getGoodsId()
    {
        return _goodsId;
    }
    /// <summary>
    /// 设置物品id
    /// </summary>
    /// <param name="id"></param>
    public void setGoodsId(byte id)
    {
        _goodsId = id;
    }
    /// <summary>
    /// 获取该物品数量
    /// </summary>
    /// <returns></returns>
    public int getCount()
    {
        return int.Parse(_Count.text);
    }
    /// <summary>
    /// 设置该物品数量
    /// </summary>
    /// <param name="_count"></param>
    public void setCount(int _count)
    {
        _Count.text = _count.ToString();
    }

    #region 拖拽实现
    ///开始拖拽
    void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
    {
        if (isOccupy)
        {
            _cellRawImage.rectTransform.SetParent(transform.parent);
            _cellRawImage.rectTransform.SetAsLastSibling();
            isDragging = true;
        }
    }
    ///拖拽中
    void IDragHandler.OnDrag(PointerEventData eventData)
    {
        if (isDragging)
        {
            Vector3 target;
            if (RectTransformUtility.ScreenPointToWorldPointInRectangle(transform.GetComponent<RectTransform>(),
                eventData.position, eventData.pressEventCamera, out target))
            {
                _cellRawImage.transform.position = target;
            }
        }
    }
    ///拖拽结束
    void IEndDragHandler.OnEndDrag(PointerEventData eventData)
    {
        if (isDragging)
        {
            _cellRawImage.rectTransform.SetParent(transform);
            _cellRawImage.rectTransform.localPosition = Vector3.zero;
            if (eventData.pointerCurrentRaycast.gameObject != null && eventData.pointerCurrentRaycast.gameObject.tag == "PackCell")
            {
                _exChanged(eventData.pointerCurrentRaycast.gameObject);
            }

            isDragging = false;
        }
    }
    #endregion

    //私有方法
    /// <summary>
    /// 拖拽交换逻辑
    /// </summary>
    /// <param name="go"></param>
    private void _exChanged(GameObject go)
    {
        UI_PackCell targetCell = go.GetComponent<UI_PackCell>();

       if( targetCell.isOccupy)//目标位被占用
        {
            byte targetId = targetCell.getGoodsId();
            int targetCount = targetCell.getCount();
            //更新目标位置上的参数
            targetCell._cellRawImage.texture = Resources.Load<Texture>(ItemsInfo.getInstance().getSpritePath(getGoodsId()));
            targetCell._cellRawImage.gameObject.SetActive(true);
            targetCell.isOccupy = true;
            targetCell.setGoodsId(getGoodsId());
            targetCell.setCount(getCount());
            //跟新本地位置的参数
            _cellRawImage.texture = Resources.Load<Texture>(ItemsInfo.getInstance().getSpritePath(targetId));
            setGoodsId(targetId);
            setCount(targetCount);
        }
        else//目标位为空
        {
            byte targetId = targetCell.getGoodsId();
            int targetCount = targetCell.getCount();
            //更新目标位置上的参数
            targetCell._cellRawImage.texture = Resources.Load<Texture>(ItemsInfo.getInstance().getSpritePath(getGoodsId()));
            targetCell._cellRawImage.gameObject.SetActive(true);
            targetCell.isOccupy = true;
            targetCell.setGoodsId(getGoodsId());
            targetCell.setCount(getCount());
            targetCell._Count.gameObject.SetActive(true);
            //跟新本地位置的参数
            _cellRawImage.texture = null;
            _cellRawImage.gameObject.SetActive(false);
            isOccupy = false;
            setGoodsId(targetId);
            setCount(0);
            _Count.gameObject.SetActive(false);
        }
    }


    //公有方法
    /// <summary>
    /// 交换图片
    /// </summary>
    /// <param name="targetCell"></param>
    public void Exchange( UI_PackCell targetCell)
    {
        if (isOccupy)
        {
            byte targetId = targetCell.getGoodsId();
            int targetCount = targetCell.getCount();
            //更新目标位置上的参数
            targetCell._cellRawImage.texture = Resources.Load<Texture>(ItemsInfo.getInstance().getSpritePath(getGoodsId()));
            targetCell._cellRawImage.gameObject.SetActive(true);
            targetCell.isOccupy = true;
            targetCell.setGoodsId(getGoodsId());
            targetCell.setCount(getCount());
            //跟新本地位置的参数
            _cellRawImage.texture = Resources.Load<Texture>(ItemsInfo.getInstance().getSpritePath(targetId));
            setGoodsId(targetId);
            setCount(targetCount);
        }
        else
        {
            byte targetId = getGoodsId();
            int targetCount = getCount();
            //更新本地位置的参数
            _cellRawImage.texture = Resources.Load<Texture>(ItemsInfo.getInstance().getSpritePath(targetCell.getGoodsId()));
            _cellRawImage.gameObject.SetActive(true);
            isOccupy = true;
            setGoodsId(targetCell.getGoodsId());
            setCount(targetCell.getCount());
            _Count.gameObject.SetActive(true);
            //更新目标位置上的参数
            targetCell._cellRawImage.texture = null;
            targetCell._cellRawImage.gameObject.SetActive(false);
            targetCell.isOccupy = false;
            targetCell.setGoodsId(targetId);
            targetCell.setCount(0);
            targetCell._Count.gameObject.SetActive(false);
        }
    }


    // Use this for initialization
    void Awake () {
        _cellRawImage = transform.FindChild("Image").GetComponent<UnityEngine.UI.RawImage>();
        _Count = transform.FindChild("Count").GetComponent<UnityEngine.UI.Text>();
    }
}

这里的ItemsInfo先别管,这是用来读取物品信息的类;在后面会有详细说明;

(3)Json文件以及读取方法

ItemsInfo .cs

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

[System.Serializable]
public enum ItemsType
{
    Drug=1,//药品
    Equip,//装备
    Skil,//技能
    Other,//普通物品(收集、任务)
}

/*药品数据类*/
[System.Serializable]
public class DrugData
{
    [System.Serializable]
    public class Drug
    {
        public byte id;//1—50为药品编号
        public string drugName;
        public string sprite_Path;//图片路径(显示于UI背包中)
        public string prefeb_Path;//预制体路径(显示于世界坐标中)
        public string introduce;//物品详细介绍
        public int bloodAdd;//加血量
        public int magicAdd;//加血量
    }
    public string dataType;
    public Drug[] Drugs;
}

/*普通物品数据类*/
[System.Serializable]
public class OtherData
{
    [System.Serializable]
    public class Other
    {
        public byte id;//51—100之间编号
        public string otherName;
        public string sprite_Path;//图片路径
        public string prefeb_Path;//预制体路径
        public string introduce;//物品介绍
    }
    public string dataType;
    public Other[] Others;
}

/*装备物品类*/
[System.Serializable]
public class EquipData
{
    [System.Serializable]
    public class Equip
    {
        public byte id;//101—150之间编号(101-130为武器)
        public string equipName;
        public string sprite_Path;//图片路径
        public string prefeb_Path;//预制体路径
        public string introduce;//物品详细介绍
        public ushort STR;//力量增加值
        public ushort INT;//智力增加值
        public ushort DEX;//敏捷增加值
        public ushort LUC;//幸运增加值
        public ushort HLTH;//体力增加值
    }
    public string dataType;
    public Equip[] Equips;
}

/*技能物品类*/
[System.Serializable]
public class SkillData
{
    [System.Serializable]
    public class SkillField
    {
        public enum Type
        {
            Type_0=0,
            Type_1=1,
            Type_2,
            Type_3,
            Type_4,
            Type_5
        }
        private Type _type;
        public byte[,] SkillType
        {
            get
            {
                switch(_type)
                {
                    case Type.Type_1:
                        return Type_1;
                    case Type.Type_2:
                        return Type_2;
                    case Type.Type_3:
                        return Type_3;
                    case Type.Type_4:
                        return Type_4;
                    case Type.Type_5:
                        return Type_5;
                    default:
                        return null;
                }
            }
        }

        //         1
        //         1
        //         1
        //         1 
        public static byte[,] Type_1 = new byte[9, 9] 
        { 
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 }
        };

        //          1
        //          1
        //   1  1  1  1  1
        //          1
        //          1
        public static byte[,] Type_2 = new byte[9, 9]
        {
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,1,1,1,1,1,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 }
        };

        //       1    1
        //       1    1
        //       1 1 1
        //       1    1
        //       1    1
        public static byte[,] Type_3 = new byte[9, 9]
        {
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,1,0,1,0,0,0 },
            {0,0,0,1,0,1,0,0,0 },
            {0,0,0,1,1,1,0,0,0 },
            {0,0,0,1,0,1,0,0,0 },
            {0,0,0,1,0,1,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 }
        };

        //   1  1  1  1  1
        //          1
        //          1 
        public static byte[,] Type_4 = new byte[9, 9]
        {
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,1,1,1,1,1,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 }
        };

        //           1
        //           1
        //           1
        //           1
        //1  1  1  1  1  1  1
        public static byte[,] Type_5 = new byte[9, 9]
        {
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,0,0,0,1,0,0,0,0 },
            {0,1,1,1,1,1,1,1,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 },
            {0,0,0,0,0,0,0,0,0 }
        };
    }

    [System.Serializable]
    public class Skill
    {
        public byte id;//151_200之间的编号
        public string skillName;
        public string sprite_Path;
        public string prefeb_Path;//这个为技能特效,世界坐标中用于表示技能的物品统一用宝箱代替
        public string introduce;
        public SkillField skillField; 
    }

    public string dataType;
    public Skill[] Skills;

}


public class LoadJson<T> : MonoBehaviour
{
    /// <summary>
    /// 从Json文件中读取数据
    /// </summary>
    /// <param name="_FileName">文件名(文件必须是.json文件)</param>
    /// <returns></returns>
    public static T LoadJsonFromFile(string _FileName)
    {
        if (!File.Exists(Application.dataPath + "/Resources/Config/" + _FileName+".json"))
        {
            return default(T);
        }

        StreamReader sr = new StreamReader(Application.dataPath + "/Resources/Config/" + _FileName + ".json");

        if (sr == null)
        {
            return default(T);
        }
        string json = sr.ReadToEnd();

        if (json.Length > 0)
        {
            return JsonUtility.FromJson<T>(json);
        }

        return default(T);
    }
}


public class ItemsInfo : MonoBehaviour {

    /*属性字段*/
    DrugData Drug;
    SkillData Skill;

    #region debug
    private void ReadTest_Drug(DrugData drug)
    {
        Debug.Log("( ItemsInfo脚本 ) 测试Json读取:" + drug.dataType);
        foreach (var data in drug.Drugs)
            Debug.Log(data.id + " " + data.drugName + " " + data.introduce);
        Debug.Log("\n");
    }
    private void ReadTest_Skill(SkillData skill)
    {
        Debug.Log("( ItemsInfo脚本 ) 测试Json读取:" + skill.dataType);
        foreach (var data in skill.Skills)
            Debug.Log(data.id + " " + data.skillName + " " + data.introduce);
        Debug.Log("\n");
    }
    #endregion

    /*公有方法*/

    public string getSpritePath(byte id)
    {
        if (id < 50 && id > 0)
        {
            foreach (var data in Drug.Drugs)
                if (data.id == id)
                {
                    return data.sprite_Path;
                }
        }

        return "none";
    }


    #region 单例
    private static ItemsInfo _instance;
    public static ItemsInfo getInstance()
    {
        return _instance;
    }
    #endregion


    // Use this for initialization
    void Awake () {
        _instance = this;

        //药品信息的读取
        Drug = LoadJson<DrugData>.LoadJsonFromFile("DrugData");
        //ReadTest_Drug(Drug);

        //技能信息的读取
        Skill = LoadJson<SkillData>.LoadJsonFromFile("SkillData");
        //ReadTest_Skill(Skill);

    }//end Start

}

前面的药品数据类DrugData,普通物品数据类OtherData,装备物品类EquipData,技能物品类SkillData,是为了存储Json文件和读取Json文件的结构类,这4个,只需要看DrugData就行,其他3个不用管。
LoadJson这个类是读取Json文件所封装的类,能够读取Json文件。
那我们怎么存储文件呢?Json是有一定格式的,请往下看Json文件的例子。

DrugData.json

{
"dataType":"Drug",
"Drugs":
    [
     {
         "id": 1, 
         "drugName":"小瓶红药水",
         "sprite_Path": "Atlas/UI2/icon-potion1",
         "prefeb_Path":"None",
         "introduce":"补充少量的HP值",
         "bloodAdd":50,
         "magicAdd":0
     },
     {
         "id": 2, 
         "drugName":"大瓶红药水",
         "sprite_Path": "Atlas/UI2/icon-potion2",
         "prefeb_Path":"None",
         "introduce":"补充大量的HP值",
         "bloodAdd":100,
         "magicAdd":0
     },
     {
         "id": 3,
         "drugName":"小瓶蓝药水",
         "sprite_Path": "Atlas/UI2/icon-potion3",
         "prefeb_Path":"None",
         "introduce":"ֵ补充少量的MP值",
         "bloodAdd":0,
         "magicAdd":50
     }
    ] 
}

可能有一些东西没说好,如果有不明白的地方,可以直接提问,我看到了会回复。但有些不懂的地方也还请体谅,我也是菜鸟~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值