Unity游戏保存踩坑记录(含Excel和Json格式)

应用场景

做了个RPG游戏,但是道具表如果建在脚本里,不方便调整,需要Excel表来统一调整记录
但是我又已经在脚本里面写了很多道具了,这样我如果重新建excel表,还得重填一遍,于是就做个自动保存excel表的方法

保存成Excel文件

public void ItemSaveToExcle(string i)
    {
        Debug.Log("保存道具个数:" + ItemManager.instance.AllItems.Count);
        // 创建一个Excel文件
        using (var package = new ExcelPackage())
        {
            Debug.Log("保存excle");
            ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("道具表");
            // 将List<Item>中的数据写入Excel表中
            worksheet.Cells[1, 1].Value = "物品编号";
            worksheet.Cells[1, 2].Value = "物品名称";
            worksheet.Cells[1, 3].Value = "品质";
            //.......这里就一行行填命名,方便理解的,写啥都行
            int row = 2;
            foreach (Item item in ItemManager.instance.AllItems)
            {
                    Debug.Log("保存:" + item.Iname);
                    worksheet.Cells[row, 1].Value = item.ItemID;
                    worksheet.Cells[row, 2].Value = item.Iname;
                    //....这里就一格格记录一个属性
                    row++;
            }
            
            // 保存Excel文件
            string filePath = Path.Combine(Application.streamingAssetsPath, i+".xlsx");
            FileInfo file = new FileInfo(filePath);
            package.SaveAs(file);
        }
    }

读取Excel文件(需要有EEPL)

   //读取excel表
    public void ItemLoadFormExcle()
    {
        bool isAndor = true;
        switch (Application.platform)
        {
            case RuntimePlatform.WindowsEditor:
                isAndor = false;
                break;

            case RuntimePlatform.Android:
                isAndor = true;
                break;
        }
        string filePath;
        //如果是安卓,这里区分安卓的原因,是挣扎了一下手机读取excle,发现确实读不了
        if (isAndor)
        {
            filePath = Path.Combine(Application.persistentDataPath, "Item.xlsx");
        }
        else
        {
            filePath = Path.Combine(Application.streamingAssetsPath, "Item.xlsx");
        }
        Debug.Log(filePath);
        FileInfo file = new FileInfo(filePath);
        using (ExcelPackage package = new ExcelPackage(file))
        {
            //读取第一张表
            ExcelWorksheet worksheet = package.Workbook.Worksheets["item"];
            int rowCount = worksheet.Dimension.Rows;

            List<Item> items = new List<Item>();
            for (int row = 2; row <= rowCount; row++)
            {
                //Debug.Log("读取:" + row + "这行");
                if (worksheet.Cells[row, 1].Value == null)
                {
                    continue;
                }
                else
                {
                    Item item = new Item();
                    item.ItemID = worksheet.Cells[row, 1].GetValue<int>();
                    item.Iname = worksheet.Cells[row, 2].Value.ToString();
                    //...把属性一行行地赋给新物品
                    //新物品加入道具表
                    items.Add(item);
                }
                
            }
            //把我们原有的道具表清空,赋值新道具表即可
            ItemManager.instance.AllItems.Clear();
            ItemManager.instance.AllItems = items;
        }
    }

