Unity 之 Scriptable Objects 更直观的序列化

article/2025/11/10 16:46:49

在日常开发中总会在Inspector面板中填写一些序列化信息,如:名称、血量、或者秘钥序列号等(图一)。但看似方便,还是有些缺点的,例如填写的序列化信息不能共享,如果在prefab上对应的脚本丢失,填写的信息也随之丢失。如果需要填写的信息特别多,这绝对是个灾难。

vuforia的SDK 7版本相对于6版本最直观的改进就是原来的配置文件改成了Scriptable Objects。

img_378b9968079bfd8f4539af4b4298edcd.png
图一

而且在【UWA DAY 2018 张鑫大佬 提到过】,使用Scriptable Objects可显著的减少内存的占用,其中的示例是这样的:每个prefab上有1000个public int 变量,实例化100个Prefab ,在红米2中的数据,常规情况下为: 耗时38.44ms 堆内存391.8KB,然后我们使用 Scriptable Objects后对应的数据为,耗时:10.76ms,堆内存1.6KB,耗时占用为原来的 28%,堆内存占用为原来的 0.4%(效果还是很可观的)。


有说的错误或者不准确的地方欢迎留言指正


下面笔者就和大家聊一聊 Scriptable Objects

首先放出官方连接

https://unity3d.com/cn/learn/tutorials/modules/beginner/live-training-archive/scriptable-objects?playlist=17117
https://unity3d.com/cn/learn/tutorials/topics/scripting/ability-system-scriptable-objects?playlist=17117
https://unity3d.com/cn/learn/tutorials/topics/scripting/character-select-system-scriptable-objects?playlist=17117

还有一篇是国内开发者的文章【貌似是冯乐乐,shader入门精要的作者】

https://blog.csdn.net/candycat1992/article/details/52181814

如想更深入了解的Scriptable Objects 可以去Unity在YouTube 的官方网站(自备梯子),里面有几个视频讲解的很详细,不过语速过快,笔者本人已经放弃


要是使用 Scriptable Objects ,首先需要准备一个模板,然后根据指定的模板创建Scriptable Objects。

#region using
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
#endregionpublic class PlayerDataScriptableObject : ScriptableObject
{[Header("玩家 ID")]public int playerId;[Header("玩家 分数")]public float playerScore;[Header("玩家 名称")]public string playerName;[Header("玩家 地址")]public string playerAddress;[Header("玩家 随机出生点")]public Vector3[] playerSpawnPoint;[Header("玩家 描述列表")]public List<Description> playerDescription = new List<Description>();}[Serializable]
public class Description
{public string descriptionOne;public string descriptionTwo;
}

注意:PlayerDataScriptableObject 继承ScriptableObject,非传统的MonoBehaviour。Description类需要添加[Serializable]特性,这个PlayerDataScriptableObject 是无法直接拖拽到Prefab等Object物体上的

模板已经创建好,下面我们介绍两种创建 ScriptableObject的方式

第一种

在Editor文件夹中创建ScriptableObjectUtility脚本

using UnityEngine;
using UnityEditor;
using System.IO;public static class ScriptableObjectUtility
{public static void CreateAsset<T>() where T : ScriptableObject{T asset = ScriptableObject.CreateInstance<T>();string path = AssetDatabase.GetAssetPath(Selection.activeObject);if (path == ""){path = "Assets";}else if (Path.GetExtension(path) != ""){path = path.Replace(Path.GetFileName(AssetDatabase.GetAssetPath(Selection.activeObject)), "");}string assetPathAndName = AssetDatabase.GenerateUniqueAssetPath(path + "/New " + typeof(T).ToString() + ".asset");AssetDatabase.CreateAsset(asset, assetPathAndName);AssetDatabase.SaveAssets();AssetDatabase.Refresh();EditorUtility.FocusProjectWindow();Selection.activeObject = asset;}
}public class CreateClassAsset
{[MenuItem("Assets/Create/Su9257/ScriptableObject")]public static void CreateAsset(){ScriptableObjectUtility.CreateAsset<PlayerDataScriptableObject>();}}
img_eb033f102753e30fd6ea4393a8f9b360.png
img_f63f2ba5edb983fd9260a6e7711132c3.png
第二种 相对比较快捷

