unity中关于游戏中数据的流动总结-1

一、普通脚本 int hp = 10 的完整生命周期

1. 编写代码阶段(Visual Studio)

csharp

public class Enemy : MonoBehaviour

{

public int hp = 10; // 代码中写死的初始值

}

此时 10 只是一个源代码中的字面量,还没有任何“固化”的形式。

2. 编译阶段(Unity 自动编译)

  • Unity 将 C# 脚本编译成 程序集(Assembly-CSharp.dll)
  • 编译器会把 hp = 10 这个初始化操作转换成 IL 指令(例如 ldc.i4.s 10),并将这个 10 作为常量数据嵌入到 DLL 文件的元数据中。
  • 此时,10 已经以二进制形式存在于磁盘上的 DLL 文件里,但它属于代码逻辑的一部分,而非独立的数据资源。

3. 编辑器中的实例化与序列化(Unity Editor)

情况 A:从未在 Inspector 中修改过 hp

  • 当你把 Enemy 脚本挂载到场景中的 GameObject 上,Unity 会在内存中创建该脚本的实例。
  • 实例化过程:
  • 分配内存,所有字段初始化为默认值(hp = 0)。调用构造函数(如果有)和字段初始化器(int hp = 10),将 hp 设为 10。Unity 的序列化系统会检查该对象是否有保存的序列化数据(比如来自场景文件 .unity)。因为没有修改过,所以没有额外数据,最终 hp 保持 10。
  • 当你保存场景(Ctrl+S),Unity 会将当前场景中所有对象的当前值序列化到 .unity 文件中。由于 hp 没改过,场景文件里其实不会显式存储**hp=10**,而是依赖代码初始化。

情况 B:在 Inspector 中修改了 hp(比如改成 20)

  • 在 Inspector 中把 hp 改为 20,Unity 立即将这个新值存入内存中的对象实例。
  • 保存场景时,Unity 会检测到 hp 的值与代码默认值(10)不一致,于是**20**序列化到场景文件(或预制体文件)中
  • 此时,20 就作为序列化数据持久化到了磁盘上的资源文件中。

4. 打包阶段(Build)

  • Unity 将所有的程序集(DLL)场景文件预制体其他资源打包成一个完整的游戏包(如 PC 版的 .exe 及附带数据文件)。
  • 注意:DLL 中包含的是代码指令(包括 hp=10 这个常量),而场景/预制体文件中包含的是经过修改的序列化数据(如果有的话)。

5. 玩家运行游戏(Runtime)

  • 游戏启动,操作系统将游戏包中的 DLL 和数据文件加载到内存。
  • 当需要创建一个 Enemy 实例时(例如加载场景或实例化预制体):
  • 先从 DLL 的元数据中获取类的定义。分配内存,字段先清零(hp = 0)。执行字段初始化器(int hp = 10),将 hp 暂时设为 10。Unity 反序列化系统介入:检查该实例是否有对应的序列化数据(来自场景文件或预制体文件)。如果有(比如之前在 Inspector 里改成了 20),则用文件中的 20覆盖hp。如果没有(从未修改过),则 hp 保持 10。
  • 最终,Enemy 实例的 hp 值要么是代码默认值 10,要么是被序列化数据覆盖后的值。

关键点:普通脚本的字段默认值 10 确实也是从磁盘(DLL)读入内存的,但它属于代码指令的一部分,无法在编辑器里像改资源那样直接修改并独立保存。如果要在编辑器中修改并持久化,必须通过 Inspector 修改并保存到场景/预制体文件中——这种方式本质上是在用资源文件覆盖代码默认值

二、ScriptableObject 版 int hp = 10 的完整生命周期

1. 编写代码

csharp

[CreateAssetMenu]

public class EnemySO : ScriptableObject

{

public int hp = 10;

}

同样,代码中写死了 10

2. 编译阶段

  • 和普通脚本一样,hp = 10 被编译进 DLL 的 IL 指令中。

3. 编辑器中的创建与修改

首次创建 .asset 文件

  • 你在 Project 窗口右键创建 EnemySO 资产,Unity 会在内存中实例化一个 EnemySO 对象。
  • 实例化过程:
  • 调用 ScriptableObject.CreateInstance<EnemySO>(),内部会分配内存并执行字段初始化器,将 hp 设为 10。Unity 立即将这个内存中的对象序列化到磁盘,生成 .asset 文件。此时文件中存储的 hp 值就是 10。
  • 注意:.asset 文件一旦生成,hp 的值就被固化到了这个独立的数据文件中,与代码中的 10 脱离关系。

修改 .asset 文件

  • 在 Inspector 中选中该 .asset 文件,把 hp 改为 20,然后保存。
  • Unity 将新的 20 重新序列化到同一个 .asset 文件中,覆盖原来的 10
  • 整个过程不需要重新编译代码,因为改的是数据文件,而非代码。