保存为Json文件

    //保存
    public void Save()
    {
        物品整型数据 = new List<int>();
        物品字符数据 = new List<string>();
        foreach (Item i in AllItems)
        {
            // 物品整型数据
            物品整型数据.Add(i.ItemID);
            物品整型数据.Add(i.品质);
            物品整型数据.Add(i.抗药性);
            物品整型数据.Add(i.可以使用 ? 1 : 0);
            物品整型数据.Add(i.使用等级);
            物品整型数据.Add(i.技艺要求数值);
            物品整型数据.Add(i.精力消耗);
            物品整型数据.Add(i.奖励帝具id);
            物品整型数据.Add(i.奖励物品id);
            物品整型数据.Add(i.普通物品id);
            物品整型数据.Add(i.技能id);
            物品整型数据.Add(i.可以售卖 ? 1 : 0);
            物品整型数据.Add(i.是否用钻 ? 1 : 0);
            物品整型数据.Add(i.售价);
            物品整型数据.Add(i.已经卖出 ? 1 : 0);
            物品整型数据.Add(i.星级);

            物品整型数据.Add((int)(i.属性要求1数值*100));
            物品整型数据.Add((int)(i.属性要求2数值 * 100));
            物品整型数据.Add((int)(i.属性惩罚数值 * 100));
            物品整型数据.Add((int)(i.属性惩罚百分比 * 100));
            物品整型数据.Add((int)(i.属性奖励数值 * 100));
            物品整型数据.Add((int)(i.属性奖励百分比 * 100));
            物品整型数据.Add((int)(i.资源奖励数值 * 100));
            物品整型数据.Add((int)(i.资源奖励百分比 * 100));
            物品整型数据.Add((int)(i.资源惩罚数值 * 100));
            物品整型数据.Add((int)(i.资源惩罚百分比 * 100));
            物品整型数据.Add((int)(i.赌狗概率 * 100));
            物品整型数据.Add((int)(i.临时属性惩罚数值 * 100));
            物品整型数据.Add((int)(i.临时属性惩罚百分比 * 100));
            物品整型数据.Add((int)(i.临时属性奖励数值 * 100));
            物品整型数据.Add((int)(i.临时属性奖励百分比 * 100));
            物品整型数据.Add((int)(i.吸血率 * 100));
            物品整型数据.Add((int)(i.反伤率 * 100));
            物品整型数据.Add((int)(i.回复率 * 100));
            物品整型数据.Add((int)(i.爆宝率 * 100));
            物品整型数据.Add((int)(i.免伤率 * 100));


            // 物品字符数据
            物品字符数据.Add(i.属性要求1.ToString());
            物品字符数据.Add(i.属性要求2.ToString());
            物品字符数据.Add(i.技艺要求.ToString());
            物品字符数据.Add(i.属性惩罚.ToString());
            物品字符数据.Add(i.属性奖励.ToString());
            物品字符数据.Add(i.资源奖励.ToString());
            物品字符数据.Add(i.资源惩罚.ToString());
            物品字符数据.Add(i.道具类型.ToString());
            物品字符数据.Add(i.资源属性.ToString());
            物品字符数据.Add(i.Iname);
            物品字符数据.Add(i.物品描述);
            物品字符数据.Add(i.使用效果);
        }
        //保存方法
        GameManager.instance.Save(物品整型数据, "/AllitemInt.json");
        GameManager.instance.Save(物品字符数据, "/AllitemString.json");
    }
    using System.Collections.Generic;
	using System.Collections;
	using UnityEngine;
	using UnityEngine.UI;
	using LitJson;
	using System.IO;
	using System;
	using UnityEngine.EventSystems;
	using UnityEngine.Networking;
        public void Save<T> (T t,string path)
    {
        bool isAndor = true;
        switch (Application.platform)
        {
            case RuntimePlatform.WindowsEditor:
                isAndor = false;
                break;

            case RuntimePlatform.Android:
                isAndor = true;
                break;
        }
        if(isAndor)
        {
            string filePath = Application.persistentDataPath + path;//persistentDataPath
            //把剧本转成json字符串
            string saveJsonstr = JsonMapper.ToJson(t);
            //新建一个StreamWiter文件,路径按照上面路径固定住
            StreamWriter sw = new StreamWriter(filePath);
            //写入json字符串
            sw.Write(saveJsonstr);
            //关闭
            sw.Close();
        }
        else
        {
            string filePath = Application.streamingAssetsPath + path;//persistentDataPath
            //把剧本转成json字符串
            string saveJsonstr = JsonMapper.ToJson(t);
            //新建一个StreamWiter文件,路径按照上面路径固定住
            StreamWriter sw = new StreamWriter(filePath);
            //写入json字符串
            sw.Write(saveJsonstr);
            //关闭
            sw.Close();
        }
    }

这个方法就是典型的因为用了float导致我一个个保存,中间还得数自己漏了哪几个,还要转换类型等等,非常麻烦,一个东西就写了一晚上,我的Skill设计是只有int和string的,保存起来非常舒服

加载Json文件