直接在对应的模板类上添加CreateAssetMenu特性

img_5d47c6716a438400fef1da97e724d473.png
img_2672069062105ed93a11aad6389578f4.gif

注意:创建的模板类名称要与对应的脚本名称保持一致


上面我们已经创建完对应的ScriptableObject文件,接下来是我们如何使用

创建测试脚本PlayGame 放到任意场景物体上
public class PlayGame : MonoBehaviour
{public PlayerDataScriptableObject playerDataScriptableObject;void Start(){}void Update(){if (Input.GetMouseButtonDown(0)){++playerDataScriptableObject.playerScore;}}
}
img_44e50dede958ebc3ec6412c479524cd3.gif

然后我们运行,会发现这个.asset序列化文件的好处,在运行模式下产生的数据不会因为退出运行而消失,同一个模板类产生的两个.asset文件不会产生数据干扰,相互独立

img_63e6fc86159ab43cc2849d7d4b96f557.gif

什么?不想拖拖拽拽?有办法!

把对应的.asset放到Resources文件夹下调用Start方法中的code就可以了(Assetbundle的加载目前还没测试)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayGame : MonoBehaviour
{public PlayerDataScriptableObject playerDataScriptableObject;void Start(){playerDataScriptableObject = (Resources.Load<PlayerDataScriptableObject>("New PlayerDataScriptableObject"));//克隆的,运行结束时数据也随之消失,换句话就是和原来的New PlayerDataScriptableObject的序列化文件没什么关系了//playerDataScriptableObject = Instantiate(Resources.Load<PlayerDataScriptableObject>("New PlayerDataScriptableObject"));}void Update(){if (Input.GetMouseButtonDown(0)){++playerDataScriptableObject.playerScore;}}
}

这时有一个疑问?这玩应难道仅仅就服务于属性、字段?答案当然不是,ScriptableObject官方文档中都有对应额回调函数,起码也能支持咱们自己写的函数吧~

然后我们把原来的模板稍加改动,改成抽象类然后添加一个抽象方法Attack;,当然,我们的创建方法也需要稍加改动一下。然后调用Attack

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "TestPlayerDataOne", menuName = "Su9257/PlayerDataOne", order = 100)]
public class PlayerDataOne : PlayerDataScriptableObject {public override void Attack(){Debug.Log($"玩家{playerName}进行了攻击");}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class PlayGame : MonoBehaviour
{public PlayerDataScriptableObject playerDataScriptableObject;void Update(){if (Input.GetMouseButtonDown(0)){++playerDataScriptableObject.playerScore;}if (Input.GetKeyDown(KeyCode.Alpha1)){playerDataScriptableObject.Attack();}}
}
img_5363f1b695c8c93d75fd45ac0e19eb4f.gif

在实际游戏开发中,我们会设置游戏的难度,简单、困难之类的,里面需要配置的东西非常的多,根据这个特点,我们可以根据不同的难度级别配置不同的 .asset序列化文件,用法和这个Attack的用法如出一辙。《炉石传说》对应的配置文件就用过这玩应

最后总结一下优缺点

优点:

  • 可以保存为assets文件
  • 可以在运行时保存
  • 可以引用而不是像MonoBehaviour那样复制
  • 性能非常快
  • 适合插槽式设计,即插即用

缺点:

