Unity中保存数据的方法

一、概述

Unity中可用于持久化的方式有:

1)通过ScriptableObject在可编辑模式下保存数据

2)通过excel、json等文件实现数据的可持久化

二、ScriptableObject的使用

1、使用背景

假如需要制作子弹预设体,每个子弹上有speed速度和damage伤害力的参数。

按照现有的方法,这两个参数设置为public或者SerializedField private的属性,那么就可以在Inspector界面中配置两个参数的具体值。

当游戏运行的时候,每生成一个实例都会复制一份这个数据,实际上复制的都是同一份数据,这样就造成了内存的浪费。

通过ScriptableObject方法可以实现编辑模式下的数据存储,针对这种复制同一份数据的情况,比excel、json等更加方便。

2、ScritableObject介绍

2.1 定义

1)ScriptableObject是Unity的一个数据配置存储基类 ,类似于MonoBehaviour的基类,继承自UnityEngine.Object。它是一个可以用来保存大量数据的数据容器 ,实例化后可以将它保存为自定义的数据资源文件。

2)ScriptableObject本身是一个类,ScriptableObject实例化后被保存为.asset资源文件,和预设体、材质球、音频文件等类似,存放在Assets文件夹下。

2.2 作用

1)编辑模式下的数据持久化

编辑模式下会保存数据,但是游戏运行时修改ScriptableObject的数据是不会保存到本地的,重新打开运行时数据还是配置的的初始数据。

2)配置文件(配置游戏中的数据)

配置文件的数据在游戏发布前定义好规则,运行时只会读出使用而不会修改数据的内容。传统配置文件是放在xml、json、excel等里面,ScriptableObject直接在Inspector中进行配置更加方便。

3)数据复用(多个对象共用一套数据)

三、使用示例

1、效果

unity配置:

2、创建ScriptableObject类的BulletData.cs:

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName ="BulletData", menuName ="ScritableObject/子弹数据")]
public class BulletData : ScriptableObject
{
    public int speed;
    public int damage;
}

fileName表示数据资源文件创建出来的文件名

menuName表示在Assets/Create下的名字

创建后命名为BulletData,并放在Assets/ScriptableObject目录下,并配置speed和damage的值。

3、创建PanelOperator.cs文件,并挂载到Panel对象上

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class PanelOperator : MonoBehaviour
{
    public BulletData bulletData;
    // Start is called before the first frame update
    void Start()
    {
        this.transform.Find("SpeedInfo").GetComponent<Text>().text = bulletData.speed.ToString();
        this.transform.Find("DamageInfo").GetComponent<Text>().text = bulletData.damage.ToString(); 
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

配置Panel的BulletData对象的值

4、编写Button的操作类ButtonOperator.cs并挂载到ButtonOperator上

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;

public class ButtonOperator : MonoBehaviour
{
    public Text speedText;
    public Text damageText;
    public BulletData bulletData;

    public void addSpeed()
    {
        int currentValue = int.Parse(speedText.text);
        currentValue += 1;
        speedText.text = currentValue.ToString(); 
    }

    public void addDamage()
    {
        int currentValue = int.Parse(damageText.text);
        currentValue += 1;
        damageText.text = currentValue.ToString();
    }

    public void storeData()
    {
        bulletData = ScriptableObject.CreateInstance<BulletData>();
        bulletData.speed = int.Parse(speedText.text);
        bulletData.damage = int.Parse(damageText.text);

        string dataStr = JsonUtility.ToJson(bulletData);
        Debug.Log(Application.streamingAssetsPath);
        // 一定要在Assets下创建StreamingAssets目录
        File.WriteAllText(Application.streamingAssetsPath + "/testJson.json", dataStr); 
    }

    public void recoverData()
    {
        string dataStr = File.ReadAllText(Application.streamingAssetsPath + "/testJson.json");
        Debug.Log(dataStr);
        // 否则报错:ArgumentNullException: Value cannot be null Parameter name: objectToOverwrit
        bulletData = ScriptableObject.CreateInstance<BulletData>();  
        JsonUtility.FromJsonOverwrite(dataStr, bulletData); 
        speedText.text = bulletData.speed.ToString();
        damageText.text = bulletData.damage.ToString(); 
    }
}

然后配置SpeedButton、DamageButton、Store、Recover的事件。

配置ButtonOperator的参数如下:

5、JSON持久化解读

5.1 保存数据

bulletData = ScriptableObject.CreateInstance<BulletData>();
bulletData.speed = int.Parse(speedText.text);
bulletData.damage = int.Parse(damageText.text);

string dataStr = JsonUtility.ToJson(bulletData);
Debug.Log(Application.streamingAssetsPath);
File.WriteAllText(Application.streamingAssetsPath + "/testJson.json", dataStr);

如果保存在Application.streamingAssetsPath路径下,一定要在Assets下创建StreamingAssets目录。

5.2 读取数据

string dataStr = File.ReadAllText(Application.streamingAssetsPath + "/testJson.json");

Debug.Log(dataStr);

bulletData = ScriptableObject.CreateInstance<BulletData>();

JsonUtility.FromJsonOverwrite(dataStr, bulletData);

speedText.text = bulletData.speed.ToString();

damageText.text = bulletData.damage.ToString();

如果使用FromJsonOverwrite把数据保存到类的实例中,一定要确保类已经实例化了。否则会报错:"ArgumentNullException: Value cannot be null Parameter name: objectToOverwrite"。

6、生成ScriptableObject非持久化数据

利用ScriptableObject类的静态方法CreateInstance<>()可以生成非持久化的数据,此时相当于BulletData继承于MonoBehaviour时的效果。使得ScriptableObject的类做到了两种用法。

该方法可以在运行时创建出指定继承自ScriptableObject的对象,该对象只存在于内存中,可以被GC垃圾回收,调用依次就创建一次。

方法见:bulletData = ScriptableObject.CreateInstance<BulletData>();

四、总结

对于只用不变的数据,就是和用ScriptableObject做数据配置文件,再加上编辑模式下实现数据持久化的特点,我们可以在Inspector面板中进行数据的配置与调试,有的时候是更加方便的,并且可以达到数据复用的目的,减少内存消耗。但是它无法在游戏打包发布后将数据的变动存储到磁盘中。

相关推荐
辻弋2013 天前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑
Martina_03214 天前
AI生成3D场景导入 Unity/Unreal 后,NPC 总串层?用6步检查导航高度与跨层连接
人工智能·游戏·数学建模·3d·unity·自然语言处理·aigc
小贺儿开发4 天前
Unity 局域网遥控幻灯片展示工具 3.0
科技·http·unity·工具·ppt·通信·网页
WarPigs6 天前
Unity对象不应该使用null传播的问题
unity
每日出拳老爷子7 天前
【VR】【Unity】抓走转放系列21|一天搭完门和抽屉工具槽:小场景按这个次序拼装
unity·vr·驱动·排错·snap zone
淡海水8 天前
02-02-原理篇-分代GC
算法·unity·c#·游戏引擎·.net·gc
小贺儿开发8 天前
Unity 文物新生 会讲故事的文物展墙
人工智能·科技·unity·ai·视频·互动·演示
淡海水8 天前
02-03-原理篇-大对象堆
unity·c#·游戏引擎·.net·gc
WarPigs9 天前
Unity在Create菜单添加创建自定义脚本模板选项
unity
郝学胜-神的一滴9 天前
C++ Templates 01:拨开迷雾,读懂C++模板经典著作
开发语言·c++·程序人生·游戏·游戏引擎·软件构建