public void Load()
    {
        AllItems.Clear();
        物品整型数据 = GameManager.instance.Load(物品整型数据, "/AllitemInt.json");
        //Debug.Log("整型数目:"+物品整型数据.Count);
        物品字符数据 = GameManager.instance.Load(物品字符数据, "/AllitemString.json");
        //Debug.Log("字符数目:" + 物品字符数据.Count);
        for (int i = 0; i < 物品整型数据.Count/36; i++)
        {
            Item item = new Item();
            item.ItemID = 物品整型数据[i*36 + 0];
            item.品质 = 物品整型数据[1 + i*36];
            item.抗药性 = 物品整型数据[2 + i*36];
            item.可以使用 = 物品整型数据[3 + i*36] == 1;
            item.使用等级 = 物品整型数据[4 + i*36];
            item.技艺要求数值 = 物品整型数据[5 + i*36];
            item.精力消耗 = 物品整型数据[6 + i*36];
            item.奖励帝具id = 物品整型数据[7 + i*36];
            item.奖励物品id = 物品整型数据[8 + i*36];
            item.普通物品id = 物品整型数据[9 + i*36];
            item.技能id = 物品整型数据[10 + i*36];
            item.可以售卖 = 物品整型数据[11 + i*36] == 1;
            item.是否用钻 = 物品整型数据[12 + i*36] == 1;
            item.售价 = 物品整型数据[13 + i*36];
            item.已经卖出 = 物品整型数据[14 + i*36] == 1;
            item.星级 = 物品整型数据[15 + i*36];
            item.属性要求1数值 = 物品整型数据[16 + i*36] / 100f;
            item.属性要求2数值 = 物品整型数据[17 + i*36] / 100f;
            item.属性惩罚数值 = 物品整型数据[18 + i*36] / 100f;
            item.属性惩罚百分比 = 物品整型数据[19 + i*36] / 100f;
            item.属性奖励数值 = 物品整型数据[20 + i*36] / 100f;
            item.属性奖励百分比 = 物品整型数据[21 + i*36] / 100f;
            item.资源奖励数值 = 物品整型数据[22 + i*36] / 100f;
            item.资源奖励百分比 = 物品整型数据[23 + i*36] / 100f;
            item.资源惩罚数值 = 物品整型数据[24 + i*36] / 100f;
            item.资源惩罚百分比 = 物品整型数据[25 + i*36] / 100f;
            item.赌狗概率 = 物品整型数据[26 + i*36] / 100f;
            item.临时属性惩罚数值 = 物品整型数据[27 + i*36];
            item.临时属性惩罚百分比 = 物品整型数据[28 + i*36];
            item.临时属性奖励数值 = 物品整型数据[29 + i*36];
            item.临时属性奖励百分比 = 物品整型数据[30 + i*36];
            item.吸血率 = 物品整型数据[31 + i*36];
            item.反伤率 = 物品整型数据[32 + i*36];
            item.回复率 = 物品整型数据[33+i*36];
            item.免伤率= 物品整型数据[34 + i*36];
            item.爆宝率= 物品整型数据[35 + i*36];
            //Debug.Log("读取道具:" + 物品字符数据[9 + i * 12]);
            item.属性要求1 = (PlayerNumber)System.Enum.Parse(typeof(PlayerNumber), 物品字符数据[0+i * 12]);
            item.属性要求2 = (PlayerNumber)System.Enum.Parse(typeof(PlayerNumber), 物品字符数据[1+ i * 12]);
            item.技艺要求 = (GameNumeber)System.Enum.Parse(typeof(GameNumeber), 物品字符数据[2+ i * 12]);

            item.属性惩罚 = (PlayerNumber)System.Enum.Parse(typeof(PlayerNumber), 物品字符数据[3+ i * 12]);
            item.属性奖励 = (PlayerNumber)System.Enum.Parse(typeof(PlayerNumber), 物品字符数据[4+ i * 12]);
            item.资源奖励 = (GameNumeber)System.Enum.Parse(typeof(GameNumeber), 物品字符数据[5+ i * 12]);

            item.资源惩罚 = (GameNumeber)System.Enum.Parse(typeof(GameNumeber), 物品字符数据[6+ i * 12]);
            item.道具类型 = (Items)System.Enum.Parse(typeof(Items), 物品字符数据[7+ i * 12]);
            item.资源属性 = (ItemType)System.Enum.Parse(typeof(ItemType), 物品字符数据[8+ i * 12]);
            
            item.Iname = 物品字符数据[9+ i * 12];
            item.物品描述 = 物品字符数据[10+ i * 12];
            item.使用效果 = 物品字符数据[11+ i * 12];
            AllItems.Add(item);
        }

    public T Load<T>(T t,string path)
    {
        bool isAndor = true;
        switch (Application.platform)
        {
            case RuntimePlatform.WindowsEditor:
                isAndor = false;
                break;

            case RuntimePlatform.Android:
                isAndor = true;
                break;
        }
        if (isAndor)
        {
            string filePath = Application.persistentDataPath + path;
            if (File.Exists(filePath))
            {
                StreamReader sr = new StreamReader(filePath);
                string jsonStr = sr.ReadToEnd();
                sr.Close();
                t = JsonMapper.ToObject<T>(jsonStr);
            }
            if (t == null)
                Debug.Log("读取失败,失败的读取物是:" + t.ToString());
            return t;
        }
        else
        {
            string filePath = Application.streamingAssetsPath + path;
            if (File.Exists(filePath))
            {
                StreamReader sr = new StreamReader(filePath);
                string jsonStr = sr.ReadToEnd();
                sr.Close();
                t = JsonMapper.ToObject<T>(jsonStr);
            }
            if (t == null)
                Debug.Log("读取失败,失败的读取物是:" + t.ToString());
            return t;
        }

    }

一个问题,保存,读取都非常麻烦,以后再做这个,直接就跳过float去保存,不然这么一个个处理,太麻烦了

心得总结

1.安卓和PC不同,PC能读取excel的方法在安卓不一定适用,目前在安卓上,没有发现可以读取excel的方法(尝试了许多,都读取失败了),还是得老老实实Json,不过可以写个PC读取Excel的方法来加快策划速度,如果是做PC端的话,可以支持读写
2.保存Json的时候,最好把数据类型定在int,bool,string这几个里面,千万千万不要使用float,否则没法保存,得一个个存,很麻烦,最好在设定的时候就改好,自定义属性用int去代替,再用方法替换,float就直接放大1000倍来处理,例如暴击率就别保存成0.01f,直接保存成10或者1,到时写个方法处理一下就行了
3.保存的时候注意方法:Application.persistentDataPath(安卓:仅可读)和Application.streamingAssetsPath(电脑:可读可写) ,后者电脑可用,可以读写,但是安卓不能用,安卓用前者,只可读不可写(但是一般手机端也不太需要写)

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值