{
  "schemaVersion": "0.11.0",
  "canonical": "https://www.pystone.net/notes/unity-scriptable-object/",
  "atlas": "https://www.pystone.net/?node=unity-scriptable-object#knowledge-atlas",
  "markdown": "https://www.pystone.net/notes/unity-scriptable-object.md",
  "context": "https://www.pystone.net/notes/unity-scriptable-object.context.json",
  "knowledgeVersion": "224c990773de.5fa8af6e39fa",
  "build": {
    "siteCommit": "224c990773de166d23a886306577dd90379529ce",
    "notesCommit": "5fa8af6e39fa3891d1b9b4832bfa6c4e0ecaaf0a",
    "builtAt": "1970-01-01T00:00:00.000Z",
    "version": "224c990773de.5fa8af6e39fa"
  },
  "id": "note:unity-scriptable-object",
  "slug": "unity-scriptable-object",
  "title": "ScriptableObject",
  "type": "note",
  "visibility": "public",
  "idStability": "rename-stable",
  "author": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "publisher": {
    "name": "Perrin Yong",
    "profile": "https://www.pystone.net/profile/"
  },
  "aliases": [],
  "summary": "ScriptableObject 创建时间：2020/6/9 17:02",
  "contentRole": "unspecified",
  "isMoc": false,
  "mocRecognition": "none",
  "generated": false,
  "attribution": "unspecified",
  "domain": "10-计算机、信息技术与工程",
  "tags": [],
  "mocs": [],
  "contentHash": "2ce8f146b359dca7d8fd054aa2b4cf5531db99a8f7ef4f49fbb3afe0afbb1623",
  "assets": [],
  "headings": [
    {
      "depth": 1,
      "text": "ScriptableObject",
      "anchor": "scriptableobject",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#scriptableobject"
    },
    {
      "depth": 2,
      "text": "ScriptableObject",
      "anchor": "scriptableobject-1",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#scriptableobject-1"
    },
    {
      "depth": 2,
      "text": "作用",
      "anchor": "作用",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E4%BD%9C%E7%94%A8"
    },
    {
      "depth": 2,
      "text": "特点",
      "anchor": "特点",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E7%89%B9%E7%82%B9"
    },
    {
      "depth": 2,
      "text": "优点",
      "anchor": "优点",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E4%BC%98%E7%82%B9"
    },
    {
      "depth": 2,
      "text": "Method",
      "anchor": "method",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#method"
    },
    {
      "depth": 2,
      "text": "使用方法",
      "anchor": "使用方法",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95"
    },
    {
      "depth": 3,
      "text": "MenuItem",
      "anchor": "menuitem",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#menuitem"
    },
    {
      "depth": 3,
      "text": "CreateAssetMenu",
      "anchor": "createassetmenu",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#createassetmenu"
    },
    {
      "depth": 3,
      "text": "动态创建",
      "anchor": "动态创建",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E5%8A%A8%E6%80%81%E5%88%9B%E5%BB%BA"
    },
    {
      "depth": 3,
      "text": "CreateAssets & FindAssets & ScriptableObject",
      "anchor": "createassets-findassets-scriptableobject",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#createassets-findassets-scriptableobject"
    },
    {
      "depth": 2,
      "text": "生命周期",
      "anchor": "生命周期",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E7%94%9F%E5%91%BD%E5%91%A8%E6%9C%9F"
    },
    {
      "depth": 2,
      "text": "其他高级应用Demo",
      "anchor": "其他高级应用demo",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E5%85%B6%E4%BB%96%E9%AB%98%E7%BA%A7%E5%BA%94%E7%94%A8demo"
    },
    {
      "depth": 3,
      "text": "保存信息",
      "anchor": "保存信息",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E4%BF%9D%E5%AD%98%E4%BF%A1%E6%81%AF"
    },
    {
      "depth": 3,
      "text": "用作配置文件",
      "anchor": "用作配置文件",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#%E7%94%A8%E4%BD%9C%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6"
    },
    {
      "depth": 2,
      "text": "Ref:",
      "anchor": "ref",
      "citation": "https://www.pystone.net/notes/unity-scriptable-object/#ref"
    }
  ],
  "claims": [],
  "outgoing": [],
  "incoming": [
    {
      "id": "note:game-graphics-and-runtime",
      "title": "游戏图形与运行时",
      "url": "https://www.pystone.net/notes/game-graphics-and-runtime/",
      "atlas": "https://www.pystone.net/?node=game-graphics-and-runtime#knowledge-atlas",
      "label": "游戏图形与运行时",
      "origin": "explicit",
      "humanReviewed": true,
      "context": "Unity中的“ScriptableObject”导航项",
      "citation": "https://www.pystone.net/notes/game-graphics-and-runtime/#unity"
    }
  ],
  "contentMarkdown": "# ScriptableObject\n> 创建时间：2020/6/9 17:02\n\n## ScriptableObject\n\n  * ScriptableObject\n    * 作用\n    * 特点\n    * 优点\n    * Method\n    * 使用方法\n      * MenuItem\n      * CreateAssetMenu\n      * 动态创建\n      * CreateAssets & FindAssets & ScriptableObject\n    * 生命周期\n    * 其他高级应用Demo\n      * 保存信息\n      * 用作配置文件\n    * Ref:\n\n> 文档：<https://docs.unity3d.com/ScriptReference/ScriptableObject.html>\n>  <https://docs.unity3d.com/Manual/class-ScriptableObject.html>\n\nScriptableObject类直接继承自Object类；它和MonoBehaviour是并列的，都继承自Object（但MonoBehaviour并不是直接继承自Object）\n\n是一个 **数据容器** ，可以用来存储大量的数据，它是可序列化的。\n\n## 作用\n\n  1. 存储数据：在游戏运行时创建脚本化对象实例，然后可以将数据保存到本地（如果不保存，它会在游戏结束后销毁）；\n\n  2. 减少内存：将数据存储在ScriptableObject对象中，在代码中可以进行引用，来减少工程以及游戏运行时因拷贝值所造成的内存占用；\n\n> **ScriptableObject与预制体** ：当你有一个预制体，它附加了一些mono脚本，包含了一些数据，每次我们实例化预制体的时候它都会拷贝assets下原预制体的值生成一份自己的拷贝，然后我们可以修改场景内预制体的值而并不影响assets下预制体的值，这是prefab的特性，对于我们从一个prefab模板生成属性不同的游戏对象是很有用的，但是如果prefab里的脚本数据是不需要修改的，它就会造成很大的资源浪费，尤其在数据很多的时候；为了避免这种问题，我们可以在不需要修改prefab里的脚本数据时，考虑使用ScriptableObject来存储这些重复的数据，然后其它所有预制体都可以使用引用的方式来访问这份数据，这就意味着不管场景中实例了多少预制体，在内存中就只需要有一份数据；它所带给我们的启示就是， **当预制体中的脚本里有大量重复数据时，我们要想着将数据抽离，单独保存在本地**\n\n## 特点\n\n  1. **Unity编辑器外不可操作** ：仅在编辑器中才可以保存修改的数据（因为ScriptableObject对象虽然声明在UnityEngine中，但是它的Scriptable是通过UnityEditor命名空间下的类例如Editor类等来实现的），所以在部署构建的时候不可以用于存储游戏运行时更改的数据，但是可以使用之前存储好的数据。也就是ScriptableObject生成的数据资源文件 **在Editor外具有只读属性** ，如果你需要在游戏中修改数据并存储下来，就不推荐使用ScriptableObject了；\n\n> 就像我们不可以在游戏运行时修改一个shader资源的代码、不可以修改一个纹理资源的像素内容一样，而在Unity Editor里可以修改ScriptableObject是因为Unity的编辑器对它格式的支持\n\n  2. 继承自UnityEngine.Object，不必附着在对象上也无需/不能赋给Gameobject或Prefab\n\n  3. 可以被serialize，可以在资源面板创建一个对应的.asset文件，把数据存储在资源文件中，通过属性面板可修改数值。该文件表示一个ScriptableObject的对象实例的序列化文件，退出之后也不会丢失。\n\n  4. 本身是个类，可以引用，在项目之间共享\n\n  5. 回调少 ：OnEnable 、OnDisable、OnDestroy\n\n  6. persistent：当它被绑定到.asset文件或者AssetBundle等资源文件中的时候（它可以通过Resources.UnloadUnusedAssets来被unload出内存。可以通过脚本引用或其他需要的时候被再次load到内存）\n非persistent：通过CreateInstance<>来创建的时候（它可以通过GC被直接destroy掉（如果没有任何引用的话）。如果不想被GC的话，可以使用HideFlags.HideAndDontSave）\n\n## 优点\n\n  1. unity内置的一种储存容器\n\n  2. PlayMode储存数据更改（再也不怕更改数据没保存了）\n3\n\n## Method\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n???\nScriptableObject内部实现上也继承自MonoBehavior，它只有四个消息函数，Awake()、OnDestroy()、OnEnable()、OnDisable()；\n\n## 使用方法\n\n### MenuItem\n\n需要指定创建的目录和资源名称，如果资源已经存在，则不会创建新资源；\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n### CreateAssetMenu\n\n可以在Assets下任意目录创建资源，而且可以创建多个资源；\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n在Assets下创建一个可编程对象资源，设置好所需数据；如果需要在其它脚本中获取该数据，是需要声明一个该类型变量，然后为其赋值或加载该数据资源；然后，就像使用用一个类中的公有变量一样使用即可；\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n### 动态创建\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n### CreateAssets & FindAssets & ScriptableObject\n\n  1. 对于ScriptableObject，使用CreateInstance来创建Asset实例对象\n`testI = (ScriptObj)ScriptableObject.CreateInstance(typeof(ScriptObj));`\n\n  2. 对于其他资源类型，使用new来创建对象\n\n  3. 然后调用 `AssetDatabase.CreateAsset`函数，将实例对象作为资源存储在Assets路径当中。\n\n  4. 最后使用`AssetDatabase.FindAssets`获取相应资源的GUID\n\n  5. 由 `AssetDatabase.GUIDToAssetPath` 获取相应资源的路径。\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n## 生命周期\n\nScriptableObject的生命周期和其他资源都是类似的：\n\n当它是被绑定到.asset文件或者AssetBundle等资源文件中的时候，它就是persistent的，这意味着\n它可以通过Resources.UnloadUnusedAssets来被unload出内存\n可以通过脚本引用或其他需要的时候被再次load到内存\n如果是通过CreateInstance<>来创建的，它就是非persistent的，这意味着\n它可以通过GC被直接destroy掉（如果没有任何引用的话）\n如果不想被GC的话，可以使用HideFlags.HideAndDontSave\n\n## 其他高级应用Demo\n\n<https://blog.csdn.net/candycat1992/article/details/52181814>\n\n### 保存信息\n\nstep1.创建你用于共享数据的类（例如EnemyData）\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\nstep2.新建一个脚本扩展Editor,使编辑器能够创建自定义的ScriptableObject对象\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\nstep3. 在需要引用的脚本中引用\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n### 用作配置文件\n\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n```csharp\nstring s1 = &quot;Hello &quot;;\nstring s2 = s1;\ns1 += &quot;World&quot;;\n\nSystem.Console.WriteLine(s2);\n//Output: Hello\n\n```\n\n## Ref:\n\n<https://blog.csdn.net/qq_36383623/article/details/99649941>\n<https://blog.csdn.net/candycat1992/article/details/52181814>\n"
}
