{"id":531,"date":"2021-09-17T20:07:48","date_gmt":"2021-09-17T20:07:48","guid":{"rendered":"https:\/\/bronsonzgeb.com\/?p=531"},"modified":"2021-09-17T20:07:49","modified_gmt":"2021-09-17T20:07:49","slug":"the-type-object-pattern-with-scriptable-objects","status":"publish","type":"post","link":"https:\/\/bronsonzgeb.com\/index.php\/2021\/09\/17\/the-type-object-pattern-with-scriptable-objects\/","title":{"rendered":"The Type Object pattern with Scriptable Objects"},"content":{"rendered":"\n<p>This article will demonstrate how to implement the Type Object pattern in Unity using Scriptable Objects.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What problem does Type Object solve?<\/h2>\n\n\n\n<p>There&#8217;s plenty of literature on the subject, but I&#8217;ll briefly explain the origins of this pattern. Let&#8217;s put Unity aside for a moment. Imagine you had to define a bunch of different buildings for your city builder game. In classical OOP style, you maybe be tempted to start with a base <code>Building<\/code> class. Then, you&#8217;d subclass <code>Building<\/code> for each new type and adjust the building cost, sell price, income generated, etc. Now you have a bunch of subclasses with nothing but a few variables changed here and there. Plus, you have to recompile your code every time you add a new building or change the cost of an existing building. Using subclasses to define types is both a hassle and inflexible.<\/p>\n\n\n\n<p>Now back to Unity. In Unity, it&#8217;s unlikely you&#8217;d take this approach at all. Instead, you&#8217;d define some building component and attach that to a prefab. Then for every new type, you&#8217;d create either a new prefab or prefab variant. So, Unity has already helped us turn our code into data in the form of prefab files. Great! Turning code into data is the aim of the Type Object pattern. Rather than creating a <code>Type<\/code> to represent variants of a class, we create a single <code>Type<\/code> that holds all the variable data. Then we make new types through data rather than through code.<\/p>\n\n\n\n<p>So if Unity already solved the problem, what&#8217;s the point of this article? Well, I&#8217;m here to offer a different approach. You&#8217;ll still use prefab variants, but Scriptable Objects provide further benefits on top of the variant system.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Scriptable Objects as Type Objects<\/h2>\n\n\n\n<p>We&#8217;ll create a bunch of monsters and experience the Scriptable Object advantage first-hand. Let&#8217;s jump right in with some code.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using UnityEngine;\n\npublic class Monster : MonoBehaviour\n{\n    public int Health;\n    public int Speed;\n    public int Attack;\n}<\/code><\/pre>\n\n\n\n<p>Behold the classic monster. Admittedly it&#8217;s a simple example, but it&#8217;s enough for demonstration purposes. Here, our monster has three stats: Health, Speed, and Attack. As I mentioned before, generally, in Unity, you would attach this component to a prefab and modify the stats on each variant to define new monsters. This is a good approach, but when we throw a Scriptable Object into the mix, we gain several advantages for minimal cost.<\/p>\n\n\n\n<p>Let&#8217;s quickly build something to provide some context. Create a new Type Object that derives from Scriptable Object with our base values.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using UnityEngine;\n\n&#91;CreateAssetMenu]\npublic class MonsterType : ScriptableObject\n{\n    public int StartingHealth;\n    public int BaseSpeed;\n    public int BaseAttack;\n}<\/code><\/pre>\n\n\n\n<p>Now, modify the Monster class to hold a reference to the Type Object.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using UnityEngine;\n\npublic class Monster : MonoBehaviour\n{\n    public int Health;\n    public int Speed;\n    public int Attack;\n    public MonsterType Type;\n\n    void Start()\n    {\n        Health = Type.StartingHealth;\n        Speed = Type.BaseSpeed;\n        Attack = Type.BaseAttack;\n    }\n}<\/code><\/pre>\n\n\n\n<p>Then, in the <code>Start<\/code> method, copy the base values from the <code>MonsterType<\/code> into this instance of a monster. By the way, this is a crucial step because any modifications to Scriptable Objects will affect all the objects referencing it. Not to mention, those modifications persist in and out of play mode. So if you change these base values while your game is running, you&#8217;ll lose your carefully balanced stats.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Scriptable Objects, Prefabs and Version Control<\/h2>\n\n\n\n<p>When it comes to version control, merging complex assets is a pain. It&#8217;s common to run into a situation where a designer must balance stat values across several creatures in a game. At the same time, artists may iterate on the visuals while gameplay developers attach new components. If multiple developers make simultaneous changes to the same prefab, it&#8217;s unlikely that those changes will merge cleanly. In this case, someone will have to redo work. What if we could split these tasks into separate assets, eliminating merge conflicts? That&#8217;s where Scriptable Objects come in.<\/p>\n\n\n\n<p>When the stats live inside a Scriptable Object, designers can change them without touching the prefab file at all. As a result, the only merge conflicts that arise come from two designers tweaking the same value. What&#8217;s more, when conflicts occur, they&#8217;re easier to solve because Scriptable Object files are more readable. For comparison, here&#8217;s a simple prefab:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!1 &amp;7398429376191695866\nGameObject:\n  m_ObjectHideFlags: 0\n  m_CorrespondingSourceObject: {fileID: 0}\n  m_PrefabInstance: {fileID: 0}\n  m_PrefabAsset: {fileID: 0}\n  serializedVersion: 6\n  m_Component:\n  - component: {fileID: 7398429376191695864}\n  - component: {fileID: 7398429376191695867}\n  - component: {fileID: 397173726}\n  - component: {fileID: 397173725}\n  m_Layer: 0\n  m_Name: MonsterBase\n  m_TagString: Untagged\n  m_Icon: {fileID: 0}\n  m_NavMeshLayer: 0\n  m_StaticEditorFlags: 0\n  m_IsActive: 1\n--- !u!4 &amp;7398429376191695864\nTransform:\n  m_ObjectHideFlags: 0\n  m_CorrespondingSourceObject: {fileID: 0}\n  m_PrefabInstance: {fileID: 0}\n  m_PrefabAsset: {fileID: 0}\n  m_GameObject: {fileID: 7398429376191695866}\n  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}\n  m_LocalPosition: {x: 0, y: 0, z: 0}\n  m_LocalScale: {x: 1, y: 1, z: 1}\n  m_Children: &#91;]\n  m_Father: {fileID: 0}\n  m_RootOrder: 0\n  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}\n--- !u!114 &amp;7398429376191695867\nMonoBehaviour:\n  m_ObjectHideFlags: 0\n  m_CorrespondingSourceObject: {fileID: 0}\n  m_PrefabInstance: {fileID: 0}\n  m_PrefabAsset: {fileID: 0}\n  m_GameObject: {fileID: 7398429376191695866}\n  m_Enabled: 1\n  m_EditorHideFlags: 0\n  m_Script: {fileID: 11500000, guid: 491079bd7ae064bad94668c7539cf90f, type: 3}\n  m_Name: \n  m_EditorClassIdentifier: \n  Type: {fileID: 0}\n--- !u!33 &amp;397173726\nMeshFilter:\n  m_ObjectHideFlags: 0\n  m_CorrespondingSourceObject: {fileID: 0}\n  m_PrefabInstance: {fileID: 0}\n  m_PrefabAsset: {fileID: 0}\n  m_GameObject: {fileID: 7398429376191695866}\n  m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0}\n--- !u!23 &amp;397173725\nMeshRenderer:\n  m_ObjectHideFlags: 0\n  m_CorrespondingSourceObject: {fileID: 0}\n  m_PrefabInstance: {fileID: 0}\n  m_PrefabAsset: {fileID: 0}\n  m_GameObject: {fileID: 7398429376191695866}\n  m_Enabled: 1\n  m_CastShadows: 1\n  m_ReceiveShadows: 1\n  m_DynamicOccludee: 1\n  m_StaticShadowCaster: 0\n  m_MotionVectors: 1\n  m_LightProbeUsage: 1\n  m_ReflectionProbeUsage: 1\n  m_RayTracingMode: 2\n  m_RayTraceProcedural: 0\n  m_RenderingLayerMask: 1\n  m_RendererPriority: 0\n  m_Materials:\n  - {fileID: 10302, guid: 0000000000000000f000000000000000, type: 0}\n  m_StaticBatchInfo:\n    firstSubMesh: 0\n    subMeshCount: 0\n  m_StaticBatchRoot: {fileID: 0}\n  m_ProbeAnchor: {fileID: 0}\n  m_LightProbeVolumeOverride: {fileID: 0}\n  m_ScaleInLightmap: 1\n  m_ReceiveGI: 1\n  m_PreserveUVs: 0\n  m_IgnoreNormalsForChartDetection: 0\n  m_ImportantGI: 0\n  m_StitchLightmapSeams: 1\n  m_SelectedEditorRenderState: 3\n  m_MinimumChartSize: 4\n  m_AutoUVMaxDistance: 0.5\n  m_AutoUVMaxAngle: 89\n  m_LightmapParameters: {fileID: 0}\n  m_SortingLayerID: 0\n  m_SortingLayer: 0\n  m_SortingOrder: 0\n  m_AdditionalVertexStreams: {fileID: 0}<\/code><\/pre>\n\n\n\n<p>And a simple Scriptable Object:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>%YAML 1.1\n%TAG !u! tag:unity3d.com,2011:\n--- !u!114 &amp;11400000\nMonoBehaviour:\n  m_ObjectHideFlags: 0\n  m_CorrespondingSourceObject: {fileID: 0}\n  m_PrefabInstance: {fileID: 0}\n  m_PrefabAsset: {fileID: 0}\n  m_GameObject: {fileID: 0}\n  m_Enabled: 1\n  m_EditorHideFlags: 0\n  m_Script: {fileID: 11500000, guid: cad5330d2463d44e68a65aa0c805c193, type: 3}\n  m_Name: Cat\n  m_EditorClassIdentifier: \n  <strong>StartingHealth<\/strong>: 20\n  <strong>BaseSpeed<\/strong>: 20\n  <strong>BaseAttack<\/strong>: 20<\/code><\/pre>\n\n\n\n<p>The Scriptable Object is&nbsp;<em>almost<\/em>&nbsp;human-readable. Plus, the stats <code>StartingHealth<\/code>, <code>BaseSpeed<\/code>, and <code>BaseAttack<\/code>&nbsp;<em>are<\/em>&nbsp;readable, which are the values most likely to change.<\/p>\n\n\n\n<p>Next, let&#8217;s explore the power of Scriptable Object as references.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Scriptable Object References<\/h2>\n\n\n\n<p>I had a hard time titling this section, but bear with me for a minute, and you&#8217;ll see where I&#8217;m going with this. One of the main advantages of Scriptable Objects is that they are first-class citizens in the Unity editor. What does that mean? Scriptable Objects automatically work with all the editor systems. They serialize and deserialize easily. The Inspector recognizes them as referenceable objects. They simply work. Now, this is pretty awesome, but it&#8217;s only part of the story. Multiple objects can reference a single Scriptable Object through dragging and dropping in the Inspector. Plus, it&#8217;s easy to test if two references are pointing at the same thing. Why do we care? Let&#8217;s find out.<\/p>\n\n\n\n<p>Let&#8217;s say our monsters have weaknesses to other monsters. By referencing <code>MonsterType<\/code> directly, designers can define weaknesses by dragging and dropping Scriptable Objects in the Inspector.<\/p>\n\n\n\n<p>Let me show you what I mean. Add a <code>MonsterType<\/code> array called <code>Weaknesses<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using UnityEngine;\n\n&#91;CreateAssetMenu]\npublic class MonsterType : ScriptableObject\n{\n    public int StartingHealth;\n    public int BaseSpeed;\n    public int BaseAttack;\n    <strong>public MonsterType&#91;] Weaknesses;<\/strong>\n}<\/code><\/pre>\n\n\n\n<p>This field will appear in the Inspector as a list of <code>MonsterType<\/code> elements. You can freely modify a monster&#8217;s <code>Weaknesses<\/code> as you wish. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"458\" height=\"230\" src=\"https:\/\/bronsonzgeb.com\/wp-content\/uploads\/2021\/09\/WormWeakness.png\" alt=\"\" class=\"wp-image-548\" srcset=\"https:\/\/bronsonzgeb.com\/wp-content\/uploads\/2021\/09\/WormWeakness.png 458w, https:\/\/bronsonzgeb.com\/wp-content\/uploads\/2021\/09\/WormWeakness-300x151.png 300w\" sizes=\"auto, (max-width: 458px) 100vw, 458px\" \/><figcaption>Worms are weak to Pidgeons and Cats<\/figcaption><\/figure><\/div>\n\n\n\n<p>But how do you know if a monster is weak to another monster? Let&#8217;s add a helper to the <code>Monster<\/code> class.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>using UnityEngine;\n\npublic class Monster : MonoBehaviour\n{\n    public int Health;\n    public int Speed;\n    public int Attack;\n    public MonsterType Type;\n\n    void Start()\n    {\n        Health = Type.StartingHealth;\n        Speed = Type.BaseSpeed;\n        Attack = Type.BaseAttack;\n    }\n\n<strong>    public bool IsWeakAgainst(MonsterType type)\n    {<\/strong>\n<strong>        foreach (var weakness in Type.Weaknesses)\n        {\n            if (type == weakness)\n                return true;\n        }\n\n        return false;\n    }<\/strong>\n}<\/code><\/pre>\n\n\n\n<p>Since <code>MonsterType<\/code> is a reference, we check if a given <code>type<\/code> is <code>==<\/code> to any elements in the <code>Weaknesses<\/code> array. If yes, we know both variables are pointing to the same Scriptable Object, and consequently, it&#8217;s part of the monster&#8217;s weaknesses. Isn&#8217;t that neat?<\/p>\n\n\n\n<p>You could extend this as well. What if you had two nearly identical monsters, but one of them was fiery? Create a new <code>Element<\/code> type and add it to <code>MonsterType<\/code> with an accompanying <code>ElementalWeaknesses<\/code> array. Then you can check if a given monster is weak against a certain element too.<\/p>\n\n\n\n<p>Using Scriptable Objects makes it straightforward to compose new variants through data by dragging items around the editor, which is the purpose of the Type Object pattern.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrap-Up<\/h2>\n\n\n\n<p>I want to extend this example further by adding abilities to the monsters with Scriptable Objects. However, that&#8217;s veering away from the Type Object pattern and into the Command pattern. So, I&#8217;ll save that for a future post!<\/p>\n\n\n\n<p><strong>Dive into the example Github project\u00a0<\/strong><a href=\"https:\/\/github.com\/bzgeb\/TypeObjectPatternExample\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>here<\/strong><\/a><strong>. To learn more about the Type Object pattern, check out\u00a0<\/strong><a rel=\"noreferrer noopener\" target=\"_blank\" href=\"http:\/\/gameprogrammingpatterns.com\/type-object.html\"><strong>this chapter<\/strong><\/a><strong>\u00a0from Game Programming Patterns. If my work is helpful, show your support and\u00a0<\/strong><a rel=\"noreferrer noopener\" target=\"_blank\" href=\"https:\/\/bronsonzgeb.com\/index.php\/join-my-mailing-list\/\"><strong>join my mailing list<\/strong><\/a><strong>. If you do, I&#8217;ll notify you whenever I write a new post.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article will demonstrate how to implement the Type Object pattern in Unity using Scriptable Objects. What problem does Type Object solve? There&#8217;s plenty of literature on the subject, but I&#8217;ll briefly explain the origins of this pattern. Let&#8217;s put Unity aside for a moment. Imagine you had to define a bunch of different buildings [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":545,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,1],"tags":[30,8,54,29,5],"class_list":["post-531","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-architecture","category-unity-programming","tag-architecture","tag-game-development","tag-programming-patterns","tag-scriptable-objects","tag-unity"],"_links":{"self":[{"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/posts\/531","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/comments?post=531"}],"version-history":[{"count":16,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/posts\/531\/revisions"}],"predecessor-version":[{"id":549,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/posts\/531\/revisions\/549"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/media\/545"}],"wp:attachment":[{"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/media?parent=531"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/categories?post=531"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/tags?post=531"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}