Unity中保存数据的方法

devtools/2024/9/24 7:16:03/

一、概述

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:

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对象上

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 updatevoid 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 framevoid Update(){}
}

配置Panel的BulletData对象的值

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

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: objectToOverwritbulletData = 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面板中进行数据的配置与调试,有的时候是更加方便的,并且可以达到数据复用的目的,减少内存消耗。但是它无法在游戏打包发布后将数据的变动存储到磁盘中。


http://www.ppmy.cn/devtools/104290.html

相关文章

《PCI Express体系结构导读》随记 —— 第II篇 第7章 PCIe总线的数据链路层与物理层(2)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第II篇 第7章 PCIe总线的数据链路层与物理层&#xff08;1&#xff09; 7.1 数据链路层的组成结构 数据链路层使用ACK/NAK协议发送和接收TLP&#xff0c;由发送部件和接收部件组成。其中&#xff0c;发送部件由…

C语言补习课

来源&#xff1a;黑马程序员 C语言常用占位符 1.%d 或 %i&#xff1a;用于输出有符号整数&#xff08;int&#xff09;。 2.%u&#xff1a;用于输出无符号整数&#xff08;unsigned int&#xff09;。 3.%f&#xff1a;用于输出浮点数&#xff08;float或double&#xff09…

【ubuntu使用笔记】Ubuntu Desktop 访问SMB共享文件夹

Ubuntu Desktop 访问SMB共享文件夹 Ubuntu Desktop 访问SMB共享文件夹文件夹打开 file managerother location输入 IP地址&#xff0c;smb://IP点击connect按钮正常进入 命令行安装客户端连接 Ubuntu Desktop 访问SMB共享文件夹 文件夹 打开 file manager other location 输入…

Spring Boot如何解决跨域问题?

1.什么是跨域&#xff1f; 跨域请求&#xff0c;就是说浏览器在执行脚本文件的ajax请求时&#xff0c;脚本文件所在的服务地址和请求的服务地址不一样。说白了就是ip、网络协议、端口都一样的时候&#xff0c;就是同一个域&#xff0c;否则就是跨域。这是由于Netscape提出一个…

【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)

看到这句话的时候证明&#xff1a;此刻你我都在努力 加油陌生人 个人主页&#xff1a;Gu Gu Study 专栏&#xff1a;用Java学习数据结构系列 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 作者&#xff…

LLaMA-Factory微调入门个人重制版

LLaMA-Factory微调入门个人重制版 说明&#xff1a; 首次发表日期&#xff1a;2024-08-30LLaMA-Factory 官方Github仓库&#xff1a; https://github.com/hiyouga/LLaMA-Factory 关于 本文是对LLaMA-Factory入门教程 https://zhuanlan.zhihu.com/p/695287607 的个人重制版&…

Codeforces Round 967 (Div. 2)(A,B,C,D)

A Make All Equal 题意 给定一个序列,每次如果a[i]<a[i1]则可以删除这两个的任意一个,问找出使a中所有元素相等所需的最小删除次数 思路 最小的删除次数就是保留相同数字最多的那个数的删除次数,无论如何都可以保留这个数,因为假如是3334那么可以根据3和4把4删了,假如是3…

c++算法第一天

温馨提示&#xff1a;本篇文章适合刚开始练算法的小白&#xff0c;大佬若见勿嘲 、 题目 核心提取 1.所有的0移动到数组末尾 2.不能复制数组 解题思路 遇到0,cur,非0则先dest1,再交换&#xff0c;最后cur。 代码编写 温馨提示&#xff1a;这里的指针可以使用下标代替 …