4. 打包阶段

  • .asset 文件作为常规资源被打包进游戏包,和场景、预制体等并列。

5. 玩家运行游戏

  • 当游戏需要用到这个 EnemySO 数据时(比如通过 Resources.Load 或直接引用),Unity 从包中加载对应的 .asset 文件。
  • 反序列化过程:
  • 读取 .asset 文件的二进制数据。直接在内存中重建对象,将 hp 字段赋值为文件中存储的值(比如 20)。
  • 整个过程中不会执行字段初始化器,因为对象是通过反序列化创建的,其所有数据都来自文件。如果文件损坏或不存在,可能才会回退到代码默认值,但正常流程中文件是主数据源。

三、核心对比总结

编译后

10 固化在 DLL 的 IL 指令中

10 同样固化在 DLL 中,但仅作为创建资产时的初始值

编辑器修改

需通过 Inspector 修改,新值保存在场景/预制体文件中

直接在 Inspector 修改 .asset 文件,新值保存在资产文件中

运行时数据源

优先从场景/预制体文件反序列化,若无则用 DLL 中的默认值

直接从 .asset 文件反序列化,DLL 默认值被完全覆盖

能否独立配置多份

每个预制体/场景实例可独立修改值(通过序列化覆盖)

可创建多个 .asset 文件,每个文件持有不同的值,被多个对象共享

修改门槛

改代码默认值需重新编译;改序列化值只需在 Inspector 操作

改默认值也无需重新编译,直接改 .asset 即可

四、你的总结非常到位

“其实说白了 这两种方式的数据流向是一样的 最主要的区别是写到正常脚本里int EnemyHp=10 不能修改 而写到ScriptableObject里面的是可以在unity编辑时随时修改并保存到磁盘 然后被调用就像其它unity资源是一样的对吧 最后游戏运行起来 这俩都是从磁盘读二进制到内存”

没错!两者的数据最终都是从磁盘二进制文件加载到内存,但:

  • 普通脚本的默认值**10**是“代码”的一部分,它存在于 DLL 这个“代码文件”中,修改它必须重新编译代码(除非用场景/预制体覆盖)。
  • ScriptableObject 的**10**只是创建资产时的“种子”,一旦资产文件生成,实际数据就独立存在于资产文件(.asset)中,可以在编辑器中像改贴图、模型一样随时修改并保存,完全无需碰代码。

这就是为什么 ScriptableObject 非常适合做游戏配置数据——它实现了真正的数据与代码分离,让策划、美术等非程序员也能自由调整数值,而不需要每次改个血量就麻烦程序员重新编译。

如果你还有任何疑问,或者想深入了解序列化在底层的具体实现,欢迎继续探讨

全部评论

相关推荐

03-11 20:19
已编辑
门头沟学院 Java
太压力了,面了2个多小时,本菜比已经被拷打的瑟瑟发抖面完两个小时后通知过了1.算法题三道(1)leetcode124&nbsp;二叉树中最大路径和hard题&nbsp;因为不久前才刷过撕出来了,又来了一道(2)leetcode&nbsp;300&nbsp;最长递增子序列变种除了递增之外还加了一个权重因素,但是思路没变,dp就行(3)寻找词汇库里符合固定长度前缀的匹配单词应该是他们自己题库的题。给了一串单词列表,然后又给了一个单词,一个下标,根据这个下标的前缀去单词列表里面找到所有匹配的单词再返回思路是创建一个单词前缀树,然后根据树找,但是可能是构件树数有问题没撕出来2.全方位项目拷打基本没有问八股,全部都是项目企业场景题,哎哟我操,完全不会。我就纯八股战士,结果没想到一道八股都没问反正尽可能把企业场景往八股上引吧。。1.&nbsp;微服务多点部署其中一个宕机了怎么办2.&nbsp;要是mq占据大量CPU该怎么排查?MySQL占据大量CPU该怎么排查?3.&nbsp;假如说让你实现视频点赞功能,你打算怎么设计?讲讲思路(我知道多级缓存,但是碰巧没背……寄)4.&nbsp;Redis延迟双删是什么,分布式锁,哨兵模式5.&nbsp;MySQL到es同步的延迟该怎么优化6.&nbsp;Rabbit&nbsp;mq的队列是怎么实现的?(这个完全没整明白,可能是队列的底层结构?&nbsp;反正我硬扯的讲了一下rabbit&nbsp;mq的架构)还扯了很多,但是往后完全就慌了),记住的是这些
不知道怎么取名字_:2小时确实有压力,持续性的脑力劳动啊
查看9道真题和解析
点赞 评论 收藏
分享
评论
点赞
1
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务