  • 需要额外的编辑脚本
  • 无法在Unity外编辑

最后,欢迎大家留言补充,非常感谢!!!


http://chatgpt.dhexx.cn/article/pIrQV2ni.shtml

相关文章

Unity Shader入门精要学习笔记 - 第17章 Unity的表面着色器探秘

转自 冯乐乐的《Unity Shader 入门精要》 2010年的Unity 3 中&#xff0c;Surface Shader 出现了。 表面着色器的一个例子。 我们先做如下准备工作。 1&#xff09;新建一个场景&#xff0c;去掉天空盒子 2&#xff09;新建一个材质&#xff0c;新建一个Shader&#xff0c…

从图形渲染管线谈游戏性能优化

从图形渲染管线谈性能优化 最近做一个3D场景类项目&#xff0c;其中涉及到各种建筑模型、植物模型、地形等等。画面效果还不错&#xff1b;可是运行起来&#xff0c;那性能啊&#xff0c;没得玩。索性尝试了各种优化手段&#xff0c;这里简单和大家分享一下。当然&#xff0c;在…

《Unity Shader入门精要》笔记01 前言

《Unity Shader入门精要》笔记01 前言 ——本系列是基于人民邮电出版社《Unity Shader入门精要》&#xff08;冯乐乐著 &#xff09;的自学Unity Shader笔记&#xff0c;如果您发现了本文的纰漏&#xff0c;还望不吝指正。 写在前边 本书旨在从基础开始&#xff0c;帮助读者逐…

unity学习-shader(一)

渲染流水线 1 CPU流水线2 GPU流水线2.1 顶点着色器2.2 剪裁2.3 屏幕映射2.4 三角形设置2.5 三角形遍历2.6 片元着色器2.7 逐片元操作 应用阶段 需要准备好场景数据&#xff0c;比如摄像机、模型、光源等。需要再这里做粗粒度剔除&#xff08;culling&#xff09;工作&#xff0…

Unity Shader入门精要--第4 章 学习Shader 所需的数学基础:矩阵

Unity系列文章目录 文章目录 Unity系列文章目录前言4.4.3 矩阵运算4.4.4 特殊的矩阵2&#xff0e;单位矩阵 参考 前言 不幸的是&#xff0c;没有人能告诉你母体&#xff08;matrix&#xff09;究竟是什么。你需要自己去发现它。 —电影《黑客帝国》&#xff08;英文名&#xf…

【转】《Unity Shader入门精要》冯乐乐著 书中彩图

为方便个人手机学习时候查阅,从网上转来这些彩图。 如属过当行为&#xff0c;联系本人删除。 勘错表 http://candycat1992.github.io/unity_shaders_book/unity_shaders_book_corrigenda.html 转自:http://candycat1992.github.io/unity_shaders_book/unity_shaders_book_image…

【转】《Unity Shader入门精要》冯乐乐 随书彩图

绕了好多圈子终于还是沉下心来好好看这本书了… 以下是原项目GitHub中分享的随书彩图 学习的时候看到色彩丰富的东西会心情更好咯 原项目GitHub链接 前言 第2章 渲染流水线 图2.1 真实生活中的流水线 图2.2 渲染流水线中的三个概念阶段 图2.3 渲染所需的数据&#xff08…

《Unity Shader入门精要》冯乐乐著 书中彩图

为方便个人手机学习时候查阅,从网上转来这些彩图&#xff0c;然后整合所有资料。 如属过当行为&#xff0c;联系本人删除。 勘错表 http://candycat1992.github.io/unity_shaders_book/unity_shaders_book_corrigenda.html 前言 第2章 渲染流水线 图2.1 真实生活中的流水线…

冯乐乐之二 shader的数学

冯乐乐目录 第2章渲染流水线介绍 第三章 Unity shader基础 基础shaderLab语言&#xff0c;shader结构&#xff0c;属性properties&#xff0c;主角SubShader&#xff0c;备胎Fallback。 shader三大类型&#xff1a; Unity宠儿表面着色器&#xff0c;聪明boy顶点片元着色器…

各大浏览器清除缓存(cache)详细步骤

1. Firefox 1.1 选择“Options”&#xff1a; 1.2 选择“Advanced”->“Network”->“Cached Web Content”&#xff0c;点击“Clear Now”&#xff1a; 2. Chrome 2.1 选择“Settings”&#xff1a; 2.2 点击页面底部“Show advanced settings”&#xff1a; 2.3 选择…

浏览器如何清除缓存教程

打开浏览器—设置—隐私设置—清除浏览器数据

清除浏览器的缓存

第一种方法 在浏览器界面按F12之后,再选择Network,选中Disable cache, 然后刷新(这里有个玄学的问题就是即使你已经选中了Disable cache, 也需要打开network这个页面再刷新才有效, 亲测有效, 但是我也不知道为什么) 第二种方法 在浏览器界面直接Ctrl Shift R 比较方便,但…

Edge浏览器如何清除缓存

浏览器在使用过程中会产生大量的缓存&#xff0c;Edge浏览器如何清理缓存&#xff1f;下面是Edge浏览器清理缓存的操作步骤。 1.双击Edge图标打开Edge浏览器。 2.单击右Edge浏览器上角的“更多操作”。 3.弹出菜单&#xff0c;选择“设置”。 4.选择单击“选择要清除的内容”…

清除缓存?(浏览器)

清除缓存 清空浏览器历史记录 **浏览器缓存&#xff1a;**浏览器将用户请求过的静态资源&#xff0c;存储到电脑本地磁盘中&#xff0c;当浏览器再次访问时&#xff0c;就可以直接从本地加载&#xff0c;不需要再去服务端请求了。 好处&#xff1a;减少了服务器的负担&#x…

Chrome清理网页缓存

F12 打开开发者工具&#xff08;或者直接右键→“检查”&#xff09;&#xff0c;此时右键点击“刷新”按钮&#xff1a; 点击“清空缓存并硬性重新加载即可”。

如何查看Chrome浏览器的页面缓存内容【详细教程】

如何查看浏览器页面缓存内容——代码&控制台 知识调用前言引入控制台输入代码查看在控制台application查看 知识调用 文章可能需要用到的知识&#x1f525;&#x1f525;&#x1f525;浏览器缓存有哪些&#xff08;通用缓存有哪些&#xff09; 前言引入 浏览器有多种缓存…

【浏览器】浏览器缓存

一 浏览器缓存机制 浏览器在每次发生请求时&#xff0c;先在在浏览器缓存中查找该请求的结果和缓存标识&#xff0c;并且每次收到请求结果均会把请求结果和缓存标识保存在浏览器缓存中。 总体脑图&#xff1a;文中脑图及流程图资源 浏览器缓存策略分类 缓存策略的分类&…

chrome浏览器清除缓存

场景 &#xff1a;更新页面后可在无痕浏览器中看到更新内容&#xff0c;无法直接打开浏览器看更新内容 方法1&#xff1a;使用无痕浏览器 浏览器右上角-打开新的无痕式窗口 方法2&#xff1a;右键打开控制台 - Application - 找到左侧store - clear site data 方法3&#xff1…

清除浏览器缓存(js、css等)

有时候写web项目&#xff0c;改了js或者css文件&#xff0c;但是浏览器就是不刷新&#xff0c;就很头疼o(╥﹏╥)o。那是因为浏览器还有缓存存在的原因&#xff0c;下面来看如何清除缓存。 1.找到目标网页&#xff0c;鼠标右击&#xff0c;点击检查&#xff1b;或者CtrlShifti&…

清除chrome浏览器缓存

之前有写过设置缓存,本文解决清除html缓存,如何才能清除缓存呢&#xff1f;一下是几个清除浏览器缓存的方法&#xff1a; 方法1.chrome浏览器地址&#xff1a;chrome://settings/clearBrowserData&#xff1b; 方法2.如果是开发者的话&#xff1a;重启服务&#xff0c;刷新页…