Jekyll2023-06-26T09:27:12-03:00https://blog.gemserk.com/feed/index.xmlGemserkGemserk's BlogGemserkRefactoring Data stored in Unity Prefabs, Scenes and other Assets2022-04-24T00:00:00-03:002022-04-24T00:00:00-03:00https://blog.gemserk.com/2022/04/24/refactoring-prefabs-and-unity-objects<p>Using Unity, most of the Data will be serialized inside Prefabs, Scenes (inside MonoBehaviour serialized fields) and other Assets. In our case we also use data only <a href="/2020/05/26/using-unity-prefabs-and-gameobjects-only-for-data/">Prefabs and GameObjects</a>.</p>
<p>Refactoring Code is a common and recommended good practice and there are tools to help in that task. For example, Rider IDE provides a great with C# code refactors and also by adjusting Unity assets and metadata (like when you change a MonoBehaviour’s class name).</p>
<p>However, there are no tools in Unity (that I know) to Refactor Data in terms of data structure changes even though it is common in software development. When we say data structure, we include stuff like: renaming fields, changing field types, moving fields from component to component, moving components from object to object, etc.</p>
<p>In the case of Prefabs and Scenes data is stored in class Component and MonoBehaviour is the most common Component. In this blog post, we treat both terms like synonymous (even though we know they are not).</p>
<p>Our use case is when we want to store data in a different (hopefully better) way when there is already a lot of created content (prefabs, scenes, etc). Even if we want to manually do that, it is not easy to know, in terms of GameObjects and Scenes, where the data is used.</p>
<p>Luckily for us, Unity provides API that includes exploring Prefabs (open them in edit mode, check if they are variants), Scenes (load/unload scenes) and Assets and that can be used for our refactors.</p>
<p>By the way, I’ve created a Github Project named <a href="https://github.com/acoppes/unity-refactoring-tools">unity-refactory-tools</a> with the code used in this blog post and also some examples to see the refactor running, if you are interested, feel free to download and try it.</p>
<p>Normally <a id="refactor_steps" name="refactor_steps">the steps</a> for data refactoring are these:</p>
<ol>
<li>Add new redundant data structure and/or types.</li>
<li>Run Automated Refactor to transform from previous data structure to new one.</li>
<li>Manually change code to use new data structure.</li>
<li>Remove old data structure and values and reserialize to remove unused serialized data.</li>
</ol>
<p>We are only covering the second step in the blog post.</p>
<p>A pseudo code for the automated Refactor would be something like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> find prefabs with the data to be modified
iterate in non variant prefabs
update data
save
iterate in prefab variants
if data was overwritten in variant
update data
save
iterate in all scenes
get objects with data
if object is not prefab instance
update data
mark scene modified
else
if data was overwritten in instance
update data
mark scene modified
if scene modified
save scene
</code></pre></div></div>
<p>In practice, our current code looks like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="n">RefactorMonoBehaviour</span><span class="p"><</span><span class="n">T</span><span class="p">>(</span><span class="kt">bool</span> <span class="n">includeScenes</span><span class="p">,</span> <span class="n">Func</span><span class="p"><</span><span class="n">GameObject</span><span class="p">,</span> <span class="kt">bool</span><span class="p">></span> <span class="n">callback</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">Component</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">guids</span> <span class="p">=</span> <span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">FindAssets</span><span class="p">(</span><span class="s">$"t:prefab"</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">prefabs</span> <span class="p">=</span> <span class="n">guids</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">g</span> <span class="p">=></span> <span class="n">AssetDatabase</span><span class="p">.</span><span class="n">LoadAssetAtPath</span><span class="p"><</span><span class="n">GameObject</span><span class="p">>(</span>
<span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">GUIDToAssetPath</span><span class="p">(</span><span class="n">g</span><span class="p">))).</span><span class="nf">ToList</span><span class="p">();</span>
<span class="c1">// Ignore prefabs without component T</span>
<span class="n">prefabs</span> <span class="p">=</span> <span class="n">prefabs</span><span class="p">.</span><span class="nf">Where</span><span class="p">(</span><span class="n">p</span> <span class="p">=></span> <span class="n">p</span><span class="p">.</span><span class="n">GetComponentInChildren</span><span class="p"><</span><span class="n">T</span><span class="p">>(</span><span class="k">true</span><span class="p">)</span> <span class="p">!=</span> <span class="k">null</span><span class="p">).</span><span class="nf">ToList</span><span class="p">();</span>
<span class="c1">// We sort by no variant prefabs first</span>
<span class="n">prefabs</span><span class="p">.</span><span class="nf">Sort</span><span class="p">(</span><span class="k">delegate</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">a</span><span class="p">,</span> <span class="n">GameObject</span> <span class="n">b</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">aIsVariant</span> <span class="p">=</span> <span class="n">PrefabUtility</span><span class="p">.</span><span class="nf">IsPartOfVariantPrefab</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">bIsVariant</span> <span class="p">=</span> <span class="n">PrefabUtility</span><span class="p">.</span><span class="nf">IsPartOfVariantPrefab</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">aIsVariant</span> <span class="p">&&</span> <span class="n">bIsVariant</span><span class="p">)</span>
<span class="k">return</span> <span class="p">-</span><span class="m">1</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">aIsVariant</span> <span class="p">&&</span> <span class="p">!</span><span class="n">bIsVariant</span><span class="p">)</span>
<span class="k">return</span> <span class="m">1</span><span class="p">;</span>
<span class="c1">// if both no variants or both variants, we just use the name to compare just to be consistent.</span>
<span class="k">return</span> <span class="n">a</span><span class="p">.</span><span class="n">name</span><span class="p">.</span><span class="nf">CompareTo</span><span class="p">(</span><span class="n">b</span><span class="p">.</span><span class="n">name</span><span class="p">);</span>
<span class="p">});</span>
<span class="n">prefabs</span><span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="k">delegate</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">o</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Debug</span><span class="p">.</span><span class="nf">Log</span><span class="p">(</span><span class="n">o</span><span class="p">.</span><span class="n">name</span><span class="p">);</span>
<span class="p">});</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">total</span> <span class="p">=</span> <span class="n">prefabs</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">DisplayProgressBar</span><span class="p">(</span><span class="s">$"Refactoring </span><span class="p">{</span><span class="n">total</span><span class="p">}</span><span class="s"> prefabs with </span><span class="p">{</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">).</span><span class="n">Name</span><span class="p">}</span><span class="s">"</span><span class="p">,</span> <span class="s">"Start"</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="n">prefabs</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">prefab</span> <span class="p">=</span> <span class="n">prefabs</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">DisplayProgressBar</span><span class="p">(</span><span class="s">$"Refactoring </span><span class="p">{</span><span class="n">prefabs</span><span class="p">.</span><span class="n">Count</span><span class="p">}</span><span class="s"> assets of type </span><span class="p">{</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">).</span><span class="n">Name</span><span class="p">}</span><span class="s">"</span><span class="p">,</span>
<span class="n">prefab</span><span class="p">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">i</span> <span class="p">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="n">total</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">contents</span> <span class="p">=</span> <span class="n">PrefabUtility</span><span class="p">.</span><span class="nf">LoadPrefabContents</span><span class="p">(</span><span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">GetAssetPath</span><span class="p">(</span><span class="n">prefab</span><span class="p">));</span>
<span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="nf">callback</span><span class="p">(</span><span class="n">contents</span><span class="p">);</span>
<span class="c1">// Just to break the loop if something is wrong...</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">result</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">PrefabUtility</span><span class="p">.</span><span class="nf">UnloadPrefabContents</span><span class="p">(</span><span class="n">contents</span><span class="p">);</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">PrefabUtility</span><span class="p">.</span><span class="nf">SaveAsPrefabAsset</span><span class="p">(</span><span class="n">contents</span><span class="p">,</span> <span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">GetAssetPath</span><span class="p">(</span><span class="n">prefab</span><span class="p">));</span>
<span class="n">PrefabUtility</span><span class="p">.</span><span class="nf">UnloadPrefabContents</span><span class="p">(</span><span class="n">contents</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">finally</span>
<span class="p">{</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">ClearProgressBar</span><span class="p">();</span>
<span class="p">}</span>
<span class="c1">// Then iterate in all scenes (if include scenes is true)</span>
<span class="k">if</span> <span class="p">(!</span><span class="n">includeScenes</span><span class="p">)</span>
<span class="k">return</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">allScenesGuids</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p"><</span><span class="kt">string</span><span class="p">>();</span>
<span class="c1">// Here we filter by all assets of type scene but under Assets folder to avoid all other scenes from </span>
<span class="c1">// external packages.</span>
<span class="n">allScenesGuids</span><span class="p">.</span><span class="nf">AddRange</span><span class="p">(</span><span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">FindAssets</span><span class="p">(</span><span class="s">"t:scene"</span><span class="p">,</span> <span class="k">new</span> <span class="p">[]</span>
<span class="p">{</span>
<span class="s">"Assets"</span>
<span class="p">}));</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">DisplayProgressBar</span><span class="p">(</span><span class="s">$"Refactoring </span><span class="p">{</span><span class="n">allScenesGuids</span><span class="p">.</span><span class="n">Count</span><span class="p">}</span><span class="s"> scenes"</span><span class="p">,</span> <span class="s">"Starting..."</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">allScenesCount</span> <span class="p">=</span> <span class="n">allScenesGuids</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="n">allScenesCount</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">sceneGuid</span> <span class="p">=</span> <span class="n">allScenesGuids</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
<span class="kt">var</span> <span class="n">scenePath</span> <span class="p">=</span> <span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">GUIDToAssetPath</span><span class="p">(</span><span class="n">sceneGuid</span><span class="p">);</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">DisplayProgressBar</span><span class="p">(</span><span class="s">$"Refactoring </span><span class="p">{</span><span class="n">allScenesGuids</span><span class="p">.</span><span class="n">Count</span><span class="p">}</span><span class="s"> scenes"</span><span class="p">,</span> <span class="n">scenePath</span><span class="p">,</span>
<span class="n">i</span> <span class="p">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span> <span class="n">allScenesCount</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">scene</span> <span class="p">=</span> <span class="n">SceneManagement</span><span class="p">.</span><span class="n">EditorSceneManager</span><span class="p">.</span><span class="nf">OpenScene</span><span class="p">(</span><span class="n">scenePath</span><span class="p">,</span>
<span class="n">SceneManagement</span><span class="p">.</span><span class="n">OpenSceneMode</span><span class="p">.</span><span class="n">Single</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">componentsList</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p"><</span><span class="n">T</span><span class="p">>();</span>
<span class="c1">// We can iterate over root objects and collect stuff to run the refactor over</span>
<span class="kt">var</span> <span class="n">rootObjects</span> <span class="p">=</span> <span class="n">scene</span><span class="p">.</span><span class="nf">GetRootGameObjects</span><span class="p">();</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">j</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">j</span> <span class="p"><</span> <span class="n">rootObjects</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">j</span><span class="p">++)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">go</span> <span class="p">=</span> <span class="n">rootObjects</span><span class="p">[</span><span class="n">j</span><span class="p">];</span>
<span class="kt">var</span> <span class="n">components</span> <span class="p">=</span> <span class="n">go</span><span class="p">.</span><span class="n">GetComponentsInChildren</span><span class="p"><</span><span class="n">T</span><span class="p">>(</span><span class="k">true</span><span class="p">);</span>
<span class="n">componentsList</span><span class="p">.</span><span class="nf">AddRange</span><span class="p">(</span><span class="n">components</span><span class="p">.</span><span class="nf">ToList</span><span class="p">());</span>
<span class="p">}</span>
<span class="kt">var</span> <span class="n">modified</span> <span class="p">=</span> <span class="k">false</span><span class="p">;</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">component</span> <span class="k">in</span> <span class="n">componentsList</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="nf">callback</span><span class="p">(</span><span class="n">component</span><span class="p">.</span><span class="n">gameObject</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">modified</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">SetDirty</span><span class="p">(</span><span class="n">component</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">modified</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">SceneManagement</span><span class="p">.</span><span class="n">EditorSceneManager</span><span class="p">.</span><span class="nf">MarkSceneDirty</span><span class="p">(</span><span class="n">scene</span><span class="p">);</span>
<span class="n">SceneManagement</span><span class="p">.</span><span class="n">EditorSceneManager</span><span class="p">.</span><span class="nf">SaveScene</span><span class="p">(</span><span class="n">scene</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">finally</span>
<span class="p">{</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">ClearProgressBar</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="change-field-type">Change field type</h3>
<p>Change a field from one type to another. For example, change to store multiple fields (normally related) into a struct.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">[Serializable]</span>
<span class="k">public</span> <span class="k">struct</span> <span class="nc">Speed</span>
<span class="p">{</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">baseValue</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">incrementValue</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">CustomBehaviour</span> <span class="p">:</span> <span class="n">MonoBehaviour</span>
<span class="p">{</span>
<span class="c1">// Redundant code here</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">speedBaseValue</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">speedIncrementValue</span><span class="p">;</span>
<span class="k">public</span> <span class="n">Speed</span> <span class="n">speed</span><span class="p">;</span>
<span class="p">}</span>
<span class="na">[MenuItem("Refactors/Refactor Custom MonoBehaviour")]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Refactor2</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">RefactorTools</span><span class="p">.</span><span class="n">RefactorMonoBehaviour</span><span class="p"><</span><span class="n">CustomBehaviour</span><span class="p">>(</span><span class="k">true</span><span class="p">,</span> <span class="k">delegate</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">gameObject</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">behaviours</span> <span class="p">=</span> <span class="n">gameObject</span><span class="p">.</span><span class="n">GetComponentsInChildren</span><span class="p"><</span><span class="n">CustomBehaviour</span><span class="p">>();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">behaviour</span> <span class="k">in</span> <span class="n">behaviours</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">behaviour</span><span class="p">.</span><span class="n">speed</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Speed</span>
<span class="p">{</span>
<span class="n">baseValue</span> <span class="p">=</span> <span class="n">behaviour</span><span class="p">.</span><span class="n">speedBaseValue</span><span class="p">,</span>
<span class="n">incrementValue</span> <span class="p">=</span> <span class="n">behaviour</span><span class="p">.</span><span class="n">speedIncrementValue</span>
<span class="p">};</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We used this kind of refactor a lot and also the case of changing from bool fields to enum type to store multiple values.</p>
<p>This could also be used to transform data for game design, like, we were storing half the speed for some enemies, so update all enemies with some criteria to double the stored speed.</p>
<h3 id="move-component-to-parent">Move Component to Parent</h3>
<p>Restructure the hierarchy of a GameObject by moving a Component to its parent object.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// here we have a simple component, stored in child object</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">ComponentA</span> <span class="p">:</span> <span class="n">MonoBehaviour</span>
<span class="p">{</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">someValue</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// The refactor would be something like this</span>
<span class="na">[MenuItem("Refactors/Refactor ComponentA to Parent")]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Refactor3</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">RefactorTools</span><span class="p">.</span><span class="n">RefactorMonoBehaviour</span><span class="p"><</span><span class="n">ComponentA</span><span class="p">>(</span><span class="k">true</span><span class="p">,</span> <span class="k">delegate</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">gameObject</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">gameObject</span><span class="p">.</span><span class="n">transform</span><span class="p">.</span><span class="n">parent</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">parentGameObject</span> <span class="p">=</span> <span class="n">gameObject</span><span class="p">.</span><span class="n">transform</span><span class="p">.</span><span class="n">parent</span><span class="p">.</span><span class="n">gameObject</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">parentComponentA</span> <span class="p">=</span> <span class="n">parentGameObject</span><span class="p">.</span><span class="n">GetComponent</span><span class="p"><</span><span class="n">ComponentA</span><span class="p">>();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">parentComponentA</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">parentComponentA</span> <span class="p">=</span> <span class="n">parentGameObject</span><span class="p">.</span><span class="n">AddComponent</span><span class="p"><</span><span class="n">ComponentA</span><span class="p">>();</span>
<span class="p">}</span>
<span class="kt">var</span> <span class="n">componentA</span> <span class="p">=</span> <span class="n">gameObject</span><span class="p">.</span><span class="n">GetComponent</span><span class="p"><</span><span class="n">ComponentA</span><span class="p">>();</span>
<span class="kt">var</span> <span class="n">json</span> <span class="p">=</span> <span class="n">JsonUtility</span><span class="p">.</span><span class="nf">ToJson</span><span class="p">(</span><span class="n">componentA</span><span class="p">);</span>
<span class="n">JsonUtility</span><span class="p">.</span><span class="nf">FromJsonOverwrite</span><span class="p">(</span><span class="n">json</span><span class="p">,</span> <span class="n">parentComponentA</span><span class="p">);</span>
<span class="n">Object</span><span class="p">.</span><span class="nf">DestroyImmediate</span><span class="p">(</span><span class="n">componentA</span><span class="p">);</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>There is no Editor Utility, that I know of, to move a Component from one object to another so we are using JSON serialization in this case (we could’ve use SerializedObject too).</p>
<p>I’m not sure if this covers all the fields properly but I suppose it does for all serializable stuff. There could be another approach using reflection.</p>
<p>If you happen to know how to use internal Unity’s API to do move Components, I would be glad to know it.</p>
<p><em>Note: if you run this refactor script multiple times, it will keep moving up in the hierarchy. We could add other considerations, like being root or being a leaf.</em></p>
<h3 id="move-component-to-children">Move Component to Children</h3>
<p>Restructure the hierarchy of a GameObject by moving a Component down.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ComponentB</span> <span class="p">:</span> <span class="n">MonoBehaviour</span>
<span class="p">{</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">anotherValue</span><span class="p">;</span>
<span class="p">}</span>
<span class="na">[MenuItem("Refactors/Refactor ComponentB to first children")]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Refactor4</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">RefactorTools</span><span class="p">.</span><span class="n">RefactorMonoBehaviour</span><span class="p"><</span><span class="n">ComponentB</span><span class="p">>(</span><span class="k">true</span><span class="p">,</span> <span class="k">delegate</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">gameObject</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// will ignore this case</span>
<span class="k">if</span> <span class="p">(</span><span class="s">"Child_WithComponentB"</span><span class="p">.</span><span class="nf">Equals</span><span class="p">(</span><span class="n">gameObject</span><span class="p">.</span><span class="n">name</span><span class="p">))</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="n">GameObject</span> <span class="n">childObject</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">gameObject</span><span class="p">.</span><span class="n">transform</span><span class="p">.</span><span class="n">childCount</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">childObject</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">GameObject</span><span class="p">(</span><span class="s">"Child_WithComponentB"</span><span class="p">);</span>
<span class="n">childObject</span><span class="p">.</span><span class="n">transform</span><span class="p">.</span><span class="nf">SetParent</span><span class="p">(</span><span class="n">gameObject</span><span class="p">.</span><span class="n">transform</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">else</span>
<span class="p">{</span>
<span class="n">childObject</span> <span class="p">=</span> <span class="n">gameObject</span><span class="p">.</span><span class="n">transform</span><span class="p">.</span><span class="nf">GetChild</span><span class="p">(</span><span class="m">0</span><span class="p">).</span><span class="n">gameObject</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">var</span> <span class="n">childComponentB</span> <span class="p">=</span> <span class="n">childObject</span><span class="p">.</span><span class="n">GetComponent</span><span class="p"><</span><span class="n">ComponentB</span><span class="p">>();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">childComponentB</span> <span class="p">==</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">childComponentB</span> <span class="p">=</span> <span class="n">childObject</span><span class="p">.</span><span class="n">AddComponent</span><span class="p"><</span><span class="n">ComponentB</span><span class="p">>();</span>
<span class="p">}</span>
<span class="kt">var</span> <span class="n">componentB</span> <span class="p">=</span> <span class="n">gameObject</span><span class="p">.</span><span class="n">GetComponent</span><span class="p"><</span><span class="n">ComponentB</span><span class="p">>();</span>
<span class="kt">var</span> <span class="n">json</span> <span class="p">=</span> <span class="n">JsonUtility</span><span class="p">.</span><span class="nf">ToJson</span><span class="p">(</span><span class="n">componentB</span><span class="p">);</span>
<span class="n">JsonUtility</span><span class="p">.</span><span class="nf">FromJsonOverwrite</span><span class="p">(</span><span class="n">json</span><span class="p">,</span> <span class="n">childComponentB</span><span class="p">);</span>
<span class="n">Object</span><span class="p">.</span><span class="nf">DestroyImmediate</span><span class="p">(</span><span class="n">componentB</span><span class="p">);</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p><em>Note: if you run the refactor script multiple times, it will keep moving it down in the hierarchy. We could add other considerations, like being root or being a leaf.</em></p>
<h3 id="considering-references-when-refactoring">Considering references when refactoring</h3>
<p>Now, what happens when, for example, that <code class="highlighter-rouge">ComponentB</code> is being referenced by a <code class="highlighter-rouge">ComponentC</code>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ComponentC</span> <span class="p">:</span> <span class="n">MonoBehaviour</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">ComponentB</span> <span class="n">referenceToB</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In those cases, what we normally do is to manually fix that reference inside the refactor script:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">...</span>
<span class="kt">var</span> <span class="n">componentC</span> <span class="p">=</span> <span class="n">gameObject</span><span class="p">.</span><span class="n">GetComponent</span><span class="p"><</span><span class="n">ComponentC</span><span class="p">>();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">componentC</span><span class="p">.</span><span class="n">referenceToB</span> <span class="p">==</span> <span class="n">componentB</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">componentC</span><span class="p">.</span><span class="n">referenceToB</span> <span class="p">=</span> <span class="n">childComponentB</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">...</span>
</code></pre></div></div>
<p>Obviously, we are only covering the case where ComponentC is used in the exactly same GameObject. If we want to do more, we could start expanding the refactor script to consider more cases but it will be still manual work, we don’t have an automatic way to cover all cases (yet).</p>
<h3 id="remove-unused-monobehaviour-class">Remove unused MonoBehaviour class</h3>
<p>When a MonoBehaviour class is removed from the code, all assets (prefabs and scene’s objects) using that MonoBehaviour will have a missing script. If you do that without previously taking care, it is a bit complicated to fix since you can’t identify the reference anymore.</p>
<p>A good practice we follow is to previously run a refactor script to remove the MonoBehaviour and only after that remove it from code.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">[MenuItem("Refactors/Refactor Custom MonoBehaviour")]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RefactorCustomMonoBehaviour</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">RefactorTools</span><span class="p">.</span><span class="n">RefactorMonoBehaviour</span><span class="p"><</span><span class="n">CustomBehaviour</span><span class="p">>(</span><span class="k">true</span><span class="p">,</span> <span class="k">delegate</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">gameObject</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">behaviours</span> <span class="p">=</span> <span class="n">gameObject</span><span class="p">.</span><span class="n">GetComponentsInChildren</span><span class="p"><</span><span class="n">CustomBehaviour</span><span class="p">>();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">behaviour</span> <span class="k">in</span> <span class="n">behaviours</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Object</span><span class="p">.</span><span class="nf">DestroyImmediate</span><span class="p">(</span><span class="n">behaviour</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>There is the special case where a GameObject only had that MonoBehaviour and there might be a good idea to remove the GameObject as well if it is empty (no children and no references to it from elsewhere).</p>
<h3 id="refactoring-data-stored-in-assets">Refactoring Data stored in Assets</h3>
<p>Refactoring assets is easier than Prefabs but still we have to follow the same <a href="#refactor_steps">steps</a> in order to conclude the refactor.</p>
<p>A pseudo code for the refactor is something like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code> find assets of type T
for asset in assets
update asset data
save asset
</code></pre></div></div>
<p>Here is a template code to use:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="n">RefactorAsset</span><span class="p"><</span><span class="n">T</span><span class="p">>(</span><span class="n">Func</span><span class="p"><</span><span class="n">T</span><span class="p">,</span> <span class="kt">bool</span><span class="p">></span> <span class="n">callback</span><span class="p">)</span> <span class="k">where</span> <span class="n">T</span> <span class="p">:</span> <span class="n">UnityEngine</span><span class="p">.</span><span class="n">Object</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">guids</span> <span class="p">=</span> <span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">FindAssets</span><span class="p">(</span><span class="s">$"t:</span><span class="p">{</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">)}</span><span class="s">"</span><span class="p">,</span> <span class="k">null</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">assets</span> <span class="p">=</span> <span class="n">guids</span><span class="p">.</span><span class="nf">Select</span><span class="p">(</span><span class="n">g</span> <span class="p">=></span> <span class="n">AssetDatabase</span><span class="p">.</span><span class="n">LoadAssetAtPath</span><span class="p"><</span><span class="n">T</span><span class="p">>(</span>
<span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">GUIDToAssetPath</span><span class="p">(</span><span class="n">g</span><span class="p">))).</span><span class="nf">ToList</span><span class="p">();</span>
<span class="k">try</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">total</span> <span class="p">=</span> <span class="n">assets</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">DisplayProgressBar</span><span class="p">(</span><span class="s">$"Refactoring </span><span class="p">{</span><span class="n">total</span><span class="p">}</span><span class="s"> assets of type </span><span class="p">{</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">).</span><span class="n">Name</span><span class="p">}</span><span class="s">"</span><span class="p">,</span> <span class="s">"Start"</span><span class="p">,</span> <span class="m">0</span><span class="p">);</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="n">assets</span><span class="p">.</span><span class="n">Count</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">asset</span> <span class="p">=</span> <span class="n">assets</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">DisplayProgressBar</span><span class="p">(</span><span class="s">$"Refactoring </span><span class="p">{</span><span class="n">assets</span><span class="p">.</span><span class="n">Count</span><span class="p">}</span><span class="s"> assets of type </span><span class="p">{</span><span class="k">typeof</span><span class="p">(</span><span class="n">T</span><span class="p">).</span><span class="n">Name</span><span class="p">}</span><span class="s">"</span><span class="p">,</span>
<span class="n">asset</span><span class="p">.</span><span class="n">name</span><span class="p">,</span>
<span class="n">i</span> <span class="p">/</span> <span class="p">(</span><span class="kt">float</span><span class="p">)</span><span class="n">total</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="nf">callback</span><span class="p">(</span><span class="n">asset</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">SetDirty</span><span class="p">(</span><span class="n">asset</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="n">AssetDatabase</span><span class="p">.</span><span class="nf">SaveAssets</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">finally</span>
<span class="p">{</span>
<span class="n">EditorUtility</span><span class="p">.</span><span class="nf">ClearProgressBar</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p><em>Note: a recommendation here is to use my <a href="https://gist.github.com/acoppes/06c536aacf5b99985ec9f3a6b2a034a2">AssetDatabaseExt</a> gist to simplify data refactors.</em></p>
<p>An example usage:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">[MenuItem("Refactors/Refactor Custom Data")]</span>
<span class="k">public</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">RefactorCustomData</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">RefactorTools</span><span class="p">.</span><span class="nf">RefactorAsset</span><span class="p">(</span><span class="k">delegate</span><span class="p">(</span><span class="n">CustomDataAsset</span> <span class="n">asset</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">asset</span><span class="p">.</span><span class="n">newValue</span> <span class="p">=</span> <span class="s">$"VALUE:</span><span class="p">{</span><span class="n">asset</span><span class="p">.</span><span class="n">previousValue</span><span class="p">}</span><span class="s">"</span><span class="p">;</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="finally">Finally</h3>
<p>This approach proved to be very helpful in our games and allowed us to improve our Data Structure while the game content was growing and since we started early on, we trained ourselves to consider more edge cases so our refactors became more consistent and solid in time.</p>
<p>One good practice is to run one refactor at a time so you can validate the results are correct and only then apply the next one. Otherwise, you will have a lot of structural changes and it is not going to be clear what was completed correctly and what not.</p>
<p>Another one is to create temporary Prefabs and Scenes with edge cases before running the Refactor to be used to manually validate the results were applied correctly. Not sure if some of this could be automated but it would be great.</p>
<p>Currently, there is no easy way to automatically synchronize Code Refactor with Data Refactor, so some Code Refactor steps must be performed manually during the Data Refactor. I suppose it could be great to have a meta script, like this pseudo code:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>void MetaRefactorIdea() {
Code.CreateFieldWithNewType();
Unity.CopyDataFromOldFieldToNewOne();
Code.ChangeCodeToReferenceNewField();
Code.RemoveOldField();
}
</code></pre></div></div>
<p>Sometimes, other serialization changes appear for data we didn’t modified. Most of the time this happens when a previous code change wasn’t reserialized yet. What we do in this case is to revert our changes (with version control), then run a reserialization on the assets (or in all assets), then commit those changes to finally run the refactor again.</p>
<p>Our current refactor approach is covering just a thin layer, it is like the “hello world” of refactors and there is a lot of space to cover, for example, using reflection to automatically change references (maybe next time) or automatically exploring other assets like Mechanim Animations to fix structural changes (moved objects, changed field names, etc).</p>
<h3 id="future-work">Future work</h3>
<p>I believe there are common Data Refactors that could be reused between projects, for example, Move Component from Object to Object.</p>
<p>As it happens with code too, specific refactors sometimes are needed and cannot be escaped from but improving tools and reusing code can help in having less manual error and cover more edge cases.</p>
<p>Also, would love to continue working on helping those reference cases, there are useful tools like FindReference which help in knowing where an asset is being used, so mixing Data Refactors with that and maybe reflection could be a great way of covering more and more refactoring data space.</p>
<p>Remember there is a Github <a href="https://github.com/acoppes/unity-refactoring-tools">unity-refactory-tools</a> with the code used here.</p>
<p>As always, thanks for reading and hope this blog post was useful and would be great to hear your opinion on this topic to improve together. See you next time.</p>
<p>If you like it, check my <a href="https://twitter.com/arielsan">twitter account</a> and retweet, it would be super helpful for me.</p>GemserkUsing Unity, most of the Data will be serialized inside Prefabs, Scenes (inside MonoBehaviour serialized fields) and other Assets. In our case we also use data only Prefabs and GameObjects. Refactoring Code is a common and recommended good practice and there are tools to help in that task. For example, Rider IDE provides a great with C# code refactors and also by adjusting Unity assets and metadata (like when you change a MonoBehaviour’s class name). However, there are no tools in Unity (that I know) to Refactor Data in terms of data structure changes even though it is common in software development. When we say data structure, we include stuff like: renaming fields, changing field types, moving fields from component to component, moving components from object to object, etc. In the case of Prefabs and Scenes data is stored in class Component and MonoBehaviour is the most common Component. In this blog post, we treat both terms like synonymous (even though we know they are not). Our use case is when we want to store data in a different (hopefully better) way when there is already a lot of created content (prefabs, scenes, etc). Even if we want to manually do that, it is not easy to know, in terms of GameObjects and Scenes, where the data is used. Luckily for us, Unity provides API that includes exploring Prefabs (open them in edit mode, check if they are variants), Scenes (load/unload scenes) and Assets and that can be used for our refactors. By the way, I’ve created a Github Project named unity-refactory-tools with the code used in this blog post and also some examples to see the refactor running, if you are interested, feel free to download and try it. Normally the steps for data refactoring are these: Add new redundant data structure and/or types. Run Automated Refactor to transform from previous data structure to new one. Manually change code to use new data structure. Remove old data structure and values and reserialize to remove unused serialized data. We are only covering the second step in the blog post. A pseudo code for the automated Refactor would be something like this: find prefabs with the data to be modified iterate in non variant prefabs update data save iterate in prefab variants if data was overwritten in variant update data save iterate in all scenes get objects with data if object is not prefab instance update data mark scene modified else if data was overwritten in instance update data mark scene modified if scene modified save scene In practice, our current code looks like this: public static void RefactorMonoBehaviour<T>(bool includeScenes, Func<GameObject, bool> callback) where T : Component { var guids = AssetDatabase.FindAssets($"t:prefab", null); var prefabs = guids.Select(g => AssetDatabase.LoadAssetAtPath<GameObject>( AssetDatabase.GUIDToAssetPath(g))).ToList(); // Ignore prefabs without component T prefabs = prefabs.Where(p => p.GetComponentInChildren<T>(true) != null).ToList(); // We sort by no variant prefabs first prefabs.Sort(delegate(GameObject a, GameObject b) { var aIsVariant = PrefabUtility.IsPartOfVariantPrefab(a); var bIsVariant = PrefabUtility.IsPartOfVariantPrefab(b); if (!aIsVariant && bIsVariant) return -1; if (aIsVariant && !bIsVariant) return 1; // if both no variants or both variants, we just use the name to compare just to be consistent. return a.name.CompareTo(b.name); }); prefabs.ForEach(delegate(GameObject o) { Debug.Log(o.name); }); try { var total = prefabs.Count; EditorUtility.DisplayProgressBar($"Refactoring {total} prefabs with {typeof(T).Name}", "Start", 0); for (var i = 0; i < prefabs.Count; i++) { var prefab = prefabs[i]; EditorUtility.DisplayProgressBar($"Refactoring {prefabs.Count} assets of type {typeof(T).Name}", prefab.name, i / (float)total); var contents = PrefabUtility.LoadPrefabContents(AssetDatabase.GetAssetPath(prefab)); var result = callback(contents); // Just to break the loop if something is wrong... if (!result) { PrefabUtility.UnloadPrefabContents(contents); break; } PrefabUtility.SaveAsPrefabAsset(contents, AssetDatabase.GetAssetPath(prefab)); PrefabUtility.UnloadPrefabContents(contents); } } finally { EditorUtility.ClearProgressBar(); } // Then iterate in all scenes (if include scenes is true) if (!includeScenes) return; var allScenesGuids = new List<string>(); // Here we filter by all assets of type scene but under Assets folder to avoid all other scenes from // external packages. allScenesGuids.AddRange(AssetDatabase.FindAssets("t:scene", new [] { "Assets" })); EditorUtility.DisplayProgressBar($"Refactoring {allScenesGuids.Count} scenes", "Starting...", 0); var allScenesCount = allScenesGuids.Count; for (var i = 0; i < allScenesCount; i++) { var sceneGuid = allScenesGuids[i]; var scenePath = AssetDatabase.GUIDToAssetPath(sceneGuid); try { EditorUtility.DisplayProgressBar($"Refactoring {allScenesGuids.Count} scenes", scenePath, i / (float) allScenesCount); var scene = SceneManagement.EditorSceneManager.OpenScene(scenePath, SceneManagement.OpenSceneMode.Single); var componentsList = new List<T>(); // We can iterate over root objects and collect stuff to run the refactor over var rootObjects = scene.GetRootGameObjects(); for (var j = 0; j < rootObjects.Length; j++) { var go = rootObjects[j]; var components = go.GetComponentsInChildren<T>(true); componentsList.AddRange(components.ToList()); } var modified = false; foreach (var component in componentsList) { var result = callback(component.gameObject); if (result) { modified = true; EditorUtility.SetDirty(component); } } if (modified) { SceneManagement.EditorSceneManager.MarkSceneDirty(scene); SceneManagement.EditorSceneManager.SaveScene(scene); } } finally { EditorUtility.ClearProgressBar(); } } } Change field type Change a field from one type to another. For example, change to store multiple fields (normally related) into a struct. [Serializable] public struct Speed { public float baseValue; public float incrementValue; } public class CustomBehaviour : MonoBehaviour { // Redundant code here public float speedBaseValue; public float speedIncrementValue; public Speed speed; } [MenuItem("Refactors/Refactor Custom MonoBehaviour")] public static void Refactor2() { RefactorTools.RefactorMonoBehaviour<CustomBehaviour>(true, delegate(GameObject gameObject) { var behaviours = gameObject.GetComponentsInChildren<CustomBehaviour>(); foreach (var behaviour in behaviours) { behaviour.speed = new Speed { baseValue = behaviour.speedBaseValue, incrementValue = behaviour.speedIncrementValue }; } return true; }); } We used this kind of refactor a lot and also the case of changing from bool fields to enum type to store multiple values. This could also be used to transform data for game design, like, we were storing half the speed for some enemies, so update all enemies with some criteria to double the stored speed. Move Component to Parent Restructure the hierarchy of a GameObject by moving a Component to its parent object. // here we have a simple component, stored in child object public class ComponentA : MonoBehaviour { public int someValue; } // The refactor would be something like this [MenuItem("Refactors/Refactor ComponentA to Parent")] public static void Refactor3() { RefactorTools.RefactorMonoBehaviour<ComponentA>(true, delegate(GameObject gameObject) { if (gameObject.transform.parent == null) return false; var parentGameObject = gameObject.transform.parent.gameObject; var parentComponentA = parentGameObject.GetComponent<ComponentA>(); if (parentComponentA == null) { parentComponentA = parentGameObject.AddComponent<ComponentA>(); } var componentA = gameObject.GetComponent<ComponentA>(); var json = JsonUtility.ToJson(componentA); JsonUtility.FromJsonOverwrite(json, parentComponentA); Object.DestroyImmediate(componentA); return true; }); } There is no Editor Utility, that I know of, to move a Component from one object to another so we are using JSON serialization in this case (we could’ve use SerializedObject too). I’m not sure if this covers all the fields properly but I suppose it does for all serializable stuff. There could be another approach using reflection. If you happen to know how to use internal Unity’s API to do move Components, I would be glad to know it. Note: if you run this refactor script multiple times, it will keep moving up in the hierarchy. We could add other considerations, like being root or being a leaf. Move Component to Children Restructure the hierarchy of a GameObject by moving a Component down. public class ComponentB : MonoBehaviour { public int anotherValue; } [MenuItem("Refactors/Refactor ComponentB to first children")] public static void Refactor4() { RefactorTools.RefactorMonoBehaviour<ComponentB>(true, delegate(GameObject gameObject) { // will ignore this case if ("Child_WithComponentB".Equals(gameObject.name)) return false; GameObject childObject; if (gameObject.transform.childCount == 0) { childObject = new GameObject("Child_WithComponentB"); childObject.transform.SetParent(gameObject.transform); } else { childObject = gameObject.transform.GetChild(0).gameObject; } var childComponentB = childObject.GetComponent<ComponentB>(); if (childComponentB == null) { childComponentB = childObject.AddComponent<ComponentB>(); } var componentB = gameObject.GetComponent<ComponentB>(); var json = JsonUtility.ToJson(componentB); JsonUtility.FromJsonOverwrite(json, childComponentB); Object.DestroyImmediate(componentB); return true; }); } Note: if you run the refactor script multiple times, it will keep moving it down in the hierarchy. We could add other considerations, like being root or being a leaf. Considering references when refactoring Now, what happens when, for example, that ComponentB is being referenced by a ComponentC: public class ComponentC : MonoBehaviour { public ComponentB referenceToB; } In those cases, what we normally do is to manually fix that reference inside the refactor script: ... var componentC = gameObject.GetComponent<ComponentC>(); if (componentC.referenceToB == componentB) { componentC.referenceToB = childComponentB; } ... Obviously, we are only covering the case where ComponentC is used in the exactly same GameObject. If we want to do more, we could start expanding the refactor script to consider more cases but it will be still manual work, we don’t have an automatic way to cover all cases (yet). Remove unused MonoBehaviour class When a MonoBehaviour class is removed from the code, all assets (prefabs and scene’s objects) using that MonoBehaviour will have a missing script. If you do that without previously taking care, it is a bit complicated to fix since you can’t identify the reference anymore. A good practice we follow is to previously run a refactor script to remove the MonoBehaviour and only after that remove it from code. [MenuItem("Refactors/Refactor Custom MonoBehaviour")] public static void RefactorCustomMonoBehaviour() { RefactorTools.RefactorMonoBehaviour<CustomBehaviour>(true, delegate(GameObject gameObject) { var behaviours = gameObject.GetComponentsInChildren<CustomBehaviour>(); foreach (var behaviour in behaviours) { Object.DestroyImmediate(behaviour); } return true; }); } There is the special case where a GameObject only had that MonoBehaviour and there might be a good idea to remove the GameObject as well if it is empty (no children and no references to it from elsewhere). Refactoring Data stored in Assets Refactoring assets is easier than Prefabs but still we have to follow the same steps in order to conclude the refactor. A pseudo code for the refactor is something like this: find assets of type T for asset in assets update asset data save asset Here is a template code to use: public static void RefactorAsset<T>(Func<T, bool> callback) where T : UnityEngine.Object { var guids = AssetDatabase.FindAssets($"t:{typeof(T)}", null); var assets = guids.Select(g => AssetDatabase.LoadAssetAtPath<T>( AssetDatabase.GUIDToAssetPath(g))).ToList(); try { var total = assets.Count; EditorUtility.DisplayProgressBar($"Refactoring {total} assets of type {typeof(T).Name}", "Start", 0); for (var i = 0; i < assets.Count; i++) { var asset = assets[i]; EditorUtility.DisplayProgressBar($"Refactoring {assets.Count} assets of type {typeof(T).Name}", asset.name, i / (float)total); var result = callback(asset); if (result) { EditorUtility.SetDirty(asset); } } AssetDatabase.SaveAssets(); } finally { EditorUtility.ClearProgressBar(); } } Note: a recommendation here is to use my AssetDatabaseExt gist to simplify data refactors. An example usage: [MenuItem("Refactors/Refactor Custom Data")] public static void RefactorCustomData() { RefactorTools.RefactorAsset(delegate(CustomDataAsset asset) { asset.newValue = $"VALUE:{asset.previousValue}"; return true; }); } Finally This approach proved to be very helpful in our games and allowed us to improve our Data Structure while the game content was growing and since we started early on, we trained ourselves to consider more edge cases so our refactors became more consistent and solid in time. One good practice is to run one refactor at a time so you can validate the results are correct and only then apply the next one. Otherwise, you will have a lot of structural changes and it is not going to be clear what was completed correctly and what not. Another one is to create temporary Prefabs and Scenes with edge cases before running the Refactor to be used to manually validate the results were applied correctly. Not sure if some of this could be automated but it would be great. Currently, there is no easy way to automatically synchronize Code Refactor with Data Refactor, so some Code Refactor steps must be performed manually during the Data Refactor. I suppose it could be great to have a meta script, like this pseudo code: void MetaRefactorIdea() { Code.CreateFieldWithNewType(); Unity.CopyDataFromOldFieldToNewOne(); Code.ChangeCodeToReferenceNewField(); Code.RemoveOldField(); } Sometimes, other serialization changes appear for data we didn’t modified. Most of the time this happens when a previous code change wasn’t reserialized yet. What we do in this case is to revert our changes (with version control), then run a reserialization on the assets (or in all assets), then commit those changes to finally run the refactor again. Our current refactor approach is covering just a thin layer, it is like the “hello world” of refactors and there is a lot of space to cover, for example, using reflection to automatically change references (maybe next time) or automatically exploring other assets like Mechanim Animations to fix structural changes (moved objects, changed field names, etc). Future work I believe there are common Data Refactors that could be reused between projects, for example, Move Component from Object to Object. As it happens with code too, specific refactors sometimes are needed and cannot be escaped from but improving tools and reusing code can help in having less manual error and cover more edge cases. Also, would love to continue working on helping those reference cases, there are useful tools like FindReference which help in knowing where an asset is being used, so mixing Data Refactors with that and maybe reflection could be a great way of covering more and more refactoring data space. Remember there is a Github unity-refactory-tools with the code used here. As always, thanks for reading and hope this blog post was useful and would be great to hear your opinion on this topic to improve together. See you next time. If you like it, check my twitter account and retweet, it would be super helpful for me.Using Custom Editors to interact with Unity ECS World2020-08-13T00:00:00-03:002020-08-13T00:00:00-03:00https://blog.gemserk.com/2020/08/13/using-custom-editors-to-interact-with-ecs<h1 id="introduction">Introduction</h1>
<p>After reading, <a href="https://twitter.com/arielsan/status/1294096960383856640">follow, retweet, like and or comment</a> if you like it.</p>
<p>By default, the Unity’s Editor comes with tools like the Inspector window to help you visualize and modify GameObjects’s values while editing or even at runtime.</p>
<p>For example, if you add a MonoBehaviour like this one to your GameObject:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ExampleFieldsBehaviour</span> <span class="p">:</span> <span class="n">MonoBehaviour</span>
<span class="p">{</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">totalHealth</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">speed</span><span class="p">;</span>
<span class="p">[</span><span class="n">SerializeField</span><span class="p">]</span>
<span class="k">private</span> <span class="kt">int</span> <span class="n">power</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It will be visualized by the default Inspector like this:</p>
<p><img src="/wp-content/uploads/2020/08/debug_example_fields.png" alt="" /></p>
<p>With the upcoming <a href="https://docs.unity3d.com/Packages/com.unity.entities@latest/">Unity ECS</a>, GameObjects can still be used to design content with the <a href="https://docs.unity3d.com/Packages/com.unity.entities@0.7/manual/gp_overview.html">GameObject conversion</a> workflow. However, at runtime, once the conversion was processed, even though those values can be edited (if you decided not to destroy the GameObject after the conversion) in the Inspector Window, they will not be synchronized to/from the corresponding Entity.</p>
<p>To visualize Entities’ values there is a new window named Entity Debugger that shows all its Components’ values in readonly mode. It also shows which systems are processing that Entity given its current Components.</p>
<p><a href="/wp-content/uploads/2020/08/debug_example_entitydebugger.png"><img src="/wp-content/uploads/2020/08/debug_example_entitydebugger.png" alt="" /></a></p>
<h1 id="how-to-modify-ecs-values">How to modify ECS values</h1>
<p>In order to modify values using Unity ECS, custom tools have to be created. I want to share a possible way to do with the Unity’s Editor.</p>
<p><em>Note: In general, modifying values at runtime could be direct in some cases (change the current health) but in others it might need you to know internal game logic to avoid leaving an invalid state.</em></p>
<p>In a nutshell, the idea is to create one or more GameObjects per Entity, with one or more debug MonoBehaviours and, for each one of those, create a Custom Editor exposing interesting values and actions.</p>
<p>Here is an example of the result:</p>
<p><a href="/wp-content/uploads/2020/08/examplerunning.gif"><img src="/wp-content/uploads/2020/08/examplerunning.gif" alt="" /></a></p>
<h1 id="defining-the-structure">Defining the structure</h1>
<p>Let’s start with the ECS Components:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Tag to identify the entities we want to debug</span>
<span class="k">public</span> <span class="k">struct</span> <span class="nc">UnitComponent</span> <span class="p">:</span> <span class="n">IComponentData</span> <span class="p">{</span> <span class="p">}</span>
<span class="c1">// The component to debug in the Custom Editor</span>
<span class="k">public</span> <span class="k">struct</span> <span class="nc">HealthComponent</span> <span class="p">:</span> <span class="n">IComponentData</span> <span class="p">{</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">current</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">total</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// Another component to perform damage to an entity</span>
<span class="k">public</span> <span class="k">struct</span> <span class="nc">Damage</span> <span class="p">:</span> <span class="n">IComponentData</span> <span class="p">{</span>
<span class="k">public</span> <span class="n">Entity</span> <span class="n">target</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">damage</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Here is the MonoBehaviour used as debug intermediary and to create the Custom Editor later:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">DebugEntityMonoBehaviour</span> <span class="p">:</span> <span class="n">MonoBehaviour</span> <span class="p">{</span>
<span class="c1">// these are going to reflect the health value </span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">current</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">total</span><span class="p">;</span>
<span class="c1">// the reference to the entity</span>
<span class="k">public</span> <span class="n">Entity</span> <span class="n">entity</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="creating-debug-gameobjects-per-entity">Creating debug GameObjects per Entity</h1>
<p>In order to create a debug object per Entity we want to debug, we are going to use a ComponentSystem and a <a href="https://docs.unity3d.com/Packages/com.unity.entities@0.9/manual/system_state_components.html">ISystemStateSharedComponentData</a>.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// This one just stores a reference to the debug object</span>
<span class="k">public</span> <span class="k">struct</span> <span class="nc">DebugEntitySystemComponent</span> <span class="p">:</span> <span class="n">ISystemStateSharedComponentData</span><span class="p">,</span> <span class="n">IEquatable</span><span class="p"><</span><span class="n">DebugEntitySystemComponent</span><span class="p">></span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">DebugEntityMonoBehaviour</span> <span class="n">debug</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">DebugEntitySystemComponent</span> <span class="n">other</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">debug</span><span class="p">,</span> <span class="n">other</span><span class="p">.</span><span class="n">debug</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="nf">Equals</span><span class="p">(</span><span class="kt">object</span> <span class="n">obj</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">return</span> <span class="n">obj</span> <span class="k">is</span> <span class="n">DebugEntitySystemComponent</span> <span class="n">other</span> <span class="p">&&</span> <span class="nf">Equals</span><span class="p">(</span><span class="n">other</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="kt">int</span> <span class="nf">GetHashCode</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="n">debug</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">?</span> <span class="n">debug</span><span class="p">.</span><span class="nf">GetHashCode</span><span class="p">()</span> <span class="p">:</span> <span class="m">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DebugEntitiesSystem</span> <span class="p">:</span> <span class="n">ComponentSystem</span>
<span class="p">{</span>
<span class="k">protected</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnUpdate</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// create the debug stuff...</span>
<span class="n">Entities</span>
<span class="c1">// we check only for entities with UnitComponent which are the ones we are interest on.</span>
<span class="p">.</span><span class="n">WithAll</span><span class="p"><</span><span class="n">UnitComponent</span><span class="p">>()</span>
<span class="p">.</span><span class="n">WithNone</span><span class="p"><</span><span class="n">DebugEntitySystemComponent</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="k">delegate</span><span class="p">(</span><span class="n">Entity</span> <span class="n">entity</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">name</span> <span class="p">=</span> <span class="n">EntityManager</span><span class="p">.</span><span class="nf">GetName</span><span class="p">(</span><span class="n">entity</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="kt">string</span><span class="p">.</span><span class="nf">IsNullOrEmpty</span><span class="p">(</span><span class="n">name</span><span class="p">))</span>
<span class="n">name</span> <span class="p">=</span> <span class="s">$"Entity</span><span class="p">{</span><span class="n">entity</span><span class="p">.</span><span class="n">Index</span><span class="p">}</span><span class="s">"</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">go</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">GameObject</span><span class="p">(</span><span class="s">$"DebugFor-</span><span class="p">{</span><span class="n">name</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">debug</span> <span class="p">=</span> <span class="n">go</span><span class="p">.</span><span class="n">AddComponent</span><span class="p"><</span><span class="n">DebugEntityMonoBehaviour</span><span class="p">>();</span>
<span class="n">PostUpdateCommands</span><span class="p">.</span><span class="nf">AddSharedComponent</span><span class="p">(</span><span class="n">entity</span><span class="p">,</span> <span class="k">new</span> <span class="n">DebugEntitySystemComponent</span>
<span class="p">{</span>
<span class="n">debug</span> <span class="p">=</span> <span class="n">debug</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="c1">// update the debug stuff</span>
<span class="n">Entities</span>
<span class="p">.</span><span class="n">WithAll</span><span class="p"><</span><span class="n">UnitComponent</span><span class="p">,</span> <span class="n">DebugEntitySystemComponent</span><span class="p">,</span> <span class="n">HealthComponent</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="k">delegate</span><span class="p">(</span><span class="n">Entity</span> <span class="n">entity</span><span class="p">,</span> <span class="n">DebugEntitySystemComponent</span> <span class="n">debug</span><span class="p">,</span> <span class="k">ref</span> <span class="n">HealthComponent</span> <span class="n">health</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">debug</span><span class="p">.</span><span class="n">debug</span><span class="p">.</span><span class="n">entity</span> <span class="p">=</span> <span class="n">entity</span><span class="p">;</span>
<span class="n">debug</span><span class="p">.</span><span class="n">debug</span><span class="p">.</span><span class="n">current</span> <span class="p">=</span> <span class="n">health</span><span class="p">.</span><span class="n">current</span><span class="p">;</span>
<span class="n">debug</span><span class="p">.</span><span class="n">debug</span><span class="p">.</span><span class="n">total</span> <span class="p">=</span> <span class="n">health</span><span class="p">.</span><span class="n">total</span><span class="p">;</span>
<span class="p">});</span>
<span class="c1">// destroy the debug stuff...</span>
<span class="n">Entities</span>
<span class="p">.</span><span class="n">WithAll</span><span class="p"><</span><span class="n">DebugEntitySystemComponent</span><span class="p">>()</span>
<span class="p">.</span><span class="n">WithNone</span><span class="p"><</span><span class="n">UnitComponent</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="k">delegate</span><span class="p">(</span><span class="n">Entity</span> <span class="n">entity</span><span class="p">,</span> <span class="n">DebugEntitySystemComponent</span> <span class="n">debug</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">GameObject</span><span class="p">.</span><span class="nf">Destroy</span><span class="p">(</span><span class="n">debug</span><span class="p">.</span><span class="n">debug</span><span class="p">.</span><span class="n">gameObject</span><span class="p">);</span>
<span class="n">PostUpdateCommands</span><span class="p">.</span><span class="n">RemoveComponent</span><span class="p"><</span><span class="n">DebugEntitySystemComponent</span><span class="p">>(</span><span class="n">entity</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This system will create a new debug GameObject for each Entity of interest (the ones with UnitComponent) that doesn’t have one yet, update it if it has one, and destroy it when the Entity was destroyed.</p>
<h1 id="creating-the-custom-editor">Creating the Custom Editor</h1>
<p>Now that there is one debug GameObject per Entity with the DebugEntityMonoBehaviour, it is time to create the Custom Editor:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">[CustomEditor(typeof(DebugEntityMonoBehaviour))]</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">DebugEntityInspector</span> <span class="p">:</span> <span class="n">UnityEditor</span><span class="p">.</span><span class="n">Editor</span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnInspectorGUI</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">debug</span> <span class="p">=</span> <span class="n">target</span> <span class="k">as</span> <span class="n">DebugEntityMonoBehaviour</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">entityManager</span> <span class="p">=</span> <span class="n">World</span><span class="p">.</span><span class="n">DefaultGameObjectInjectionWorld</span><span class="p">.</span><span class="n">EntityManager</span><span class="p">;</span>
<span class="n">EditorGUI</span><span class="p">.</span><span class="nf">BeginChangeCheck</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">newCurrent</span> <span class="p">=</span> <span class="n">EditorGUILayout</span><span class="p">.</span><span class="nf">IntField</span><span class="p">(</span><span class="s">"Current Health"</span><span class="p">,</span> <span class="n">debug</span><span class="p">.</span><span class="n">current</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">newTotal</span> <span class="p">=</span> <span class="n">EditorGUILayout</span><span class="p">.</span><span class="nf">IntField</span><span class="p">(</span><span class="s">"Total Health"</span><span class="p">,</span> <span class="n">debug</span><span class="p">.</span><span class="n">total</span><span class="p">);</span>
<span class="n">EditorGUI</span><span class="p">.</span><span class="nf">BeginDisabledGroup</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
<span class="n">EditorGUILayout</span><span class="p">.</span><span class="nf">IntField</span><span class="p">(</span><span class="s">"Percentage"</span><span class="p">,</span> <span class="n">debug</span><span class="p">.</span><span class="n">current</span> <span class="p">*</span> <span class="m">100</span> <span class="p">/</span> <span class="n">debug</span><span class="p">.</span><span class="n">total</span><span class="p">);</span>
<span class="n">EditorGUI</span><span class="p">.</span><span class="nf">EndDisabledGroup</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="n">EditorGUI</span><span class="p">.</span><span class="nf">EndChangeCheck</span><span class="p">())</span>
<span class="p">{</span>
<span class="n">entityManager</span><span class="p">.</span><span class="nf">SetComponentData</span><span class="p">(</span><span class="n">debug</span><span class="p">.</span><span class="n">entity</span><span class="p">,</span> <span class="k">new</span> <span class="n">HealthComponent</span>
<span class="p">{</span>
<span class="n">current</span> <span class="p">=</span> <span class="n">newCurrent</span><span class="p">,</span>
<span class="n">total</span> <span class="p">=</span> <span class="n">newTotal</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">GUILayout</span><span class="p">.</span><span class="nf">Button</span><span class="p">(</span><span class="s">"Perform Damage"</span><span class="p">))</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">target</span> <span class="p">=</span> <span class="n">debug</span><span class="p">.</span><span class="n">entity</span><span class="p">;</span>
<span class="kt">var</span> <span class="n">damageEntity</span> <span class="p">=</span> <span class="n">entityManager</span><span class="p">.</span><span class="nf">CreateEntity</span><span class="p">(</span><span class="n">ComponentType</span><span class="p">.</span><span class="n">ReadWrite</span><span class="p"><</span><span class="n">Damage</span><span class="p">>());</span>
<span class="n">entityManager</span><span class="p">.</span><span class="nf">SetComponentData</span><span class="p">(</span><span class="n">damageEntity</span><span class="p">,</span> <span class="k">new</span> <span class="n">Damage</span>
<span class="p">{</span>
<span class="n">target</span> <span class="p">=</span> <span class="n">target</span><span class="p">,</span>
<span class="n">damage</span> <span class="p">=</span> <span class="m">5</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="n">GUILayout</span><span class="p">.</span><span class="nf">Button</span><span class="p">(</span><span class="s">"Destroy"</span><span class="p">))</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">target</span> <span class="p">=</span> <span class="n">debug</span><span class="p">.</span><span class="n">entity</span><span class="p">;</span>
<span class="n">entityManager</span><span class="p">.</span><span class="nf">DestroyEntity</span><span class="p">(</span><span class="n">target</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Here is how it looks like:</p>
<p><img src="/wp-content/uploads/2020/08/debug_custom_editor2.png" alt="" /></p>
<p>That’s it, now each time an Entity with a UnitComponent is created, the system will create a debug GameObject with the MonoBehaviour and start synchronizing values to show them in the Inspector. The CustomEditor will allow us to interact with ECS changing values or performing actions. Now new fields can be exposed and new actions can be created.</p>
<p>Watch again everything working together:</p>
<p><a href="/wp-content/uploads/2020/08/examplerunning.gif"><img src="/wp-content/uploads/2020/08/examplerunning.gif" alt="" /></a></p>
<h1 id="extend-using-gizmos">Extend using Gizmos</h1>
<p>We can also use Gizmos to draw other interesting information in the Scene view. As example, I created a new AttackComponent with the attack range.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">struct</span> <span class="nc">AttackComponent</span> <span class="p">:</span> <span class="n">IComponentData</span> <span class="p">{</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">range</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Then modified the debug MonoBehaviour to support a new value and added the DrawGizmos method:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">DebugEntityMonoBehaviour</span> <span class="p">:</span> <span class="n">MonoBehaviour</span>
<span class="p">{</span>
<span class="c1">// previous stuff ...</span>
<span class="k">public</span> <span class="kt">float</span> <span class="n">attackRange</span><span class="p">;</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">OnDrawGizmos</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">attackRange</span> <span class="p">></span> <span class="m">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Gizmos</span><span class="p">.</span><span class="n">color</span> <span class="p">=</span> <span class="n">Color</span><span class="p">.</span><span class="n">red</span><span class="p">;</span>
<span class="n">Gizmos</span><span class="p">.</span><span class="nf">DrawWireSphere</span><span class="p">(</span><span class="n">transform</span><span class="p">.</span><span class="n">position</span><span class="p">,</span> <span class="n">attackRange</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And now extended the DebugEntitiesSystem with a new query to copy the attack range to the MonoBehaviour if there is an AttackComponent in the Entity.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">// ....</span>
<span class="n">Entities</span>
<span class="p">.</span><span class="n">WithAll</span><span class="p"><</span><span class="n">UnitComponent</span><span class="p">,</span> <span class="n">DebugEntitySystemComponent</span><span class="p">,</span> <span class="n">AttackComponent</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="k">delegate</span><span class="p">(</span><span class="n">Entity</span> <span class="n">entity</span><span class="p">,</span> <span class="n">DebugEntitySystemComponent</span> <span class="n">debug</span><span class="p">,</span> <span class="k">ref</span> <span class="n">AttackComponent</span> <span class="n">attack</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">debug</span><span class="p">.</span><span class="n">debug</span><span class="p">.</span><span class="n">attackRange</span> <span class="p">=</span> <span class="n">attack</span><span class="p">.</span><span class="n">range</span><span class="p">;</span>
<span class="p">});</span>
<span class="c1">// .... </span>
</code></pre></div></div>
<p>That will work, but all Gizmos are going to be drawn at 0,0, since our GameObjects are not considering the Entity’s position. Now, for that to make sense, we need to copy also the translation to the GameObject’s Transform, for that, I created another query:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="c1">// ....</span>
<span class="n">Entities</span>
<span class="p">.</span><span class="n">WithAll</span><span class="p"><</span><span class="n">UnitComponent</span><span class="p">,</span> <span class="n">DebugEntitySystemComponent</span><span class="p">,</span> <span class="n">Translation</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">ForEach</span><span class="p">(</span><span class="k">delegate</span><span class="p">(</span><span class="n">Entity</span> <span class="n">entity</span><span class="p">,</span> <span class="n">DebugEntitySystemComponent</span> <span class="n">debug</span><span class="p">,</span> <span class="k">ref</span> <span class="n">Translation</span> <span class="n">t</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">debug</span><span class="p">.</span><span class="n">debug</span><span class="p">.</span><span class="n">transform</span><span class="p">.</span><span class="n">position</span> <span class="p">=</span> <span class="n">t</span><span class="p">.</span><span class="n">Value</span><span class="p">;</span>
<span class="p">});</span>
<span class="c1">// .... </span>
</code></pre></div></div>
<p>So, for all Entities with Translation Component, the system will copy that value to the GameObject’s Transform.</p>
<p>Here is the result:</p>
<p><a href="/wp-content/uploads/2020/08/debug_gizmos_transform.png"><img src="/wp-content/uploads/2020/08/debug_gizmos_transform.png" alt="" /></a></p>
<h2 id="pros">Pros</h2>
<ul>
<li>We can take advantage of all Unity’s Editor tools, even accessing the UnityEditor API. For example, we could Handles to move an Entity with a Translation Component.</li>
<li>Since you have to create the inspector logic by hand, in some cases game logic can be reused for some actions and avoid breaking the game by touching values directly that could leave an invalid state.</li>
<li>It is super easy to implement (we are following a similar approach with my dev team).</li>
<li>Expose what you want, and even make the exposure optional, like rendering values only if the Entity has or not a Component.</li>
</ul>
<h2 id="cons">Cons</h2>
<ul>
<li>Manually maintained, there is no auto generated inspector by default.</li>
<li>Only usable in Unity’s Editor.</li>
<li>Doesn’t scale so well, but I believe the automatic option (exposing all GameObject’s values) doesn’t either.</li>
</ul>
<h1 id="conclusion">Conclusion</h1>
<p>I like that you can’t easily edit ECS values through the Entity Debugger nor the Inspector and to have to make your own tools. In my experience, you normally don’t want to change every value at runtime, maybe you do read some values to check the current game state and maybe, for some specific cases, you want to change a value or take an action to test some behaviour. In some way, it reminds me the <a href="https://www.gdcvault.com/play/1025284/Tools-Tutorial-Day-A-Tale">GDC talk about using different data schemas</a> since the idea is to expose meaningful values to designers and debuggers which might involve some transformation in the middle.</p>
<p>Of course you can create a tool using reflection and automatically generating code to create these debug objects explained in the blog post but you will end up with tons of unused debug stuff and start working in a way to turn off unused values.</p>
<p>The technique presented here is a simple approach, might not scale so well but can be quickly implemented to have some visual tools to interact with the ECS World. I like it I would love to have this kind of tools in the builds and not only in the Unity’s Editor. I suppose a better approach could be to start creating tools integrated in the game depending a bit more to game concepts and logic. That solution could use Unity’s UI now that I think (I might try to work on that a bit and write another blog post).</p>
<p>In case you are interested in the code, <a href="https://github.com/acoppes/DebugToolsEcsExample">here is the Github project used for this article</a>.</p>
<p>It was a simple article but, as always, I hope you liked it and If you did, <a href="https://twitter.com/arielsan/status/1294096960383856640">follow, retweet, like and or comment</a>, thanks!!</p>arielsanIntroduction After reading, follow, retweet, like and or comment if you like it. By default, the Unity’s Editor comes with tools like the Inspector window to help you visualize and modify GameObjects’s values while editing or even at runtime. For example, if you add a MonoBehaviour like this one to your GameObject: public class ExampleFieldsBehaviour : MonoBehaviour { public float totalHealth; public float speed; [SerializeField] private int power; } It will be visualized by the default Inspector like this: With the upcoming Unity ECS, GameObjects can still be used to design content with the GameObject conversion workflow. However, at runtime, once the conversion was processed, even though those values can be edited (if you decided not to destroy the GameObject after the conversion) in the Inspector Window, they will not be synchronized to/from the corresponding Entity. To visualize Entities’ values there is a new window named Entity Debugger that shows all its Components’ values in readonly mode. It also shows which systems are processing that Entity given its current Components. How to modify ECS values In order to modify values using Unity ECS, custom tools have to be created. I want to share a possible way to do with the Unity’s Editor. Note: In general, modifying values at runtime could be direct in some cases (change the current health) but in others it might need you to know internal game logic to avoid leaving an invalid state. In a nutshell, the idea is to create one or more GameObjects per Entity, with one or more debug MonoBehaviours and, for each one of those, create a Custom Editor exposing interesting values and actions. Here is an example of the result: Defining the structure Let’s start with the ECS Components: // Tag to identify the entities we want to debug public struct UnitComponent : IComponentData { } // The component to debug in the Custom Editor public struct HealthComponent : IComponentData { public int current; public int total; } // Another component to perform damage to an entity public struct Damage : IComponentData { public Entity target; public int damage; } Here is the MonoBehaviour used as debug intermediary and to create the Custom Editor later: public class DebugEntityMonoBehaviour : MonoBehaviour { // these are going to reflect the health value public float current; public float total; // the reference to the entity public Entity entity; } Creating debug GameObjects per Entity In order to create a debug object per Entity we want to debug, we are going to use a ComponentSystem and a ISystemStateSharedComponentData. // This one just stores a reference to the debug object public struct DebugEntitySystemComponent : ISystemStateSharedComponentData, IEquatable<DebugEntitySystemComponent> { public DebugEntityMonoBehaviour debug; public bool Equals(DebugEntitySystemComponent other) { return Equals(debug, other.debug); } public override bool Equals(object obj) { return obj is DebugEntitySystemComponent other && Equals(other); } public override int GetHashCode() { return (debug != null ? debug.GetHashCode() : 0); } } public class DebugEntitiesSystem : ComponentSystem { protected override void OnUpdate() { // create the debug stuff... Entities // we check only for entities with UnitComponent which are the ones we are interest on. .WithAll<UnitComponent>() .WithNone<DebugEntitySystemComponent>() .ForEach(delegate(Entity entity) { var name = EntityManager.GetName(entity); if (string.IsNullOrEmpty(name)) name = $"Entity{entity.Index}"; var go = new GameObject($"DebugFor-{name}"); var debug = go.AddComponent<DebugEntityMonoBehaviour>(); PostUpdateCommands.AddSharedComponent(entity, new DebugEntitySystemComponent { debug = debug }); }); // update the debug stuff Entities .WithAll<UnitComponent, DebugEntitySystemComponent, HealthComponent>() .ForEach(delegate(Entity entity, DebugEntitySystemComponent debug, ref HealthComponent health) { debug.debug.entity = entity; debug.debug.current = health.current; debug.debug.total = health.total; }); // destroy the debug stuff... Entities .WithAll<DebugEntitySystemComponent>() .WithNone<UnitComponent>() .ForEach(delegate(Entity entity, DebugEntitySystemComponent debug) { GameObject.Destroy(debug.debug.gameObject); PostUpdateCommands.RemoveComponent<DebugEntitySystemComponent>(entity); }); } } This system will create a new debug GameObject for each Entity of interest (the ones with UnitComponent) that doesn’t have one yet, update it if it has one, and destroy it when the Entity was destroyed. Creating the Custom Editor Now that there is one debug GameObject per Entity with the DebugEntityMonoBehaviour, it is time to create the Custom Editor: [CustomEditor(typeof(DebugEntityMonoBehaviour))] public class DebugEntityInspector : UnityEditor.Editor { public override void OnInspectorGUI() { var debug = target as DebugEntityMonoBehaviour; var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager; EditorGUI.BeginChangeCheck(); var newCurrent = EditorGUILayout.IntField("Current Health", debug.current); var newTotal = EditorGUILayout.IntField("Total Health", debug.total); EditorGUI.BeginDisabledGroup(true); EditorGUILayout.IntField("Percentage", debug.current * 100 / debug.total); EditorGUI.EndDisabledGroup(); if (EditorGUI.EndChangeCheck()) { entityManager.SetComponentData(debug.entity, new HealthComponent { current = newCurrent, total = newTotal }); } if (GUILayout.Button("Perform Damage")) { var target = debug.entity; var damageEntity = entityManager.CreateEntity(ComponentType.ReadWrite<Damage>()); entityManager.SetComponentData(damageEntity, new Damage { target = target, damage = 5 }); } if (GUILayout.Button("Destroy")) { var target = debug.entity; entityManager.DestroyEntity(target); } } } Here is how it looks like: That’s it, now each time an Entity with a UnitComponent is created, the system will create a debug GameObject with the MonoBehaviour and start synchronizing values to show them in the Inspector. The CustomEditor will allow us to interact with ECS changing values or performing actions. Now new fields can be exposed and new actions can be created. Watch again everything working together: Extend using Gizmos We can also use Gizmos to draw other interesting information in the Scene view. As example, I created a new AttackComponent with the attack range. public struct AttackComponent : IComponentData { public float range; } Then modified the debug MonoBehaviour to support a new value and added the DrawGizmos method: public class DebugEntityMonoBehaviour : MonoBehaviour { // previous stuff ... public float attackRange; private void OnDrawGizmos() { if (attackRange > 0) { Gizmos.color = Color.red; Gizmos.DrawWireSphere(transform.position, attackRange); } } } And now extended the DebugEntitiesSystem with a new query to copy the attack range to the MonoBehaviour if there is an AttackComponent in the Entity. // .... Entities .WithAll<UnitComponent, DebugEntitySystemComponent, AttackComponent>() .ForEach(delegate(Entity entity, DebugEntitySystemComponent debug, ref AttackComponent attack) { debug.debug.attackRange = attack.range; }); // .... That will work, but all Gizmos are going to be drawn at 0,0, since our GameObjects are not considering the Entity’s position. Now, for that to make sense, we need to copy also the translation to the GameObject’s Transform, for that, I created another query: // .... Entities .WithAll<UnitComponent, DebugEntitySystemComponent, Translation>() .ForEach(delegate(Entity entity, DebugEntitySystemComponent debug, ref Translation t) { debug.debug.transform.position = t.Value; }); // .... So, for all Entities with Translation Component, the system will copy that value to the GameObject’s Transform. Here is the result: Pros We can take advantage of all Unity’s Editor tools, even accessing the UnityEditor API. For example, we could Handles to move an Entity with a Translation Component. Since you have to create the inspector logic by hand, in some cases game logic can be reused for some actions and avoid breaking the game by touching values directly that could leave an invalid state. It is super easy to implement (we are following a similar approach with my dev team). Expose what you want, and even make the exposure optional, like rendering values only if the Entity has or not a Component. Cons Manually maintained, there is no auto generated inspector by default. Only usable in Unity’s Editor. Doesn’t scale so well, but I believe the automatic option (exposing all GameObject’s values) doesn’t either. Conclusion I like that you can’t easily edit ECS values through the Entity Debugger nor the Inspector and to have to make your own tools. In my experience, you normally don’t want to change every value at runtime, maybe you do read some values to check the current game state and maybe, for some specific cases, you want to change a value or take an action to test some behaviour. In some way, it reminds me the GDC talk about using different data schemas since the idea is to expose meaningful values to designers and debuggers which might involve some transformation in the middle. Of course you can create a tool using reflection and automatically generating code to create these debug objects explained in the blog post but you will end up with tons of unused debug stuff and start working in a way to turn off unused values. The technique presented here is a simple approach, might not scale so well but can be quickly implemented to have some visual tools to interact with the ECS World. I like it I would love to have this kind of tools in the builds and not only in the Unity’s Editor. I suppose a better approach could be to start creating tools integrated in the game depending a bit more to game concepts and logic. That solution could use Unity’s UI now that I think (I might try to work on that a bit and write another blog post). In case you are interested in the code, here is the Github project used for this article. It was a simple article but, as always, I hope you liked it and If you did, follow, retweet, like and or comment, thanks!!Using Unity Prefabs and GameObjects only for data.2020-05-26T00:00:00-03:002020-05-26T00:00:00-03:00https://blog.gemserk.com/2020/05/26/using-unity-prefabs-and-gameobjects-only-for-data<h1 id="introduction">Introduction</h1>
<p><a href="https://docs.unity3d.com/Manual/GameObjects.html">GameObjects</a> are the main concept of Unity, they are composed by different Components which normally contain both Logic and Data. A GameObject can contain other GameObjects as well in a hierarchical way.</p>
<p><a href="https://docs.unity3d.com/Manual/Prefabs.html">Prefabs</a> are GameObjects stored in assets that can be easily reused by instantiating them in scenes during edition time, for example, an enemy spawner in the right corner of the level, or in runtime, for example, the enemies spawned by that spawner.</p>
<!-- Overthrowing the Scriptable Object Tyranny in a Glorious Data Game Object Revolution -->
<h1 id="using-prefabs-and-gameobjects-only-for-data">Using Prefabs and GameObjects only for Data</h1>
<p>When we want to store only data, we normally tend to use <a href="https://docs.unity3d.com/Manual/class-ScriptableObject.html">ScriptableObjects</a> since it is a more natural way. They are just assets that can store anything serializable by Unity. ScriptableObjects are great and have some advanced usages explained <a href="https://www.youtube.com/watch?v=raQ3iHhE_Kk">here</a> and <a href="https://www.youtube.com/watch?v=6vmRwLYWNRo">here</a> but this blog post is not about that.</p>
<p>It is not common, however, to use GameObjects and Prefabs for data only (no logic at all) but that doesn’t mean it is not useful, <em>au contraire mon ami</em>, and I will share why.</p>
<p>When using GameObjects and Prefabs with this perspective in mind, it is like using ScriptableObjects but with all these extra features:</p>
<ul>
<li>Data Composition by Hierarchical Structure</li>
<li>Data Composition by Components</li>
<li>In-Scene Data Customization</li>
<li>Prefab Variants Data Customization</li>
<li>Reuse Data with Nested Prefabs</li>
<li>Prefabs Editor</li>
<li>GameObjects default Components like Transforms</li>
<li>Useful API methods</li>
</ul>
<p>For the rest of the blog post I will refer to those GameObjects as Data GameObjects.</p>
<h2 id="data-by-using-gameobject-hierarchical-structure">Data by using GameObject hierarchical structure</h2>
<p>As GameObjects can be added one to another in a hierarchical way, we can store different Data together by just adding the corresponding Data GameObject to another.</p>
<p><img src="/wp-content/uploads/2020/05/datagameobject-objectcomposition.gif" alt="" /></p>
<p>Given the previous example, we can get data using something like this:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">void</span> <span class="nf">SomeLogic</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">dataObject</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">health</span> <span class="p">=</span> <span class="n">dataObject</span><span class="p">.</span><span class="n">GetComponentInChildren</span><span class="p"><</span><span class="n">HealthData</span><span class="p">>();</span>
<span class="c1">// ... do something with the health</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="data-by-adding-gameobjects-components">Data by adding GameObject’s Components</h2>
<p>As I said before, GameObjects are composed of a list of Components, we can use that as well to store different Data together by just adding corresponding Components to the Data GameObject we want.</p>
<p><img src="/wp-content/uploads/2020/05/datagameobject-components.gif" alt="" /></p>
<p>And with this example, we can do the same:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">void</span> <span class="nf">SomeLogic</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">dataObject</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">health</span> <span class="p">=</span> <span class="n">dataObject</span><span class="p">.</span><span class="n">GetComponent</span><span class="p"><</span><span class="n">HealthData</span><span class="p">>();</span>
<span class="c1">// ... do something with the health</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="in-scene-data-customization">In-Scene Data Customization</h2>
<p>ScriptableObjects can’t be stored in scenes but GameObjects can, and that opens new possibilities to Data customization.</p>
<p>In order to do that, Data GameObject can be created in scenes (or instantiated in the case they are stored in Prefabs) and modified as needed.</p>
<p><img src="/wp-content/uploads/2020/05/datagameobject-inscene-customization.gif" alt="" /></p>
<h2 id="prefab-variants-data-customization">Prefab Variants Data Customization</h2>
<p>If using Unity 2018.3 or newer, there is also the <a href="https://docs.unity3d.com/Manual/PrefabVariants.html">Prefab Variants</a> feature for Data Customization as well, and simplify storing and reusing those modifications.</p>
<p><img src="/wp-content/uploads/2020/05/datagameobject-prefabvariant.gif" alt="" /></p>
<h2 id="reuse-data-with-nested-prefabs">Reuse Data with Nested Prefabs</h2>
<p><a href="https://docs.unity3d.com/Manual/NestedPrefabs.html">Nested Prefabs</a> is also one of those new Prefabs features that allow reusing Data composition by adding other Data GameObject Prefabs as children.</p>
<p><img src="/wp-content/uploads/2020/05/datagameobject-nestedprefab.gif" alt="" /></p>
<h2 id="prefabs-editor">Prefabs Editor</h2>
<p>Now that Prefabs can be edited completely without having to instantiate them, we can take advantage of that too. This is super useful in the case of using the hierarchical Data composition mentioned before.</p>
<p><img src="/wp-content/uploads/2020/05/datagameobject-prefabeditor.png" alt="" /></p>
<h2 id="gameobjects-default-components-like-transforms">GameObjects default Components like Transforms</h2>
<p>GameObjects normally come with a lot of extra burden, like the Transform Component for example, but that’s not always bad. Sometimes it is useful to have positional information in the Data GameObjects by using Transforms, for example, to spawn an enemy in a given offset.</p>
<p><img src="/wp-content/uploads/2020/05/datagameobject-transforms.gif" alt="" /></p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">SpawnerData</span> <span class="p">:</span> <span class="n">MonoBehaviour</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">Vector2</span> <span class="n">Offset</span> <span class="p">=></span>
<span class="n">transform</span><span class="p">.</span><span class="nf">Find</span><span class="p">(</span><span class="s">"Offset"</span><span class="p">).</span><span class="n">localPosition</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Even though this means extra memory cost compared to using ScriptableObjects, it doesn’t mean extra performance cost since Data GameObjects are not instantiated and have no logic.</p>
<h2 id="useful-api-methods">Useful API methods</h2>
<p>As we are using GameObjects, we can also take advantage of all its related API methods like GetComponent methods, or checking for a Transform children to be there or not.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">void</span> <span class="nf">SomeLogic</span><span class="p">(</span><span class="n">GameObject</span> <span class="n">dataObject</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">dataObject</span><span class="p">.</span><span class="n">transform</span><span class="p">.</span><span class="nf">Find</span><span class="p">(</span><span class="s">"DoubleDamage"</span><span class="p">)</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// perform double damage</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="c1">// perform normal damage</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>We could even use it to get MonoBehaviours implementing an Interface. Even though that is normally more useful for logic, we could have complex Data that depends on other factors, so it might be interesting to create an Interface and have different implementations to retrieve those values while ensuring readonly usage at the same time.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">interface</span> <span class="nc">WeaponData</span> <span class="p">{</span>
<span class="kt">int</span> <span class="n">Damage</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">BasicWeaponData</span> <span class="p">:</span> <span class="n">MonoBehaviour</span><span class="p">,</span> <span class="n">WeaponData</span> <span class="p">{</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">damage</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">Damage</span> <span class="p">=></span> <span class="n">damage</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">class</span> <span class="nc">AdvancedWeaponData</span> <span class="p">:</span> <span class="n">MonoBehaviour</span><span class="p">,</span> <span class="n">WeaponData</span> <span class="p">{</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">damage</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">level</span> <span class="p">=</span> <span class="m">1</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">int</span> <span class="n">Damage</span> <span class="p">=></span> <span class="n">damage</span> <span class="p">*</span> <span class="n">level</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In case you are interested, <a href="https://github.com/acoppes/DataGameObjectsExample">here is the Github project used for this article</a>.</p>
<h2 id="some-drawbacks-to-have-in-mind">Some drawbacks to have in mind</h2>
<p>When using ScriptableObjects, it is super easy to pick a reference in the Editor since it shows only valid assets of that type. In the case of referencing GameObjects the editor will show all possible GameObjects in the scene or Prefabs in the assets database. You can’t even reference to specific Component type since, in that case, the editor shows nothing (unless you select something from the scene) and you’ll have to manually drag and drop the reference from the assets.</p>
<p>One common mistake when working with assets in runtime is to modify their values through code without knowing, and Prefabs are no exception. To mitigate this, we try to treat them as read only as possible. For example, we use them only in creation time or try to return immutable values by using structs or by using an interface like the previous example.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Using Prefabs and GameObjects for Data proved to be a great tool to easily reuse and customize Data by taking advantage of all of the GameObjects features mentioned before.</p>
<p>Having great Data tools is relevant when developing a game focused on Data that everyone in the team collaborate in building it. It helps when <a href="https://www.gdcvault.com/play/1025284/Tools-Tutorial-Day-A-Tale">separating data for different purposes</a>, for example, the Data edited by Game Designers and the Data optimized for the engine.</p>
<!--
Separating Data from Logic helps when thking in therms of the [ECS][10] paradigm in mind, where logic is performed by Systems and the Components are ol (would love to migrate in the future, if possible, to [Unity's implementation][9]), but that is food for another blog post.
-->
<p>I know this blog post was a bit generic but it was to share the general idea behind this and present it in a clean way. Would love to share a more real example of how we are using it for our current game but I can’t.</p>
<p>As always, I hope you liked it, and feel free to comment and share :)</p>
<!-- Unite Austin 2017 - Game Architecture with Scriptable Objects -->
<!-- Unite 2016 - Overthrowing the MonoBehaviour Tyranny in a Glorious Scriptable Object Revolution -->arielsanIntroduction GameObjects are the main concept of Unity, they are composed by different Components which normally contain both Logic and Data. A GameObject can contain other GameObjects as well in a hierarchical way. Prefabs are GameObjects stored in assets that can be easily reused by instantiating them in scenes during edition time, for example, an enemy spawner in the right corner of the level, or in runtime, for example, the enemies spawned by that spawner. Using Prefabs and GameObjects only for Data When we want to store only data, we normally tend to use ScriptableObjects since it is a more natural way. They are just assets that can store anything serializable by Unity. ScriptableObjects are great and have some advanced usages explained here and here but this blog post is not about that. It is not common, however, to use GameObjects and Prefabs for data only (no logic at all) but that doesn’t mean it is not useful, au contraire mon ami, and I will share why. When using GameObjects and Prefabs with this perspective in mind, it is like using ScriptableObjects but with all these extra features: Data Composition by Hierarchical Structure Data Composition by Components In-Scene Data Customization Prefab Variants Data Customization Reuse Data with Nested Prefabs Prefabs Editor GameObjects default Components like Transforms Useful API methods For the rest of the blog post I will refer to those GameObjects as Data GameObjects. Data by using GameObject hierarchical structure As GameObjects can be added one to another in a hierarchical way, we can store different Data together by just adding the corresponding Data GameObject to another. Given the previous example, we can get data using something like this: public void SomeLogic(GameObject dataObject) { var health = dataObject.GetComponentInChildren<HealthData>(); // ... do something with the health } Data by adding GameObject’s Components As I said before, GameObjects are composed of a list of Components, we can use that as well to store different Data together by just adding corresponding Components to the Data GameObject we want. And with this example, we can do the same: public void SomeLogic(GameObject dataObject) { var health = dataObject.GetComponent<HealthData>(); // ... do something with the health } In-Scene Data Customization ScriptableObjects can’t be stored in scenes but GameObjects can, and that opens new possibilities to Data customization. In order to do that, Data GameObject can be created in scenes (or instantiated in the case they are stored in Prefabs) and modified as needed. Prefab Variants Data Customization If using Unity 2018.3 or newer, there is also the Prefab Variants feature for Data Customization as well, and simplify storing and reusing those modifications. Reuse Data with Nested Prefabs Nested Prefabs is also one of those new Prefabs features that allow reusing Data composition by adding other Data GameObject Prefabs as children. Prefabs Editor Now that Prefabs can be edited completely without having to instantiate them, we can take advantage of that too. This is super useful in the case of using the hierarchical Data composition mentioned before. GameObjects default Components like Transforms GameObjects normally come with a lot of extra burden, like the Transform Component for example, but that’s not always bad. Sometimes it is useful to have positional information in the Data GameObjects by using Transforms, for example, to spawn an enemy in a given offset. public class SpawnerData : MonoBehaviour { public Vector2 Offset => transform.Find("Offset").localPosition; } Even though this means extra memory cost compared to using ScriptableObjects, it doesn’t mean extra performance cost since Data GameObjects are not instantiated and have no logic. Useful API methods As we are using GameObjects, we can also take advantage of all its related API methods like GetComponent methods, or checking for a Transform children to be there or not. public void SomeLogic(GameObject dataObject) { if (dataObject.transform.Find("DoubleDamage") != null) { // perform double damage } else { // perform normal damage } } We could even use it to get MonoBehaviours implementing an Interface. Even though that is normally more useful for logic, we could have complex Data that depends on other factors, so it might be interesting to create an Interface and have different implementations to retrieve those values while ensuring readonly usage at the same time. public interface WeaponData { int Damage { get; } } public class BasicWeaponData : MonoBehaviour, WeaponData { public int damage; public int Damage => damage; } public class AdvancedWeaponData : MonoBehaviour, WeaponData { public int damage; public int level = 1; public int Damage => damage * level; } In case you are interested, here is the Github project used for this article. Some drawbacks to have in mind When using ScriptableObjects, it is super easy to pick a reference in the Editor since it shows only valid assets of that type. In the case of referencing GameObjects the editor will show all possible GameObjects in the scene or Prefabs in the assets database. You can’t even reference to specific Component type since, in that case, the editor shows nothing (unless you select something from the scene) and you’ll have to manually drag and drop the reference from the assets. One common mistake when working with assets in runtime is to modify their values through code without knowing, and Prefabs are no exception. To mitigate this, we try to treat them as read only as possible. For example, we use them only in creation time or try to return immutable values by using structs or by using an interface like the previous example. Conclusion Using Prefabs and GameObjects for Data proved to be a great tool to easily reuse and customize Data by taking advantage of all of the GameObjects features mentioned before. Having great Data tools is relevant when developing a game focused on Data that everyone in the team collaborate in building it. It helps when separating data for different purposes, for example, the Data edited by Game Designers and the Data optimized for the engine. I know this blog post was a bit generic but it was to share the general idea behind this and present it in a clean way. Would love to share a more real example of how we are using it for our current game but I can’t. As always, I hope you liked it, and feel free to comment and share :)Using the new Unity’s Input System during Ludum Dare 44 Jam2019-05-11T00:00:00-03:002019-05-11T00:00:00-03:00https://blog.gemserk.com/2019/05/11/experimenting-with-new-unity-input-system<p>During <a href="https://blog.gemserk.com/2019/04/30/bankinbacon-ld44jam/">Bankin’ Bacon development</a> we ended up using both Unity’s legacy Input System and new <a href="https://github.com/Unity-Technologies/InputSystem">Input System</a>, and we wanted to share our experience with them.</p>
<p>We knew from the beginning we wanted to experiment with the new Input System but since we had no experience and we only had three days, we started by using only the legacy one.</p>
<h1 id="legacy-input-system">Legacy input system</h1>
<p>After prototyping a bit and iterating over the game concept, we decided we wanted to control everything Gamepads (using Xbox 360 Controllers) and the player would be able to do four actions, move (left stick), target (right stick), dash and attack.</p>
<p>For those actions, we created an <a href="https://gitlab.com/gemserk/ld44bankingbacon/blob/master/Assets/Scripts/Game/Logic/Input/UnitControllerInput.cs">input class</a> that reads the Input and store their state so it can be used later by our character class. The code is something like this:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">UnitController</span> <span class="p">:</span> <span class="n">MonoBehaviour</span> <span class="p">{</span>
<span class="n">Vector2</span> <span class="n">movementDirection</span><span class="p">;</span>
<span class="n">Vector2</span> <span class="n">fireDirection</span><span class="p">;</span>
<span class="kt">bool</span> <span class="n">isFiring</span><span class="p">;</span>
<span class="kt">bool</span> <span class="n">isDashing</span><span class="p">;</span>
<span class="n">UnitControllerAsset</span> <span class="n">inputAsset</span><span class="p">;</span>
<span class="k">void</span> <span class="nf">Update</span><span class="p">()</span> <span class="p">{</span>
<span class="n">movementDirection</span><span class="p">.</span><span class="n">x</span> <span class="p">=</span> <span class="n">Input</span><span class="p">.</span><span class="nf">GetAxis</span><span class="p">(</span><span class="n">inputAsset</span><span class="p">.</span><span class="n">moveHorizontalAxis</span><span class="p">);</span>
<span class="n">movementDirection</span><span class="p">.</span><span class="n">y</span> <span class="p">=</span> <span class="n">Input</span><span class="p">.</span><span class="nf">GetAxis</span><span class="p">(</span><span class="n">inputAsset</span><span class="p">.</span><span class="n">moveVerticalAxis</span><span class="p">);</span>
<span class="p">...</span>
<span class="n">isFiring</span> <span class="p">=</span> <span class="n">Input</span><span class="p">.</span><span class="nf">GetButtonDown</span><span class="p">(</span><span class="n">inputAsset</span><span class="p">.</span><span class="n">fire1Button</span><span class="p">);</span>
<span class="p">...</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The Player’s prefab can be configured to use a specific set of Input keys by creating a <code class="highlighter-rouge">UnitControllerAsset</code> asset and assigning it to the controller. The asset looks like this:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">UnitControllerAsset</span> <span class="p">:</span> <span class="n">ScriptableObject</span> <span class="p">{</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">moveHorizontalAxis</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">moveVerticalAxis</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">fireHorizontalAxis</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">fireVerticalAxis</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">fire1Button</span><span class="p">;</span>
<span class="k">public</span> <span class="kt">string</span> <span class="n">fire2Button</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In order to perform actions, our character class checks the state of the <code class="highlighter-rouge">UnitController</code> values and acts accordingly. For example:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">UnitCharacter</span> <span class="p">:</span> <span class="n">MonoBehaviour</span> <span class="p">{</span>
<span class="n">UnitController</span> <span class="n">controller</span><span class="p">;</span>
<span class="k">void</span> <span class="nf">Update</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">transform</span><span class="p">.</span><span class="n">position</span> <span class="p">+=</span> <span class="n">controller</span><span class="p">.</span><span class="n">movingDirection</span> <span class="p">*</span> <span class="n">speed</span> <span class="p">*</span> <span class="n">dt</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="n">controller</span><span class="p">.</span><span class="n">isFiring</span> <span class="p">&&</span> <span class="n">cooldown</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">FireProjectile</span><span class="p">(</span><span class="n">controller</span><span class="p">.</span><span class="n">fireDirection</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">...</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p>Note: this is an oversimplified code, the game’s code is super ugly.</p>
</blockquote>
<p>From the Unity’s InputManager side, we created action keys for each player and configure them using different joystick numbers:</p>
<p><img src="/wp-content/uploads/2019/05/playeractions_expanded.png" alt="" /></p>
<p>This was a hell to manage, I mean, it wasn’t so hard but it was super easy to make mistakes and not know where. To simplify a bit this task, we normally modify the <code class="highlighter-rouge">ProjectSettings/InputManager.asset</code> file directly using a text editor so we can do copy, paste and replace text.</p>
<p>Following this approach we quickly had something working for two players and if we wanted more players we would have just to copy the actions and configure some prefabs.</p>
<h2 id="macwindows-differences">Mac/Windows differences</h2>
<p>Since life is not easy, buttons and axis are mapped differently between Windows and Mac (at least with the driver we were using for Xbox 360 Controllers). To overcome this issue, we had to implement a hack to support different platform Input mapping. What we do is, we duplicate action keys for each OS and we read them differently on that. So, we end up having something like <code class="highlighter-rouge">Player0_Fire1</code> for Windows and <code class="highlighter-rouge">Player0_Fire1Mac</code> for Mac (you can see that in the previous InputManager’s image) . Here is an example of the hack code:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">void</span> <span class="nf">Update</span><span class="p">()</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">Application</span><span class="p">.</span><span class="n">platform</span> <span class="p">==</span> <span class="n">RuntimePlatform</span><span class="p">.</span><span class="n">OSXPlayer</span> <span class="p">||</span> <span class="n">Application</span><span class="p">.</span><span class="n">platform</span> <span class="p">==</span> <span class="n">RuntimePlatform</span><span class="p">.</span><span class="n">OSXEditor</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">fx</span> <span class="p">=</span> <span class="n">Input</span><span class="p">.</span><span class="nf">GetAxis</span><span class="p">(</span><span class="n">_inputAsset</span><span class="p">.</span><span class="n">fireHorizontalAxis</span> <span class="p">+</span> <span class="s">"Mac"</span><span class="p">);</span>
<span class="n">fy</span> <span class="p">=</span> <span class="n">Input</span><span class="p">.</span><span class="nf">GetAxis</span><span class="p">(</span><span class="n">_inputAsset</span><span class="p">.</span><span class="n">fireVerticalAxis</span> <span class="p">+</span> <span class="s">"Mac"</span><span class="p">);</span>
<span class="n">firing1</span> <span class="p">=</span> <span class="n">Input</span><span class="p">.</span><span class="nf">GetButtonDown</span><span class="p">(</span><span class="n">_inputAsset</span><span class="p">.</span><span class="n">fire1Button</span> <span class="p">+</span> <span class="s">"Mac"</span><span class="p">);</span>
<span class="n">firing2</span> <span class="p">=</span> <span class="n">Input</span><span class="p">.</span><span class="nf">GetButtonDown</span><span class="p">(</span><span class="n">_inputAsset</span><span class="p">.</span><span class="n">fire2Button</span> <span class="p">+</span> <span class="s">"Mac"</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<blockquote>
<p>We are not responsible if you want to use this code and your computer explodes.</p>
</blockquote>
<p>By the end of the second day of development we had our Gamepads working and we were able to go from 2 to 4 players support by just adding the actions mapping for new players in the InputManager and creating some prefabs.</p>
<p>Even though that was working fine in the computer we were using for development, it didn’t on our personal computers at home and we didn’t know why.</p>
<h1 id="new-input-system">New input system</h1>
<p>Since we were worried that could happen to more people and we love livin’ on the edge (we used Unity 2019.1 for the game), we decided to spend the last day trying to improve our input issues by using the new Input System (whaaaaaaaat?).</p>
<p>We started by creating another project named <a href="https://github.com/acoppes/LearnAboutNewInputSystem">LearnAboutNewInputSystem</a> and importing the needed packages by following these <a href="https://github.com/Unity-Technologies/InputSystem/blob/develop/Packages/com.unity.inputsystem/Documentation~/Installation.md">installation steps</a>. The idea was to iterate and learn about the API in a safe context and, only after we manage to do what we needed, integrate it in the game.</p>
<p>Once we had the project ready, we created an Input Actions asset with <code class="highlighter-rouge">Create > Input Actions</code> and configured some actions to start testing. Here is the asset configuration:</p>
<p><img src="/wp-content/uploads/2019/05/newsystem_actions2.png" alt="" /></p>
<p>We specified a continuous axis Action, named <code class="highlighter-rouge">Movement</code>, that receives input from the Gamepad left stick and from the keyboard keys WASD. In order to react to that action, we created a GameObject with a <code class="highlighter-rouge">PlayerInput</code> MonoBehaviour and mapped to our custom MonoBehaviour methods using Unity Events.</p>
<p><code class="highlighter-rouge">PlayerInput</code> inspector automatically shows Unity Events for each action you create on the Input Actions configuration asset:</p>
<p><img src="/wp-content/uploads/2019/05/newsystem_playerinput.png" alt="" /></p>
<blockquote>
<p>Note: it has a bug what adds same action multiple times each time it reloads code or something like that.</p>
</blockquote>
<p>And here is our code to handle the action event:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">MyControllerTest</span> <span class="p">{</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">OnMovement</span><span class="p">(</span><span class="n">InputAction</span><span class="p">.</span><span class="n">CallbackContext</span> <span class="n">context</span><span class="p">)</span> <span class="p">{</span>
<span class="kt">var</span> <span class="n">axis</span> <span class="p">=</span> <span class="n">context</span><span class="p">.</span><span class="n">ReadValue</span><span class="p"><</span><span class="n">Vector2</span><span class="p">>();</span>
<span class="n">Debug</span><span class="p">.</span><span class="nf">LogFormat</span><span class="p">(</span><span class="s">"Moving to direction {0}"</span><span class="p">,</span> <span class="n">axis</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>That worked well, however we started to see some possible problems. First, even though we received callbacks continuously for the Gamepad left stick, we only received callbacks for the keyboard when a key was pressed or released but not all the time as expected. Second, we didn’t know how to identify different Gamepads, so with the current test, each time a left stick on any connected Gamepad was moved, our callback was invoked.</p>
<blockquote>
<p>Note: we didn’t know about the <code class="highlighter-rouge">PlayerInputManager</code> class while developing the game. We tried using it now (while writing this blog post) but we detected also some problems.</p>
</blockquote>
<p>By checking about new Input System in <a href="https://forum.unity.com/forums/new-input-system.103/">Unity’s Forums</a> we found some people trying to do something similar and one dev suggested <a href="https://forum.unity.com/threads/how-to-use-multiple-controllers-in-local-multiplayer-game.616726/">doing this</a> and also checking the <a href="https://github.com/Unity-Technologies/InputSystem/tree/develop/Assets/Tests">test cases</a> for how to use the API. Following those recommendations, we managed to make our first version of multiple Gamepads support.</p>
<p>Here is the code:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">MyPlayersManager</span> <span class="p">:</span> <span class="n">MonoBehaviour</span> <span class="p">{</span>
<span class="n">InputUser</span><span class="p">[]</span> <span class="n">_users</span><span class="p">;</span>
<span class="n">Gamepad</span><span class="p">[]</span> <span class="n">_gamepads</span><span class="p">;</span>
<span class="k">void</span> <span class="nf">Start</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">_users</span> <span class="p">=</span> <span class="k">new</span> <span class="n">InputUser</span><span class="p">[</span><span class="m">4</span><span class="p">];</span>
<span class="n">_gamepads</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Gamepad</span><span class="p">[</span><span class="m">4</span><span class="p">];</span>
<span class="n">InputUser</span><span class="p">.</span><span class="n">listenForUnpairedDeviceActivity</span> <span class="p">=</span> <span class="m">4</span><span class="p">;</span>
<span class="n">InputUser</span><span class="p">.</span><span class="n">onChange</span> <span class="p">+=</span> <span class="n">OnControlsChanged</span><span class="p">;</span>
<span class="n">InputUser</span><span class="p">.</span><span class="n">onUnpairedDeviceUsed</span> <span class="p">+=</span> <span class="n">ListenForUnpairedGamepads</span><span class="p">;</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="n">_users</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="n">_users</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="p">=</span> <span class="n">InputUser</span><span class="p">.</span><span class="nf">CreateUserWithoutPairedDevices</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">void</span> <span class="nf">OnControlsChanged</span><span class="p">(</span><span class="n">InputUser</span> <span class="n">user</span><span class="p">,</span> <span class="n">InputUserChange</span> <span class="n">change</span><span class="p">,</span> <span class="n">InputDevice</span> <span class="n">device</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">change</span> <span class="p">==</span> <span class="n">InputUserChange</span><span class="p">.</span><span class="n">DevicePaired</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">playerId</span> <span class="p">=</span> <span class="n">_users</span><span class="p">.</span><span class="nf">ToList</span><span class="p">().</span><span class="nf">IndexOf</span><span class="p">(</span><span class="n">user</span><span class="p">);</span>
<span class="n">_gamepads</span><span class="p">[</span><span class="n">playerId</span><span class="p">]</span> <span class="p">=</span> <span class="n">device</span> <span class="k">as</span> <span class="n">Gamepad</span><span class="p">;</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">change</span> <span class="p">==</span> <span class="n">InputUserChange</span><span class="p">.</span><span class="n">DeviceUnpaired</span><span class="p">)</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">playerId</span> <span class="p">=</span> <span class="n">_users</span><span class="p">.</span><span class="nf">ToList</span><span class="p">().</span><span class="nf">IndexOf</span><span class="p">(</span><span class="n">user</span><span class="p">);</span>
<span class="n">_gamepads</span><span class="p">[</span><span class="n">playerId</span><span class="p">]</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">void</span> <span class="nf">ListenForUnpairedGamepads</span><span class="p">(</span><span class="n">InputControl</span> <span class="n">control</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">control</span><span class="p">.</span><span class="n">device</span> <span class="k">is</span> <span class="n">Gamepad</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p"><</span> <span class="n">_users</span><span class="p">.</span><span class="n">Length</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
<span class="p">{</span>
<span class="c1">// find a user without a paired device</span>
<span class="k">if</span> <span class="p">(</span><span class="n">_users</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">pairedDevices</span><span class="p">.</span><span class="n">Count</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// pair the new Gamepad device to that user</span>
<span class="n">_users</span><span class="p">[</span><span class="n">i</span><span class="p">]</span> <span class="p">=</span> <span class="n">InputUser</span><span class="p">.</span><span class="nf">PerformPairingWithDevice</span><span class="p">(</span><span class="n">control</span><span class="p">.</span><span class="n">device</span><span class="p">,</span> <span class="n">_users</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
<span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>What we do here is to listen for any raw event, for example pressing a button, from unpaired Gamepads and pair them with users without paired devices.</p>
<p>In the Forums, they also recommend creating a new instance of the Input Actions asset for each user, we tested that and worked somehow but we realized we didn’t need it for the game so we decided to just read the Gamepad values directly.</p>
<h1 id="integrating-it-in-bankinbacon">Integrating it in Bankin’Bacon</h1>
<p>To integrate it in the game and be able to use it in any scene, we created a Singleton named <a href="https://gitlab.com/gemserk/ld44bankingbacon/blob/master/Assets/Scripts/Game/Logic/Input/UnitNewInputSingleton.cs"><code class="highlighter-rouge">UnitNewInputSingleton</code></a>, using a ScriptableObject, initiated the first time it was invoked. Each time we want to know the state of a Gamepad for a user, we add a dependency to the asset and use it directly from code.</p>
<p>To implement a new controller using the new input, we first created an abstract class for the <code class="highlighter-rouge">UnitController</code> and then created a <a href="https://gitlab.com/gemserk/ld44bankingbacon/blob/master/Assets/Scripts/Game/Logic/Input/UnitControllerNewInput.cs">new implementation</a> using a reference to the <code class="highlighter-rouge">UnitNewInputSingleton</code> to ask for the raw data of the Player’s Gamepad. Here is the code of the new input:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">UnitControllerNewInput</span> <span class="p">:</span> <span class="n">UnitControllerBaseInput</span> <span class="p">{</span>
<span class="p">[</span><span class="n">SerializeField</span><span class="p">]</span>
<span class="k">private</span> <span class="n">UnitNewInputSingleton</span> <span class="n">_inputMaster</span><span class="p">;</span>
<span class="p">[</span><span class="n">SerializeField</span><span class="p">]</span>
<span class="k">private</span> <span class="n">UnitControllerInputAsset</span> <span class="n">_keyboardControls</span><span class="p">;</span>
<span class="k">private</span> <span class="n">Vector2</span> <span class="n">_moveDirection</span><span class="p">;</span>
<span class="k">private</span> <span class="n">Vector2</span> <span class="n">_targetDirection</span><span class="p">;</span>
<span class="k">public</span> <span class="k">override</span> <span class="n">Vector3</span> <span class="n">MoveDirection</span> <span class="p">=></span> <span class="k">new</span> <span class="nf">Vector3</span><span class="p">(</span><span class="n">_moveDirection</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">_moveDirection</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>
<span class="k">public</span> <span class="k">override</span> <span class="n">Vector3</span> <span class="n">FireDirection</span> <span class="p">=></span> <span class="k">new</span> <span class="nf">Vector3</span><span class="p">(</span><span class="n">_targetDirection</span><span class="p">.</span><span class="n">x</span><span class="p">,</span> <span class="m">0</span><span class="p">,</span> <span class="n">_targetDirection</span><span class="p">.</span><span class="n">y</span><span class="p">);</span>
<span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">IsFiring1</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="kt">bool</span> <span class="n">IsFiring2</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">private</span> <span class="kt">int</span> <span class="n">_inputPlayerId</span><span class="p">;</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">Start</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">_inputPlayerId</span> <span class="p">=</span> <span class="n">_inputMaster</span><span class="p">.</span><span class="nf">RegisterPlayer</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">Update</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">_moveDirection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Vector2</span><span class="p">();</span>
<span class="n">_targetDirection</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Vector2</span><span class="p">();</span>
<span class="kt">var</span> <span class="n">gamepad</span> <span class="p">=</span> <span class="n">_inputMaster</span><span class="p">.</span><span class="nf">GetGamepad</span><span class="p">(</span><span class="n">_inputPlayerId</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">gamepad</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">_moveDirection</span> <span class="p">=</span> <span class="n">gamepad</span><span class="p">.</span><span class="n">leftStick</span><span class="p">.</span><span class="nf">ReadValue</span><span class="p">();</span>
<span class="n">_targetDirection</span> <span class="p">=</span> <span class="n">gamepad</span><span class="p">.</span><span class="n">rightStick</span><span class="p">.</span><span class="nf">ReadValue</span><span class="p">();</span>
<span class="n">IsFiring1</span> <span class="p">=</span> <span class="n">gamepad</span><span class="p">.</span><span class="n">rightShoulder</span><span class="p">.</span><span class="n">wasPressedThisFrame</span> <span class="p">||</span> <span class="n">IsFiring1</span><span class="p">;</span>
<span class="n">IsFiring2</span> <span class="p">=</span> <span class="n">gamepad</span><span class="p">.</span><span class="n">leftShoulder</span><span class="p">.</span><span class="n">wasPressedThisFrame</span> <span class="p">||</span> <span class="n">IsFiring2</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Since we had access to the raw input, on some scenes where we just wanted to know if any Gamepad button was pressed, we iterated over all the Gamepads. This was used to restart the game for example.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">start</span> <span class="p">=</span> <span class="n">_inputMaster</span><span class="p">.</span><span class="n">Gamepads</span><span class="p">.</span><span class="nf">Any</span><span class="p">(</span><span class="n">g</span> <span class="p">=></span> <span class="n">g</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&&</span> <span class="n">g</span><span class="p">.</span><span class="n">startButton</span><span class="p">.</span><span class="n">wasReleasedThisFrame</span><span class="p">);</span>
<span class="kt">var</span> <span class="k">select</span> <span class="p">=</span> <span class="n">_inputMaster</span><span class="p">.</span><span class="n">Gamepads</span><span class="p">.</span><span class="nf">Any</span><span class="p">(</span><span class="n">g</span> <span class="p">=></span> <span class="n">g</span> <span class="p">!=</span> <span class="k">null</span> <span class="p">&&</span> <span class="n">g</span><span class="p">.</span><span class="n">selectButton</span><span class="p">.</span><span class="n">wasReleasedThisFrame</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="n">start</span><span class="p">)</span>
<span class="p">{</span>
<span class="nf">OnGameRestart</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="k">select</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">SceneLists</span><span class="p">.</span><span class="nf">Load</span><span class="p">().</span><span class="nf">LoadMenu</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If you want to see more about one day solution code check <a href="https://gitlab.com/gemserk/ld44bankingbacon">the game Gitlab page</a>.</p>
<h1 id="finally">Finally</h1>
<p>Even though Legacy Input System works for quickly prototyping, it is really limited to do Gamepads support and it sucks in terms of configuration. It even doesn’t support remap joystick actions using the default Unity’s Launcher Window.</p>
<p>The new Input System is looking better already but we believe it still has a lot of issues to fix and probably not ready for production. It also has some strange design decisions (in our humble opinion) like having split screen stuff in the API and configuration scripts. The API should be clean and provide low level control and then there should be optional packages to do more stuff depending the game.</p>
<p>We hope they keep working and improve it as much as possible and release a stable version soon.</p>arielsanDuring Bankin’ Bacon development we ended up using both Unity’s legacy Input System and new Input System, and we wanted to share our experience with them. We knew from the beginning we wanted to experiment with the new Input System but since we had no experience and we only had three days, we started by using only the legacy one. Legacy input system After prototyping a bit and iterating over the game concept, we decided we wanted to control everything Gamepads (using Xbox 360 Controllers) and the player would be able to do four actions, move (left stick), target (right stick), dash and attack. For those actions, we created an input class that reads the Input and store their state so it can be used later by our character class. The code is something like this: class UnitController : MonoBehaviour { Vector2 movementDirection; Vector2 fireDirection; bool isFiring; bool isDashing; UnitControllerAsset inputAsset; void Update() { movementDirection.x = Input.GetAxis(inputAsset.moveHorizontalAxis); movementDirection.y = Input.GetAxis(inputAsset.moveVerticalAxis); ... isFiring = Input.GetButtonDown(inputAsset.fire1Button); ... } } The Player’s prefab can be configured to use a specific set of Input keys by creating a UnitControllerAsset asset and assigning it to the controller. The asset looks like this: class UnitControllerAsset : ScriptableObject { public string moveHorizontalAxis; public string moveVerticalAxis; public string fireHorizontalAxis; public string fireVerticalAxis; public string fire1Button; public string fire2Button; } In order to perform actions, our character class checks the state of the UnitController values and acts accordingly. For example: class UnitCharacter : MonoBehaviour { UnitController controller; void Update() { transform.position += controller.movingDirection * speed * dt; if (controller.isFiring && cooldown) { FireProjectile(controller.fireDirection); } ... } } Note: this is an oversimplified code, the game’s code is super ugly. From the Unity’s InputManager side, we created action keys for each player and configure them using different joystick numbers: This was a hell to manage, I mean, it wasn’t so hard but it was super easy to make mistakes and not know where. To simplify a bit this task, we normally modify the ProjectSettings/InputManager.asset file directly using a text editor so we can do copy, paste and replace text. Following this approach we quickly had something working for two players and if we wanted more players we would have just to copy the actions and configure some prefabs. Mac/Windows differences Since life is not easy, buttons and axis are mapped differently between Windows and Mac (at least with the driver we were using for Xbox 360 Controllers). To overcome this issue, we had to implement a hack to support different platform Input mapping. What we do is, we duplicate action keys for each OS and we read them differently on that. So, we end up having something like Player0_Fire1 for Windows and Player0_Fire1Mac for Mac (you can see that in the previous InputManager’s image) . Here is an example of the hack code: void Update() { if (Application.platform == RuntimePlatform.OSXPlayer || Application.platform == RuntimePlatform.OSXEditor) { fx = Input.GetAxis(_inputAsset.fireHorizontalAxis + "Mac"); fy = Input.GetAxis(_inputAsset.fireVerticalAxis + "Mac"); firing1 = Input.GetButtonDown(_inputAsset.fire1Button + "Mac"); firing2 = Input.GetButtonDown(_inputAsset.fire2Button + "Mac"); } } We are not responsible if you want to use this code and your computer explodes. By the end of the second day of development we had our Gamepads working and we were able to go from 2 to 4 players support by just adding the actions mapping for new players in the InputManager and creating some prefabs. Even though that was working fine in the computer we were using for development, it didn’t on our personal computers at home and we didn’t know why. New input system Since we were worried that could happen to more people and we love livin’ on the edge (we used Unity 2019.1 for the game), we decided to spend the last day trying to improve our input issues by using the new Input System (whaaaaaaaat?). We started by creating another project named LearnAboutNewInputSystem and importing the needed packages by following these installation steps. The idea was to iterate and learn about the API in a safe context and, only after we manage to do what we needed, integrate it in the game. Once we had the project ready, we created an Input Actions asset with Create > Input Actions and configured some actions to start testing. Here is the asset configuration: We specified a continuous axis Action, named Movement, that receives input from the Gamepad left stick and from the keyboard keys WASD. In order to react to that action, we created a GameObject with a PlayerInput MonoBehaviour and mapped to our custom MonoBehaviour methods using Unity Events. PlayerInput inspector automatically shows Unity Events for each action you create on the Input Actions configuration asset: Note: it has a bug what adds same action multiple times each time it reloads code or something like that. And here is our code to handle the action event: public class MyControllerTest { public void OnMovement(InputAction.CallbackContext context) { var axis = context.ReadValue<Vector2>(); Debug.LogFormat("Moving to direction {0}", axis); } } That worked well, however we started to see some possible problems. First, even though we received callbacks continuously for the Gamepad left stick, we only received callbacks for the keyboard when a key was pressed or released but not all the time as expected. Second, we didn’t know how to identify different Gamepads, so with the current test, each time a left stick on any connected Gamepad was moved, our callback was invoked. Note: we didn’t know about the PlayerInputManager class while developing the game. We tried using it now (while writing this blog post) but we detected also some problems. By checking about new Input System in Unity’s Forums we found some people trying to do something similar and one dev suggested doing this and also checking the test cases for how to use the API. Following those recommendations, we managed to make our first version of multiple Gamepads support. Here is the code: public class MyPlayersManager : MonoBehaviour { InputUser[] _users; Gamepad[] _gamepads; void Start() { _users = new InputUser[4]; _gamepads = new Gamepad[4]; InputUser.listenForUnpairedDeviceActivity = 4; InputUser.onChange += OnControlsChanged; InputUser.onUnpairedDeviceUsed += ListenForUnpairedGamepads; for (var i = 0; i < _users.Length; i++) { _users[i] = InputUser.CreateUserWithoutPairedDevices(); } } void OnControlsChanged(InputUser user, InputUserChange change, InputDevice device) { if (change == InputUserChange.DevicePaired) { var playerId = _users.ToList().IndexOf(user); _gamepads[playerId] = device as Gamepad; } else if (change == InputUserChange.DeviceUnpaired) { var playerId = _users.ToList().IndexOf(user); _gamepads[playerId] = null; } } void ListenForUnpairedGamepads(InputControl control) { if (control.device is Gamepad) { for (var i = 0; i < _users.Length; i++) { // find a user without a paired device if (_users[i].pairedDevices.Count == 0) { // pair the new Gamepad device to that user _users[i] = InputUser.PerformPairingWithDevice(control.device, _users[i]); return; } } } } } What we do here is to listen for any raw event, for example pressing a button, from unpaired Gamepads and pair them with users without paired devices. In the Forums, they also recommend creating a new instance of the Input Actions asset for each user, we tested that and worked somehow but we realized we didn’t need it for the game so we decided to just read the Gamepad values directly. Integrating it in Bankin’Bacon To integrate it in the game and be able to use it in any scene, we created a Singleton named UnitNewInputSingleton, using a ScriptableObject, initiated the first time it was invoked. Each time we want to know the state of a Gamepad for a user, we add a dependency to the asset and use it directly from code. To implement a new controller using the new input, we first created an abstract class for the UnitController and then created a new implementation using a reference to the UnitNewInputSingleton to ask for the raw data of the Player’s Gamepad. Here is the code of the new input: public class UnitControllerNewInput : UnitControllerBaseInput { [SerializeField] private UnitNewInputSingleton _inputMaster; [SerializeField] private UnitControllerInputAsset _keyboardControls; private Vector2 _moveDirection; private Vector2 _targetDirection; public override Vector3 MoveDirection => new Vector3(_moveDirection.x, 0, _moveDirection.y); public override Vector3 FireDirection => new Vector3(_targetDirection.x, 0, _targetDirection.y); public override bool IsFiring1 { get; set; } public override bool IsFiring2 { get; set; } private int _inputPlayerId; private void Start() { _inputPlayerId = _inputMaster.RegisterPlayer(); } private void Update() { _moveDirection = new Vector2(); _targetDirection = new Vector2(); var gamepad = _inputMaster.GetGamepad(_inputPlayerId); if (gamepad != null) { _moveDirection = gamepad.leftStick.ReadValue(); _targetDirection = gamepad.rightStick.ReadValue(); IsFiring1 = gamepad.rightShoulder.wasPressedThisFrame || IsFiring1; IsFiring2 = gamepad.leftShoulder.wasPressedThisFrame || IsFiring2; } } } Since we had access to the raw input, on some scenes where we just wanted to know if any Gamepad button was pressed, we iterated over all the Gamepads. This was used to restart the game for example. var start = _inputMaster.Gamepads.Any(g => g != null && g.startButton.wasReleasedThisFrame); var select = _inputMaster.Gamepads.Any(g => g != null && g.selectButton.wasReleasedThisFrame); if (start) { OnGameRestart(); } else if (select) { SceneLists.Load().LoadMenu(); } If you want to see more about one day solution code check the game Gitlab page. Finally Even though Legacy Input System works for quickly prototyping, it is really limited to do Gamepads support and it sucks in terms of configuration. It even doesn’t support remap joystick actions using the default Unity’s Launcher Window. The new Input System is looking better already but we believe it still has a lot of issues to fix and probably not ready for production. It also has some strange design decisions (in our humble opinion) like having split screen stuff in the API and configuration scripts. The API should be clean and provide low level control and then there should be optional packages to do more stuff depending the game. We hope they keep working and improve it as much as possible and release a stable version soon.The making of Bankin’ Bacon: A dev experience we can take to the piggy bank2019-04-30T00:00:00-03:002019-04-30T00:00:00-03:00https://blog.gemserk.com/2019/04/30/bankinbacon-ld44jam<div class="video-container">
<iframe src="https://www.youtube.com/embed/ITQ_MtVXFJU" frameborder="0" allowfullscreen=""></iframe>
</div>
<p>We want to share a bit about the game we did for Ludum Dare Jam #44 last weekend, it’s named:</p>
<p><img src="/wp-content/uploads/2019/04/bankinbacon_banner.png" alt="" /></p>
<p>Made by:</p>
<ul>
<li>Ariel Coppes (<a href="https://twitter.com/arielsan">@arielsan</a>)</li>
<li>Enzo Gaiero (<a href="https://twitter.com/playorbust">@playorbust</a>)</li>
<li>Rubén Garat (<a href="https://twitter.com/rgarat">@rgarat</a>)</li>
<li>Anthony García (<a href="https://www.artstation.com/thonyg09">@thonyg09</a>)</li>
</ul>
<p>Links</p>
<ul>
<li><a href="https://ldjam.com/events/ludum-dare/44/$153838">Ludum Dare #44 Jam entry</a></li>
</ul>
<iframe src="https://itch.io/embed/414757" height="167" frameborder="0"></iframe>
<p>And now a bit of dev story by our friend Enzo.</p>
<h2 id="dev-story">Dev Story</h2>
<p>Initially, when we heard about the theme <strong>Your life is currency</strong> we were a bit bummed since we were set on doing a roguelike shoot em’ up game and were not so sure how to fit the theme into the mechanics, however, after a few cups of coffee and a brainstorming session around the whiteboard we ended up coming with the idea that would flesh out to be Bankin’ Bacon.</p>
<p><img src="/wp-content/uploads/2019/04/cerdito_concept01.png" alt="" /></p>
<p style="text-align: center;">
Initial ideas on character concept.
</p>
<p>We discussed using lifesteal mechanics, simply addressing the theme through art assets, using HP for upgrades (but adding a lot of upgrades would take time away from polishing) and more. Eventually we ended up going for the idea of having HP being your ammo and the price to pay for every skill.</p>
<p>Once the core idea behind the mechanics was settled, we needed a main character. We tossed around many ideas like a gold golem being chased by dwarves, bankers throwing money stacks at each other but chose to go with a lovable character that would fit the theme perfectly… A piggy bank that shoots its own coins.</p>
<p><img src="/wp-content/uploads/2019/04/cerdito_concept02.png" alt="" /></p>
<p style="text-align: center;">
Our characters are taking shape.
</p>
<p>A few hours later our awesome artist had this bouncy fella ready for integrating.</p>
<div class="wp-video">
<video class="wp-video-shortcode" id="video-3123-4" preload="metadata" controls="controls"><source type="video/mp4" src="/wp-content/uploads/2019/04/bankinbacon_running.mp4?_=4" /><a href="/wp-content/uploads/2019/04/bankinbacon_running.mp4">/wp-content/uploads/2019/04/bankinbacon_running.mp4</a></video>
</div>
<p>So, now that the character was settled and that the artist was working on the environment art we had to fully define the game’s mechanics.</p>
<p>Since we have some game jams under our belt we’ve learnt the hard way that the best way to address features during a jam is to have the ideal game in mind and the minimum viable product (MVP) to call it a closed game. Then, start building the MVP and polish our way on top of that.</p>
<p><img src="/wp-content/uploads/2019/04/cerdito_concept03.png" alt="" /></p>
<p style="text-align: center;">
Terrain and colors concept.
</p>
<p>Our main goal was to make a game that would deliver a fun couch multiplayer experience but instead of shooting like crazy you’d have to be frugal about it and make your shots count, after all… Your life is currency.</p>
<p>In order to make the players play frugally, we needed mechanics that would encourage that sort of play.</p>
<h4 id="planned-mechanics-that-made-it-into-the-game-">Planned mechanics that made it into the game :)</h4>
<ul>
<li>Shooting does self damage to the shooter.</li>
<li>Getting hit does more damage than shooting. (so shooting would make sense)</li>
<li>Players die if getting shot drops their HP below zero.</li>
<li>Dashing makes you invulnerable but costs HP.</li>
<li>Players with no coins won’t be able to shoot. (So you can’t die from shooting.)</li>
</ul>
<h4 id="planned-mechanics-that-didnt-make-it-into-the-game-">Planned mechanics that didn’t make it into the game :(</h4>
<ul>
<li>Starting out with 50% max HP</li>
<li>Dashing into coins would steal the coin shot.</li>
<li>Player scale would vary according to HP. (so that the winning player would have a bigger hit box)</li>
<li>Player speed would vary according to HP. (So that the losing player would be faster)</li>
<li>Different coin values (i.e. quarters, nickels, pennies, etc.)</li>
</ul>
<p>Why mention the mechanics that didn’t make it into the game? Well, to convey the whole “ideal game vs MVP” when it comes to jam development and also to explain the reason behind adding a new mechanic, coin dropping.</p>
<div class="wp-video">
<video class="wp-video-shortcode" id="video-3123-4" preload="metadata" controls="controls"><source type="video/mp4" src="/wp-content/uploads/2019/04/bankinbacon_coinattack.mp4?_=4" /><a href="/wp-content/uploads/2019/04/bankinbacon_coinattack.mp4">/wp-content/uploads/2019/04/bankinbacon_coinattack.mp4</a></video>
</div>
<p>Even though we managed to make the game encourage players to be frugal about shooting and dashing, we were encouraging players not to do anything that was fun in the game, therefore, we needed a way to keep the coins around so players could keep playing, but doing regular powerup drops would inflate the game’s economy, thus, making about 80% of the coins used drop around the level was the right way to go.</p>
<p>When it comes to level design, we started by trying out Unity’s Probuilder, which came in handy for prototyping really complex levels with tunnels and nooks to hide in that would turn the game into more of a hide n’ seek type of play, but two issues came up from doing that:</p>
<ul>
<li>The camera needed for using tunnels and the like was a bit hectic for the type of game and stretched the art assets, so we ended up switching to a fixed camera.</li>
<li>Doing that sort of levels would require an amount of art assets that would be impossible to make during a jam without sacrificing the art standards.</li>
</ul>
<p>However, even though we didn’t use assets made in Probuilder, it played a crucial role alongside Progrid for testing out level sizes, prototypes and ultimately assembling the level with the final assets. After several iterations using complex designs, simple levels with little obstacles proved to be the way to go leaving more time for polishing the environmental decoration.</p>
<p>In conclusion, the overall experience was more than satisfactory, leaving us with a somewhat polished game that could provide plenty of fun couch multiplayer experiences.</p>
<p>To finish up, we leave you a longer gameplay video, enjoy!</p>
<div class="video-container">
<iframe src="https://www.youtube.com/embed/_Jo0FVdeCYU" frameborder="0" allowfullscreen=""></iframe>
</div>
<p>Thanks for reading!</p>adminWe want to share a bit about the game we did for Ludum Dare Jam #44 last weekend, it’s named: Made by: Ariel Coppes (@arielsan) Enzo Gaiero (@playorbust) Rubén Garat (@rgarat) Anthony García (@thonyg09) Links Ludum Dare #44 Jam entry And now a bit of dev story by our friend Enzo. Dev Story Initially, when we heard about the theme Your life is currency we were a bit bummed since we were set on doing a roguelike shoot em’ up game and were not so sure how to fit the theme into the mechanics, however, after a few cups of coffee and a brainstorming session around the whiteboard we ended up coming with the idea that would flesh out to be Bankin’ Bacon. Initial ideas on character concept. We discussed using lifesteal mechanics, simply addressing the theme through art assets, using HP for upgrades (but adding a lot of upgrades would take time away from polishing) and more. Eventually we ended up going for the idea of having HP being your ammo and the price to pay for every skill. Once the core idea behind the mechanics was settled, we needed a main character. We tossed around many ideas like a gold golem being chased by dwarves, bankers throwing money stacks at each other but chose to go with a lovable character that would fit the theme perfectly… A piggy bank that shoots its own coins. Our characters are taking shape. A few hours later our awesome artist had this bouncy fella ready for integrating. /wp-content/uploads/2019/04/bankinbacon_running.mp4 So, now that the character was settled and that the artist was working on the environment art we had to fully define the game’s mechanics. Since we have some game jams under our belt we’ve learnt the hard way that the best way to address features during a jam is to have the ideal game in mind and the minimum viable product (MVP) to call it a closed game. Then, start building the MVP and polish our way on top of that. Terrain and colors concept. Our main goal was to make a game that would deliver a fun couch multiplayer experience but instead of shooting like crazy you’d have to be frugal about it and make your shots count, after all… Your life is currency. In order to make the players play frugally, we needed mechanics that would encourage that sort of play. Planned mechanics that made it into the game :) Shooting does self damage to the shooter. Getting hit does more damage than shooting. (so shooting would make sense) Players die if getting shot drops their HP below zero. Dashing makes you invulnerable but costs HP. Players with no coins won’t be able to shoot. (So you can’t die from shooting.) Planned mechanics that didn’t make it into the game :( Starting out with 50% max HP Dashing into coins would steal the coin shot. Player scale would vary according to HP. (so that the winning player would have a bigger hit box) Player speed would vary according to HP. (So that the losing player would be faster) Different coin values (i.e. quarters, nickels, pennies, etc.) Why mention the mechanics that didn’t make it into the game? Well, to convey the whole “ideal game vs MVP” when it comes to jam development and also to explain the reason behind adding a new mechanic, coin dropping. /wp-content/uploads/2019/04/bankinbacon_coinattack.mp4 Even though we managed to make the game encourage players to be frugal about shooting and dashing, we were encouraging players not to do anything that was fun in the game, therefore, we needed a way to keep the coins around so players could keep playing, but doing regular powerup drops would inflate the game’s economy, thus, making about 80% of the coins used drop around the level was the right way to go. When it comes to level design, we started by trying out Unity’s Probuilder, which came in handy for prototyping really complex levels with tunnels and nooks to hide in that would turn the game into more of a hide n’ seek type of play, but two issues came up from doing that: The camera needed for using tunnels and the like was a bit hectic for the type of game and stretched the art assets, so we ended up switching to a fixed camera. Doing that sort of levels would require an amount of art assets that would be impossible to make during a jam without sacrificing the art standards. However, even though we didn’t use assets made in Probuilder, it played a crucial role alongside Progrid for testing out level sizes, prototypes and ultimately assembling the level with the final assets. After several iterations using complex designs, simple levels with little obstacles proved to be the way to go leaving more time for polishing the environmental decoration. In conclusion, the overall experience was more than satisfactory, leaving us with a somewhat polished game that could provide plenty of fun couch multiplayer experiences. To finish up, we leave you a longer gameplay video, enjoy! Thanks for reading!Sharing code between Unity projects2019-03-25T20:05:55-03:002019-03-25T20:05:55-03:00https://blog.gemserk.com/2019/03/25/sharing-code-between-unity-projects<p>Over the last months, I was researching, in my spare time, some ideas to reuse code between Unity projects. I was mainly interested in using generic code from Iron Marines in multiple projects we were prototyping at Ironhide.</p>
<p>The target solution in mind was to have something like <a href="https://www.npmjs.com/">NPM</a> or <a href="https://maven.apache.org/" title="Maven">Maven</a> where packages are stored in a remote repository, and you can depend on a version of them in any project by just adding a configuration.</p>
<p>Some time ago, Unity added the Unity Package Manager (UPM) which does exactly that, it automatically downloads a list of packages given a dependency configuration. I was really excited with this solution since it goes along the direction I wanted.</p>
<p><em>Note: to know more about dependency management follow <a href="https://docs.gradle.org/current/userguide/introduction_dependency_management.html">this link</a>, even though it is about specific dependency manager, it gives the global idea of how they work.</em></p>
<h1 id="workflow">Workflow</h1>
<p>So, a good workflow would be something like this.</p>
<p>Imagine there are two projects, project A and project B and the first has some useful code we want to use in the second.</p>
<p>In order to do that, project A must be uploaded to the dependency system and tagged with a specific version to be identified, for example, version 0.0.1.</p>
<p>Then, to import that code in project B, we just add a dependency in the package dependency declaration.</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"com.gemserk.projectA"</span><span class="p">:</span><span class="w"> </span><span class="s2">"0.0.1"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Suppose we keep working on the project B while someone working on another stuff added a new functionality to project A, and we want it. Since the new feature was released in version 0.0.5 of project A, we need to update the package dependency declaration to depend on it, like this:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"com.gemserk.projectA"</span><span class="p">:</span><span class="w"> </span><span class="s2">"0.0.5"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>And that will download it and now project B can access the new feature. That is basically a common workflow.</p>
<p>Since we aren’t Unity, we can’t upload our code to their packages repository (yet?). However, there other are ways to declare dependencies stored elsewhere.</p>
<h2 id="depend-on-a-project-in-the-local-filesystem">Depend on a project in the local filesystem</h2>
<p>UPM supports <a href="https://forum.unity.com/threads/local-packages.637630/">depending on a project stored in the local filesystem</a> like this:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"com.gemserk.projectA"</span><span class="p">:</span><span class="w"> </span><span class="s2">"file:../../ProjectA/"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>For example, project A is stored in a sibling folder to project B.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/Workspace
/ProjectB
/Packages
manifest.json
/ProjectA
</code></pre></div></div>
<p><em>Note: There is a <a href="https://gist.github.com/LotteMakesStuff/6e02e0ea303030517a071a1c81eb016e">great Gist</a> by <a href="https://twitter.com/LotteMakesStuff">LotteMakesStuff</a> about this topic and more (thanks <a href="https://twitter.com/rgarat">Rubén</a> for the link).</em></p>
<p>This approach has the advantage of using local projects with any structure, stored anywhere (Git or not, more on that later). It even allows depending on a sub folder of project A, so project A could be a complete Unity project with lots of stuff (test scenes, testing assemblies, etc) but project B only depends on the shared code.</p>
<p>It needs all developers to use a similar folder structure for all the projects and download all of them together to work. Transitive dependencies is not supported by UPM following this approach, so if project A depends on project Zero, project B would never automatically find out.</p>
<p>It has some unexpected behaviors in code, at least in Visual Studio, when editing project A (add new code, refactor, etc) by opening project B solution through Unity. That’s is probably a side effect on how they create the VS solution or may be just a bug.</p>
<p>It doesn’t support versioning. Each time project A is modified, project B will automatically know about the change. This could be an issue if project A changed its API and we don’t want to (or can’t) update project B yet.</p>
<h2 id="depend-on-a-git-project">Depend on a Git project</h2>
<p>Another option is to use a <a href="https://forum.unity.com/threads/git-support-on-package-manager.573673/">link to a Git project</a>, like this:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s2">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"com.gemserk.projectA"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://github.com/gemserk/projectA.git"</span><span class="p">,</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>Dependencies can be stored directly in Git projects (in Github or any other Git server). It supports depending on a specific commit, branch or tag to simulate versioning, but changing versions should be done by hand since UPM doesn’t show the list of versions like it does with Unity packages.</p>
<p>Since it looks at the root folder, a different Git project is needed for each dependency. This is not necessary a bad thing, but it is not possible to have a Git project with multiple folders, one for each project, something that might be common in some cases, like we did with our <a href="https://github.com/gemserk/commons-gdx">LibGDX projects</a>.</p>
<p>A bigger problem related to this is that project A should have only the code to be used by other projects, otherwise UPM will import everything.</p>
<p>It also lacks support for transitive dependencies since UPM doesn’t process the dependencies declaration of the Git project.</p>
<p><em>UPDATE: <a href="https://www.patreon.com/posts/25070968">this is a great tutorial</a> on using git as package provider.</em></p>
<h2 id="mixing-both-approaches-with-git-submodules">Mixing both approaches with Git submodules</h2>
<p>There is also a mix using filesystem reference and Git submodules to overcome the versioning disadvantage of the first approach.</p>
<p>For example, project A is downloaded as project B submodule structure pointing to specific branch/tag/commit.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/ProjectB_Root
/ProjectB
/Packages/manifest.json
/ProjectA (Git submodule, specific tag)
</code></pre></div></div>
<p>In this way, we have specific versions of project A in each project, and we can share code by uploading it to Git to that submodule and tagging versions. We still have the transitive dependency limitation, and other problems related to Git submodules (more on that later).</p>
<h2 id="using-a-packages-repository">Using a packages repository</h2>
<p>The last way is to use a <a href="https://forum.unity.com/threads/setup-for-scoped-registries-private-registries.573934/">local or remote package repository</a> like Nexus, Artifactory, <a href="https://forum.unity.com/threads/other-registries-than-unitys-own-already-work-nice.533691/">NPM</a>, Verdaccio, etc, and then configure it in the manifest.json:</p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
</span><span class="s2">"registry"</span><span class="p">:</span><span class="w"> </span><span class="s2">"https://unitypackages.gemserk.com"</span><span class="p">,</span><span class="w">
</span><span class="s2">"dependencies"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"com.gemserk.projectA"</span><span class="p">:</span><span class="w"> </span><span class="s2">"0.0.1"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>
<p>This approach is similar to using Unity’s packages but a remote repository in a private server is needed to share code among developers. It is also possible to upload the code to a public server like NPM. Obviously, a private server need maintenance but I believe it is the long term solution if you have private code you can’t share with the world.</p>
<p>At Gemserk we had our own repository using Nexus and at some point we even uploaded some of our dependencies to Maven central. We configured it when we started making games and probably touched once or twice per year, maintenance wasn’t a problem at all.</p>
<p>I tried to use version range with UPM to see if I can add a dependency to a package 1.0.x and that would automatically download latest 1.0 (for example, 1.0.26) but couldn’t make it work, <a href="https://forum.unity.com/threads/semantic-versioning-like-1-0-x-is-not-working.649774/">not sure if it is not supported yet or I am doing it wrong</a>. <em>UPDATE: it is not supported yet but it is going to be in the long term plan.</em></p>
<p>With this approach, project A is integrated like any Unity’s package and the code is accessible in the VS solution but it can’t be easily modified through project B. Any changes in project A should be made apart, a new version must be uploaded to the repository and then update project B dependency declaration. In some cases this shouldn’t be an issue but, for some development cycles, it could.</p>
<p><em>Note: When we used Maven, there was a concept of SNAPSHOT which is a work in progress version that it is overwritten each time it is uploaded to the dependency system and projects depending on it use latest version automatically. That was super useful for development and the reason I tested version ranges with UPM.</em></p>
<p><em>UPDATE: I tested creating a packages server using <a href="https://verdaccio.org/">Verdaccio</a> and see how UPM interacts with it, and how hard it was to upload a package to the server. It turns out that it is relatively simple, UPM shows the list of available versions and probably get transitive dependencies (didn’t test that yet). I followed <a href="https://medium.com/@markushofer/run-your-own-unity-package-server-b4fe9995704e">this tutorial</a> in case you want to test it too.</em></p>
<p>After that initial research and considering some of the current limitations of the UPM, I started looking for other options as well.</p>
<h2 id="using-git-submodules-without-upm">Using Git Submodules without UPM</h2>
<p>In this approach, code is imported using a Git submodule in the project B itself.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/ProjectB
/Assets
/ProjectA (submodule)
</code></pre></div></div>
<p>Following this approach the code is more integrated, changes can be made and uploaded to that submodule directly from project B. In case there are different versions, project B can depend on specific branch/tag/commit of that submodule too.</p>
<p>Similar to the Git + UPM approach, the submodule should contain only the stuff needed to be reused, otherwise it will import it too since submodules point to the root folder of the Git project. However, since it is integrated in the other projects, it should be easier to edit in some way.</p>
<p>It is an interesting approach but has some <a href="https://medium.com/@porteneuve/mastering-git-submodules-34c65e940407">drawbacks as well</a>, for example, having to update each Git submodule manually by each developer, or the root folder problem.</p>
<h2 id="reusing-code-by-hand">Reusing code by hand</h2>
<p>There is an ultimate form of reusing code: copy and paste the code from project to project. Even though it is ugly and doesn’t scale at all, it might work when having to do some quick tests. Worst case scenario, create a script to automatically copy from one project o another, maybe using rsync or something like that.</p>
<h1 id="conclusion">Conclusion</h1>
<p>Whatever the chosen way of sharing code, first it must be decoupled in a nice way and that’s what I’m planning to write about in the next blog post.</p>
<p>That was my research for now, there are a lot of links to keep digging in the UPM solution. I hope they keep improving it to support transitive dependencies for filesystem and git approaches and version ranges.</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://maven.apache.org/" title="Maven">Maven</a></li>
<li><a href="https://gist.github.com/LotteMakesStuff/6e02e0ea303030517a071a1c81eb016e">LotteMakesStuff</a></li>
<li><a href="https://forum.unity.com/forums/package-manager.150/">Unity Forums about Package Manager</a></li>
<li><a href="https://forum.unity.com/threads/local-packages.637630/">Local Packages</a></li>
<li><a href="https://forum.unity.com/threads/git-support-on-package-manager.573673/">Git Support</a></li>
<li><a href="https://forum.unity.com/threads/setup-for-scoped-registries-private-registries.573934/">Private Registries</a></li>
<li><a href="https://forum.unity.com/threads/other-registries-than-unitys-own-already-work-nice.533691/">Using NPM registry</a></li>
<li><a href="https://medium.com/@markushofer/run-your-own-unity-package-server-b4fe9995704e">Run your own Unity packages server</a></li>
<li><a href="https://devopedia.org/dependency-manager">Dependency Manager</a></li>
<li><a href="https://git-scm.com/book/en/v2/Git-Tools-Submodules">Git Submodules</a></li>
<li><a href="https://medium.com/@porteneuve/mastering-git-submodules-34c65e940407">Mastering Git Submodules</a></li>
<li><a href="https://www.patreon.com/posts/25070968">Tutorial: How to develop a package for UnityPackageManager</a></li>
</ul>arielsanOver the last months, I was researching, in my spare time, some ideas to reuse code between Unity projects. I was mainly interested in using generic code from Iron Marines in multiple projects we were prototyping at Ironhide. The target solution in mind was to have something like NPM or Maven where packages are stored in a remote repository, and you can depend on a version of them in any project by just adding a configuration. Some time ago, Unity added the Unity Package Manager (UPM) which does exactly that, it automatically downloads a list of packages given a dependency configuration. I was really excited with this solution since it goes along the direction I wanted. Note: to know more about dependency management follow this link, even though it is about specific dependency manager, it gives the global idea of how they work. Workflow So, a good workflow would be something like this. Imagine there are two projects, project A and project B and the first has some useful code we want to use in the second. In order to do that, project A must be uploaded to the dependency system and tagged with a specific version to be identified, for example, version 0.0.1. Then, to import that code in project B, we just add a dependency in the package dependency declaration. { "dependencies": { "com.gemserk.projectA": "0.0.1" } } Suppose we keep working on the project B while someone working on another stuff added a new functionality to project A, and we want it. Since the new feature was released in version 0.0.5 of project A, we need to update the package dependency declaration to depend on it, like this: { "dependencies": { "com.gemserk.projectA": "0.0.5" } } And that will download it and now project B can access the new feature. That is basically a common workflow. Since we aren’t Unity, we can’t upload our code to their packages repository (yet?). However, there other are ways to declare dependencies stored elsewhere. Depend on a project in the local filesystem UPM supports depending on a project stored in the local filesystem like this: { "dependencies": { "com.gemserk.projectA": "file:../../ProjectA/" } } For example, project A is stored in a sibling folder to project B. /Workspace /ProjectB /Packages manifest.json /ProjectA Note: There is a great Gist by LotteMakesStuff about this topic and more (thanks Rubén for the link). This approach has the advantage of using local projects with any structure, stored anywhere (Git or not, more on that later). It even allows depending on a sub folder of project A, so project A could be a complete Unity project with lots of stuff (test scenes, testing assemblies, etc) but project B only depends on the shared code. It needs all developers to use a similar folder structure for all the projects and download all of them together to work. Transitive dependencies is not supported by UPM following this approach, so if project A depends on project Zero, project B would never automatically find out. It has some unexpected behaviors in code, at least in Visual Studio, when editing project A (add new code, refactor, etc) by opening project B solution through Unity. That’s is probably a side effect on how they create the VS solution or may be just a bug. It doesn’t support versioning. Each time project A is modified, project B will automatically know about the change. This could be an issue if project A changed its API and we don’t want to (or can’t) update project B yet. Depend on a Git project Another option is to use a link to a Git project, like this: "dependencies": { "com.gemserk.projectA": "https://github.com/gemserk/projectA.git", } Dependencies can be stored directly in Git projects (in Github or any other Git server). It supports depending on a specific commit, branch or tag to simulate versioning, but changing versions should be done by hand since UPM doesn’t show the list of versions like it does with Unity packages. Since it looks at the root folder, a different Git project is needed for each dependency. This is not necessary a bad thing, but it is not possible to have a Git project with multiple folders, one for each project, something that might be common in some cases, like we did with our LibGDX projects. A bigger problem related to this is that project A should have only the code to be used by other projects, otherwise UPM will import everything. It also lacks support for transitive dependencies since UPM doesn’t process the dependencies declaration of the Git project. UPDATE: this is a great tutorial on using git as package provider. Mixing both approaches with Git submodules There is also a mix using filesystem reference and Git submodules to overcome the versioning disadvantage of the first approach. For example, project A is downloaded as project B submodule structure pointing to specific branch/tag/commit. /ProjectB_Root /ProjectB /Packages/manifest.json /ProjectA (Git submodule, specific tag) In this way, we have specific versions of project A in each project, and we can share code by uploading it to Git to that submodule and tagging versions. We still have the transitive dependency limitation, and other problems related to Git submodules (more on that later). Using a packages repository The last way is to use a local or remote package repository like Nexus, Artifactory, NPM, Verdaccio, etc, and then configure it in the manifest.json: { "registry": "https://unitypackages.gemserk.com", "dependencies": { "com.gemserk.projectA": "0.0.1" } } This approach is similar to using Unity’s packages but a remote repository in a private server is needed to share code among developers. It is also possible to upload the code to a public server like NPM. Obviously, a private server need maintenance but I believe it is the long term solution if you have private code you can’t share with the world. At Gemserk we had our own repository using Nexus and at some point we even uploaded some of our dependencies to Maven central. We configured it when we started making games and probably touched once or twice per year, maintenance wasn’t a problem at all. I tried to use version range with UPM to see if I can add a dependency to a package 1.0.x and that would automatically download latest 1.0 (for example, 1.0.26) but couldn’t make it work, not sure if it is not supported yet or I am doing it wrong. UPDATE: it is not supported yet but it is going to be in the long term plan. With this approach, project A is integrated like any Unity’s package and the code is accessible in the VS solution but it can’t be easily modified through project B. Any changes in project A should be made apart, a new version must be uploaded to the repository and then update project B dependency declaration. In some cases this shouldn’t be an issue but, for some development cycles, it could. Note: When we used Maven, there was a concept of SNAPSHOT which is a work in progress version that it is overwritten each time it is uploaded to the dependency system and projects depending on it use latest version automatically. That was super useful for development and the reason I tested version ranges with UPM. UPDATE: I tested creating a packages server using Verdaccio and see how UPM interacts with it, and how hard it was to upload a package to the server. It turns out that it is relatively simple, UPM shows the list of available versions and probably get transitive dependencies (didn’t test that yet). I followed this tutorial in case you want to test it too. After that initial research and considering some of the current limitations of the UPM, I started looking for other options as well. Using Git Submodules without UPM In this approach, code is imported using a Git submodule in the project B itself. /ProjectB /Assets /ProjectA (submodule) Following this approach the code is more integrated, changes can be made and uploaded to that submodule directly from project B. In case there are different versions, project B can depend on specific branch/tag/commit of that submodule too. Similar to the Git + UPM approach, the submodule should contain only the stuff needed to be reused, otherwise it will import it too since submodules point to the root folder of the Git project. However, since it is integrated in the other projects, it should be easier to edit in some way. It is an interesting approach but has some drawbacks as well, for example, having to update each Git submodule manually by each developer, or the root folder problem. Reusing code by hand There is an ultimate form of reusing code: copy and paste the code from project to project. Even though it is ugly and doesn’t scale at all, it might work when having to do some quick tests. Worst case scenario, create a script to automatically copy from one project o another, maybe using rsync or something like that. Conclusion Whatever the chosen way of sharing code, first it must be decoupled in a nice way and that’s what I’m planning to write about in the next blog post. That was my research for now, there are a lot of links to keep digging in the UPM solution. I hope they keep improving it to support transitive dependencies for filesystem and git approaches and version ranges. References Maven LotteMakesStuff Unity Forums about Package Manager Local Packages Git Support Private Registries Using NPM registry Run your own Unity packages server Dependency Manager Git Submodules Mastering Git Submodules Tutorial: How to develop a package for UnityPackageManagerImplementing Fog of War for RTS games in Unity 2/22018-11-20T20:42:31-03:002018-11-20T20:42:31-03:00https://blog.gemserk.com/2018/11/20/implementing-fog-of-war-for-rts-games-in-unity-2-2<p>As I said in the previous <a href="/2018/08/27/implementing-fog-of-war-for-rts-games-in-unity-1-2/">blog post</a>, some time ago I started working on a new Fog of War / Vision System solution aiming the following features:</p>
<ul>
<li>Being able to render the fog of war of each player at any time, for replays and debug.</li>
<li>Being able to combine multiple players’ visions for alliances, spectator mode or watching replays.</li>
<li>Blocking vision by different terrain heights or other elements like bushes.</li>
<li>Optimized to support 50+ units at the same time in mobile devices at 60FPS.</li>
<li>It should look similar to modern games like Starcraft 2 and League of Legends (in fact, SC2 is already eight years old, not sure if that is consider a modern game or not :P).</li>
</ul>
<p>This is an example of what I want:</p>
<div class="video-container">
<iframe src="https://www.youtube.com/embed/J4VP1wbria0" frameborder="0" allowfullscreen=""></iframe>
</div>
<p style="text-align: center;">
<em>Example: fog of war in Starcraft 2</em>
</p>
<p>To simplify a bit writing this article, when I write unit I mean not only units but also structures or anything that could affect the fog of war in the game.</p>
<h1 id="logic">Logic</h1>
<p>First, there is a concept named UnitVision used to represent anything that reveals fog. Here is the data structure:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">UnitVision</span>
<span class="p">{</span>
<span class="c1">// A bit mask representing a group of players inside </span>
<span class="c1">// the vision system.</span>
<span class="kt">int</span> <span class="n">players</span><span class="p">;</span>
<span class="c1">// The range of the vision (in world coordinates)</span>
<span class="kt">float</span> <span class="n">range</span><span class="p">;</span>
<span class="c1">// the position (in world coordinates)</span>
<span class="n">vector2</span> <span class="n">position</span><span class="p">;</span>
<span class="c1">// used for blocking vision</span>
<span class="kt">short</span> <span class="n">terrainHeight</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Normally, a game will have one for each unit but there could be cases where a unit could have more (for example a large unit) or even none.</p>
<p>A bit mask is used to specify a group of players, so for example, if player 0 is 0001 and player1 is 0010, then 0011 means the group formed by player0 and player1. Since it is an int, it supports up to <code class="highlighter-rouge">sizeof(int)</code> players.</p>
<p>Most of the time the group would contain only one player but there might be some situations, like a general effect or cinematic, etc, that needs to be seen by all players and one possible solution is to use a unitVision with more than one player.</p>
<p>The <code class="highlighter-rouge">terrainHeight</code> field stores the current height of the unit and it is used for blocking vision or not. It normally will be the world terrain’s height on that position if it is a ground unit but there are cases like flying units or special abilities that could change the unit height that should be consider when calculating blocked vision. It is the game’s responsibility to update that field accordingly.</p>
<p>There is another concept named VisionGrid that represents the vision for all the players. Here is the data structure:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">VisionGrid</span>
<span class="p">{</span>
<span class="c1">// the width and height of the grid (needed to access the arrays)</span>
<span class="kt">int</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">;</span>
<span class="c1">// array of size width * height, each entry has an int with the </span>
<span class="c1">// bits representing which players have this entry in vision.</span>
<span class="kt">int</span><span class="p">[]</span> <span class="n">values</span><span class="p">;</span>
<span class="c1">// similar to the values but it just stores if a player visited</span>
<span class="c1">// that entry at some point in time.</span>
<span class="kt">int</span><span class="p">[]</span> <span class="n">visited</span><span class="p">;</span>
<span class="k">void</span> <span class="nf">SetVisible</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">players</span><span class="p">)</span> <span class="p">{</span>
<span class="n">values</span><span class="p">[</span><span class="n">i</span> <span class="p">+</span> <span class="n">j</span> <span class="p">*</span> <span class="n">width</span><span class="p">]</span> <span class="p">|=</span> <span class="n">players</span><span class="p">;</span>
<span class="n">visited</span><span class="p">[</span><span class="n">i</span> <span class="p">+</span> <span class="n">j</span> <span class="p">*</span> <span class="n">width</span><span class="p">]</span> <span class="p">|=</span> <span class="n">players</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">void</span> <span class="nf">Clear</span><span class="p">()</span> <span class="p">{</span>
<span class="n">values</span><span class="p">.</span><span class="nf">clear</span><span class="p">(</span><span class="m">0</span><span class="p">);</span>
<span class="p">}</span>
<span class="kt">bool</span> <span class="nf">IsVisible</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">players</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="n">values</span><span class="p">[</span><span class="n">i</span> <span class="p">+</span> <span class="n">j</span> <span class="p">*</span> <span class="n">width</span><span class="p">]</span> <span class="p">&</span> <span class="n">players</span><span class="p">)</span> <span class="p">&</span><span class="n">gt</span><span class="p">;</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kt">bool</span> <span class="nf">WasVisible</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">players</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">(</span><span class="n">visited</span><span class="p">[</span><span class="n">i</span> <span class="p">+</span> <span class="n">j</span> <span class="p">*</span> <span class="n">width</span><span class="p">]</span> <span class="p">&</span> <span class="n">players</span><span class="p">)</span> <span class="p">&</span><span class="n">gt</span><span class="p">;</span> <span class="m">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Note: arrays have a size of width * height.</p>
<p>The bigger the grid is, the slower it gets to calculate vision but it also has more information which could be useful for units’ behaviors or to get better fog rendering.The smaller the grid is, the opposite. A good balance must be defined from the beginning in order to build the game over that decision.</p>
<p>Here is an example of a grid over the game world:</p>
<p><img src="/wp-content/uploads/2018/11/sc1_with_grid2_crop-1024x745.png" alt="" /></p>
<p>Given a grid entry for a world position, the structure stores an int in the <em>values</em> array with the data of which players have that position inside vision. For example, if the entry has 0001 stored, it means only the player0 sees that point. If it has 0011, then both the player0 and player1.</p>
<p>This structure also stores when a player revealed fog in the past in the <em>visited</em> array which is used mainly for rendering purposes (gray fog) but could also be used by the game logic (to check if a player knows some information for example).</p>
<p>The method <code class="highlighter-rouge">IsVisible(i, j, players)</code> will return true if any of the players in the bit mask has the position visible. The method <code class="highlighter-rouge">WasVisible(i, j, players)</code> is similar but will check the <code class="highlighter-rouge">visited</code> array.</p>
<p>So, for example, if player1 and player2 (0010 and 0100 in bits) are in an alliance, then when player2 wants to know if an enemy is visible to perform an attack, it can call isVisible method with the bitmask for both players 0110.</p>
<h2 id="calculating-vision">Calculating vision</h2>
<p>Each time the vision grid is updated, the <code class="highlighter-rouge">values</code> array is cleared and recalculated.</p>
<p>Here is a pseudo code of the algorithm:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">void</span> <span class="nf">CalculateVision</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">visionGrid</span><span class="p">.</span><span class="nf">Clear</span><span class="p">()</span>
<span class="k">for</span> <span class="n">each</span> <span class="n">unitVision</span> <span class="k">in</span> <span class="n">world</span> <span class="p">{</span>
<span class="k">for</span> <span class="n">each</span> <span class="n">gridEntry</span> <span class="n">inside</span> <span class="n">unitVision</span><span class="p">.</span><span class="n">range</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">not</span> <span class="nf">IsBlocked</span><span class="p">(</span><span class="n">gridEntry</span><span class="p">))</span> <span class="p">{</span>
<span class="c1">// where set visible updates both the values and the</span>
<span class="c1">// visited arrays.</span>
<span class="n">grid</span><span class="p">.</span><span class="nf">SetVisible</span><span class="p">(</span><span class="n">gridEntry</span><span class="p">.</span><span class="n">i</span><span class="p">,</span> <span class="n">gridEntry</span><span class="p">.</span><span class="n">j</span><span class="p">,</span>
<span class="n">unitVision</span><span class="p">.</span><span class="n">players</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>To iterate over grid entries inside range, it first calculates vision’s position and range in grid coordinates, named gridPosition and gridRange, and then it <a href="https://stackoverflow.com/questions/1201200/fast-algorithm-for-drawing-filled-circles">draws a filled circle</a> of gridRange radius around gridPosition.</p>
<p><img src="/wp-content/uploads/2018/11/sc1_grid_circlearoundvision-1024x745.png" alt="" /></p>
<h2 id="blocked-vision">Blocked vision</h2>
<p>In order to detect blocked vision, there is another grid of the same size with terrain’s height information. Here is its data structure:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">struct</span> <span class="nc">Terrain</span> <span class="p">{</span>
<span class="c1">// the width and height of the grid (needed to access the arrays) </span>
<span class="kt">int</span> <span class="n">width</span><span class="p">,</span> <span class="n">height</span><span class="p">;</span>
<span class="c1">// array of size width * height, has the terrain level of the </span>
<span class="c1">// grid entry. </span>
<span class="kt">short</span><span class="p">[]</span> <span class="n">height</span><span class="p">;</span>
<span class="kt">int</span> <span class="nf">GetHeight</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">height</span><span class="p">[</span><span class="n">i</span> <span class="p">+</span> <span class="n">j</span> <span class="p">*</span> <span class="n">width</span><span class="p">];</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Here is an example of how the grid looks over the game:</p>
<p><img src="/wp-content/uploads/2018/11/sc1_with_grid_numbers_crop-1-1024x745.png" alt="" /></p>
<p>Note: that image is handmade as an example, there might be some mistakes.</p>
<p>While iterating through the vision’s grid entries around unitVision’s range, to detect if the entry is visible or not, the system checks if there are no obstacles to the vision’s center. To do that, it <a href="http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C.23">draws a line</a> from the entry’s position to the center’s position.</p>
<p>If all the grid entries in the line are in the same height or below, then the entry is visible. Here is an example where the blue dot represents the entry being calculated and white dots the line to the center.</p>
<p><img src="/wp-content/uploads/2018/11/sc1_grid_line_not_blocked-1024x745.png" alt="" /></p>
<p>If there is at least one entry in the line that is in a greater height, then the line of sight is blocked. Here is an example where the blue dot represents the entry we want to know if it is visible or not, white dots represents entries in the line in the same height and red dots represents entries in a higher ground.</p>
<p><img src="/wp-content/uploads/2018/11/sc1_grid_line_blocked-1024x745.png" alt="" /></p>
<p>Once it detects one entry above the vision it doesn’t need to continue drawing the line to the vision center.</p>
<p>Here is a pseudo algorithm:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="nf">IsBlocked</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">for</span> <span class="n">each</span> <span class="n">entry</span> <span class="k">in</span> <span class="n">line</span> <span class="n">to</span> <span class="n">unitVision</span><span class="p">.</span><span class="n">position</span> <span class="p">{</span>
<span class="n">height</span> <span class="p">=</span> <span class="n">terrain</span><span class="p">.</span><span class="nf">GetHeight</span><span class="p">(</span><span class="n">entry</span><span class="p">.</span><span class="n">position</span><span class="p">)</span>
<span class="k">if</span> <span class="p">(</span><span class="n">height</span> <span class="p">&</span><span class="n">gt</span><span class="p">;</span> <span class="n">unitVision</span><span class="p">.</span><span class="n">height</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="optimizations">Optimizations</h2>
<ul>
<li>If an entry was already marked as visible while iterating over all unit visions then there is no need to recalculate it.</li>
<li>Reduce the size of the grid.</li>
<li>Update the fog less frequently (In Starcraft there is a delay of about 1 second, I recently noticed while playing, it is an old game).</li>
</ul>
<h1 id="rendering">Rendering</h1>
<p>To render the Fog of War, first I have a small texture of the same size of the grid, named FogTexture, where I write a Color array of the same size using the Texture2D.SetPixels() method.</p>
<p>Each frame, I iterate on each VisionGrid entry and set the corresponding Color to the array using the <code class="highlighter-rouge">values</code> and <code class="highlighter-rouge">visited</code> arrays. Here is a pseudo algorithm:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">void</span> <span class="nf">Update</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">for</span> <span class="n">i</span><span class="p">,</span> <span class="n">j</span> <span class="k">in</span> <span class="n">grid</span> <span class="p">{</span>
<span class="n">colors</span><span class="p">[</span><span class="n">i</span> <span class="p">+</span> <span class="n">j</span> <span class="p">*</span> <span class="n">width</span><span class="p">]</span> <span class="p">=</span> <span class="n">black</span>
<span class="k">if</span> <span class="p">(</span><span class="n">visionGrid</span><span class="p">.</span><span class="nf">IsVisible</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">activePlayers</span><span class="p">))</span>
<span class="n">colors</span><span class="p">[</span><span class="n">pixel</span><span class="p">]</span> <span class="p">=</span> <span class="n">white</span>
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">visionGrid</span><span class="p">.</span><span class="nf">WasVisible</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">activePlayers</span><span class="p">))</span>
<span class="n">colors</span><span class="p">[</span><span class="n">pixel</span><span class="p">]</span> <span class="p">=</span> <span class="n">grey</span> <span class="c1">// this is for previous vision</span>
<span class="p">}</span>
<span class="n">texture</span><span class="p">.</span><span class="nf">SetPixels</span><span class="p">(</span><span class="n">colors</span><span class="p">)</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The field <code class="highlighter-rouge">activePlayers</code> contains a bit mask of players and it is used to render the current fog of those players. It will normally contain just the main player during game but in situations like replay mode, for example, it can change at any time to render different player’s vision.</p>
<div class="wp-video">
<video class="wp-video-shortcode" id="video-3123-4" preload="metadata" controls="controls"><source type="video/mp4" src="/wp-content/uploads/2018/11/fogmultipleplayers.mp4?_=4" /><a href="/wp-content/uploads/2018/11/fogmultipleplayers.mp4">/wp-content/uploads/2018/11/fogmultipleplayers.mp4</a></video>
</div>
<p>In the case that two players are in an alliance, a bitmask for both players can be used to render their shared vision.</p>
<p>After filling the FogTexture, it is rendered in a RenderTexture using a Camera with a Post Processing filter used to apply some blur to make it look better. This RenderTexture is four times bigger in order to get a better result when applying the Post Processing effects.</p>
<p><img src="/wp-content/uploads/2018/11/render_texture.png" alt="" /></p>
<p>Once I have the RenderTexture, I render it over the game with a custom shader that treats the image as an alpha mask (white is transparent and black is opaque, or red in this case since I don’t need other color channels) similar to how we did with Iron Marines.</p>
<p>Here is how it looks like:</p>
<p><img src="/wp-content/uploads/2018/09/fog-texture-1024x772.png" alt="" /></p>
<p>And here is how it looks in the Unity’s Scene View:</p>
<p><img src="/wp-content/uploads/2018/09/fog-texture-scene.png" alt="" /></p>
<p>The render process is something like this:</p>
<p><img src="/wp-content/uploads/2018/09/Diagram-2018-09-22-20-02-18.png" alt="" /></p>
<h2 id="easing">Easing</h2>
<p>There are some cases when the fog texture changed dramatically from one frame to the other, for example when a new unit appears or when a unit moves to a higher ground.</p>
<p>For those cases, I added easing on the colors array, so each entry in the array transitions in time from the previous state to the new one in order to minimize the change. It was really simple, it added a bit of performance cost when processing the texture pixels but in the end it was so much better than I preferred to pay that extra cost (it can be disabled at any time).</p>
<div class="wp-video">
<video class="wp-video-shortcode" id="video-3123-5" preload="metadata" controls="controls"><source type="video/mp4" src="/wp-content/uploads/2018/09/fog-interpolation.mp4?_=5" /><a href="/wp-content/uploads/2018/09/fog-interpolation.mp4">/wp-content/uploads/2018/09/fog-interpolation.mp4</a></video>
</div>
<p>At first I wasn’t sure about writing pixels directly to a texture since I thought it would be slow but, after testing on mobile devices, it is quite fast so it shouldn’t be an issue.</p>
<h1 id="unit-visibility">Unit visibility</h1>
<p>To know if a unit is visible or not, the system checks for all the entries where the unit is contained (big units could occupy multiple entries) and if at least one of them is visible then the unit is visible. This check is useful to know if a unit can be attacked for example.</p>
<p>Here is a pseudo code:</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">bool</span> <span class="nf">IsVisible</span><span class="p">(</span><span class="n">players</span><span class="p">,</span> <span class="n">unit</span><span class="p">)</span>
<span class="p">{</span>
<span class="c1">// it is a unit from one of the players</span>
<span class="k">if</span> <span class="p">((</span><span class="n">unit</span><span class="p">.</span><span class="n">players</span> <span class="p">&</span> <span class="n">players</span><span class="p">)</span> <span class="p">&</span><span class="n">gt</span><span class="p">;</span> <span class="m">0</span><span class="p">)</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="c1">// returns all the entries where the unit is contained</span>
<span class="n">entries</span> <span class="p">=</span> <span class="n">visionGrid</span><span class="p">.</span><span class="nf">GetEntries</span><span class="p">(</span><span class="n">unit</span><span class="p">.</span><span class="n">position</span><span class="p">,</span> <span class="n">unit</span><span class="p">.</span><span class="n">size</span><span class="p">)</span>
<span class="k">for</span> <span class="p">(</span><span class="n">entry</span> <span class="k">in</span> <span class="n">entries</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">visionGrid</span><span class="p">.</span><span class="nf">IsVisible</span><span class="p">(</span><span class="n">entry</span><span class="p">,</span> <span class="n">players</span><span class="p">))</span>
<span class="k">return</span> <span class="k">true</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">return</span> <span class="k">false</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Which units are visible is related with the fog being rendered so we use the same <code class="highlighter-rouge">activePlayers</code> field to check whether to show or hide a unit.</p>
<p>To avoid rendering units I followed a similar approach to what we did for Iron Marines using the GameObject’s layer, so if the unit is visible, the default layer is set to its GameObject and if the unit is not visible, a layer that is culled from the game camera is set.</p>
<div class="language-c# highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">void</span> <span class="nf">UpdateVisibles</span><span class="p">()</span> <span class="p">{</span>
<span class="k">for</span> <span class="p">(</span><span class="n">unit</span> <span class="k">in</span> <span class="n">units</span><span class="p">)</span> <span class="p">{</span>
<span class="n">unit</span><span class="p">.</span><span class="n">gameObject</span><span class="p">.</span><span class="n">layer</span> <span class="p">=</span> <span class="nf">IsVisible</span><span class="p">(</span><span class="n">activePlayers</span><span class="p">,</span> <span class="n">unit</span><span class="p">)</span> <span class="p">:</span> <span class="k">default</span> <span class="p">?</span> <span class="n">hidden</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="finally">Finally</h1>
<p>This is how everything looks working together:</p>
<div class="video-container">
<iframe src="https://www.youtube.com/embed/ubhF_OjUHck" frameborder="0" allowfullscreen=""></iframe>
</div>
<h1 id="conclusion">Conclusion</h1>
<p>When simplifying the world in a grid and started thinking in terms of textures, it was easier to apply different kind of image algorithms like drawing a filled circle or a line which were really useful when optimizing. There are even more image operations that could be used for the game logic and rendering.</p>
<p>SC2 has a lot of information in terms of textures, not only the player’s vision, and they provide an <a href="https://www.youtube.com/watch?time_continue=1&v=-fKUyT14G-8">API to access it and it is being used for machine learning experiments.</a></p>
<p>I am still working on more features and I plan to try some optimization experiments like using c# job system. I am really excited about that one but I first have to transform my code to make it work. I would love to write about that experiment.</p>
<p>Using a blur effect for the fog texture has some drawbacks like revealing a bit of higher ground when it shouldn’t. I want to research a bit of some other image effect to apply where black color is not modified when blurring but not sure if that is possible or if it is the proper solution. One thing that I want to try though is an upscale technique like the one <a href="https://engineering.riotgames.com/news/story-fog-and-war">used in League of Legends</a> when creating the fog texture and then reduce the applied blur effect, all of this to try to minimize the issue.</p>
<p>After writing this blog post and having to create some images to explain concepts I believe it could be great to add more debug features like showing the vision or terrain grid itself at any time or showing a line from one point to another to show where the vision is blocked and why, among other stuff. That could be useful at some point.</p>
<p>This blog post was really hard to write since, even though I am familiarized with the logic, it was hard to define the proper concepts to be clear when explaining it. In the end, I feel like I forgot to explain some stuff but I can’t realize exactly what.</p>
<p>As always, I really hope you enjoyed it and it would be great to hear your feedback to improve writing this kind of blog posts.</p>
<p>Thanks for reading!</p>arielsanAs I said in the previous blog post, some time ago I started working on a new Fog of War / Vision System solution aiming the following features: Being able to render the fog of war of each player at any time, for replays and debug. Being able to combine multiple players’ visions for alliances, spectator mode or watching replays. Blocking vision by different terrain heights or other elements like bushes. Optimized to support 50+ units at the same time in mobile devices at 60FPS. It should look similar to modern games like Starcraft 2 and League of Legends (in fact, SC2 is already eight years old, not sure if that is consider a modern game or not :P). This is an example of what I want: Example: fog of war in Starcraft 2 To simplify a bit writing this article, when I write unit I mean not only units but also structures or anything that could affect the fog of war in the game. Logic First, there is a concept named UnitVision used to represent anything that reveals fog. Here is the data structure: struct UnitVision { // A bit mask representing a group of players inside // the vision system. int players; // The range of the vision (in world coordinates) float range; // the position (in world coordinates) vector2 position; // used for blocking vision short terrainHeight; } Normally, a game will have one for each unit but there could be cases where a unit could have more (for example a large unit) or even none. A bit mask is used to specify a group of players, so for example, if player 0 is 0001 and player1 is 0010, then 0011 means the group formed by player0 and player1. Since it is an int, it supports up to sizeof(int) players. Most of the time the group would contain only one player but there might be some situations, like a general effect or cinematic, etc, that needs to be seen by all players and one possible solution is to use a unitVision with more than one player. The terrainHeight field stores the current height of the unit and it is used for blocking vision or not. It normally will be the world terrain’s height on that position if it is a ground unit but there are cases like flying units or special abilities that could change the unit height that should be consider when calculating blocked vision. It is the game’s responsibility to update that field accordingly. There is another concept named VisionGrid that represents the vision for all the players. Here is the data structure: struct VisionGrid { // the width and height of the grid (needed to access the arrays) int width, height; // array of size width * height, each entry has an int with the // bits representing which players have this entry in vision. int[] values; // similar to the values but it just stores if a player visited // that entry at some point in time. int[] visited; void SetVisible(i, j, players) { values[i + j * width] |= players; visited[i + j * width] |= players; } void Clear() { values.clear(0); } bool IsVisible(i, j, players) { return (values[i + j * width] & players) &gt; 0; } bool WasVisible(i, j, players) { return (visited[i + j * width] & players) &gt; 0; } } Note: arrays have a size of width * height. The bigger the grid is, the slower it gets to calculate vision but it also has more information which could be useful for units’ behaviors or to get better fog rendering.The smaller the grid is, the opposite. A good balance must be defined from the beginning in order to build the game over that decision. Here is an example of a grid over the game world: Given a grid entry for a world position, the structure stores an int in the values array with the data of which players have that position inside vision. For example, if the entry has 0001 stored, it means only the player0 sees that point. If it has 0011, then both the player0 and player1. This structure also stores when a player revealed fog in the past in the visited array which is used mainly for rendering purposes (gray fog) but could also be used by the game logic (to check if a player knows some information for example). The method IsVisible(i, j, players) will return true if any of the players in the bit mask has the position visible. The method WasVisible(i, j, players) is similar but will check the visited array. So, for example, if player1 and player2 (0010 and 0100 in bits) are in an alliance, then when player2 wants to know if an enemy is visible to perform an attack, it can call isVisible method with the bitmask for both players 0110. Calculating vision Each time the vision grid is updated, the values array is cleared and recalculated. Here is a pseudo code of the algorithm: void CalculateVision() { visionGrid.Clear() for each unitVision in world { for each gridEntry inside unitVision.range { if (not IsBlocked(gridEntry)) { // where set visible updates both the values and the // visited arrays. grid.SetVisible(gridEntry.i, gridEntry.j, unitVision.players) } } } } To iterate over grid entries inside range, it first calculates vision’s position and range in grid coordinates, named gridPosition and gridRange, and then it draws a filled circle of gridRange radius around gridPosition. Blocked vision In order to detect blocked vision, there is another grid of the same size with terrain’s height information. Here is its data structure: struct Terrain { // the width and height of the grid (needed to access the arrays) int width, height; // array of size width * height, has the terrain level of the // grid entry. short[] height; int GetHeight(i, j) { return height[i + j * width]; } } Here is an example of how the grid looks over the game: Note: that image is handmade as an example, there might be some mistakes. While iterating through the vision’s grid entries around unitVision’s range, to detect if the entry is visible or not, the system checks if there are no obstacles to the vision’s center. To do that, it draws a line from the entry’s position to the center’s position. If all the grid entries in the line are in the same height or below, then the entry is visible. Here is an example where the blue dot represents the entry being calculated and white dots the line to the center. If there is at least one entry in the line that is in a greater height, then the line of sight is blocked. Here is an example where the blue dot represents the entry we want to know if it is visible or not, white dots represents entries in the line in the same height and red dots represents entries in a higher ground. Once it detects one entry above the vision it doesn’t need to continue drawing the line to the vision center. Here is a pseudo algorithm: bool IsBlocked() { for each entry in line to unitVision.position { height = terrain.GetHeight(entry.position) if (height &gt; unitVision.height) { return true; } } return false; } Optimizations If an entry was already marked as visible while iterating over all unit visions then there is no need to recalculate it. Reduce the size of the grid. Update the fog less frequently (In Starcraft there is a delay of about 1 second, I recently noticed while playing, it is an old game). Rendering To render the Fog of War, first I have a small texture of the same size of the grid, named FogTexture, where I write a Color array of the same size using the Texture2D.SetPixels() method. Each frame, I iterate on each VisionGrid entry and set the corresponding Color to the array using the values and visited arrays. Here is a pseudo algorithm: void Update() { for i, j in grid { colors[i + j * width] = black if (visionGrid.IsVisible(i, j, activePlayers)) colors[pixel] = white else if (visionGrid.WasVisible(i, j, activePlayers)) colors[pixel] = grey // this is for previous vision } texture.SetPixels(colors) } The field activePlayers contains a bit mask of players and it is used to render the current fog of those players. It will normally contain just the main player during game but in situations like replay mode, for example, it can change at any time to render different player’s vision. /wp-content/uploads/2018/11/fogmultipleplayers.mp4 In the case that two players are in an alliance, a bitmask for both players can be used to render their shared vision. After filling the FogTexture, it is rendered in a RenderTexture using a Camera with a Post Processing filter used to apply some blur to make it look better. This RenderTexture is four times bigger in order to get a better result when applying the Post Processing effects. Once I have the RenderTexture, I render it over the game with a custom shader that treats the image as an alpha mask (white is transparent and black is opaque, or red in this case since I don’t need other color channels) similar to how we did with Iron Marines. Here is how it looks like: And here is how it looks in the Unity’s Scene View: The render process is something like this: Easing There are some cases when the fog texture changed dramatically from one frame to the other, for example when a new unit appears or when a unit moves to a higher ground. For those cases, I added easing on the colors array, so each entry in the array transitions in time from the previous state to the new one in order to minimize the change. It was really simple, it added a bit of performance cost when processing the texture pixels but in the end it was so much better than I preferred to pay that extra cost (it can be disabled at any time). /wp-content/uploads/2018/09/fog-interpolation.mp4 At first I wasn’t sure about writing pixels directly to a texture since I thought it would be slow but, after testing on mobile devices, it is quite fast so it shouldn’t be an issue. Unit visibility To know if a unit is visible or not, the system checks for all the entries where the unit is contained (big units could occupy multiple entries) and if at least one of them is visible then the unit is visible. This check is useful to know if a unit can be attacked for example. Here is a pseudo code: bool IsVisible(players, unit) { // it is a unit from one of the players if ((unit.players & players) &gt; 0) return true; // returns all the entries where the unit is contained entries = visionGrid.GetEntries(unit.position, unit.size) for (entry in entries) { if (visionGrid.IsVisible(entry, players)) return true; } return false; } Which units are visible is related with the fog being rendered so we use the same activePlayers field to check whether to show or hide a unit. To avoid rendering units I followed a similar approach to what we did for Iron Marines using the GameObject’s layer, so if the unit is visible, the default layer is set to its GameObject and if the unit is not visible, a layer that is culled from the game camera is set. void UpdateVisibles() { for (unit in units) { unit.gameObject.layer = IsVisible(activePlayers, unit) : default ? hidden; } } Finally This is how everything looks working together: Conclusion When simplifying the world in a grid and started thinking in terms of textures, it was easier to apply different kind of image algorithms like drawing a filled circle or a line which were really useful when optimizing. There are even more image operations that could be used for the game logic and rendering. SC2 has a lot of information in terms of textures, not only the player’s vision, and they provide an API to access it and it is being used for machine learning experiments. I am still working on more features and I plan to try some optimization experiments like using c# job system. I am really excited about that one but I first have to transform my code to make it work. I would love to write about that experiment. Using a blur effect for the fog texture has some drawbacks like revealing a bit of higher ground when it shouldn’t. I want to research a bit of some other image effect to apply where black color is not modified when blurring but not sure if that is possible or if it is the proper solution. One thing that I want to try though is an upscale technique like the one used in League of Legends when creating the fog texture and then reduce the applied blur effect, all of this to try to minimize the issue. After writing this blog post and having to create some images to explain concepts I believe it could be great to add more debug features like showing the vision or terrain grid itself at any time or showing a line from one point to another to show where the vision is blocked and why, among other stuff. That could be useful at some point. This blog post was really hard to write since, even though I am familiarized with the logic, it was hard to define the proper concepts to be clear when explaining it. In the end, I feel like I forgot to explain some stuff but I can’t realize exactly what. As always, I really hope you enjoyed it and it would be great to hear your feedback to improve writing this kind of blog posts. Thanks for reading!Implementing Fog of War for RTS games in Unity 1/22018-08-27T09:00:07-03:002018-08-27T09:00:07-03:00https://blog.gemserk.com/2018/08/27/implementing-fog-of-war-for-rts-games-in-unity-1-2<p>For the last 3 years, I’ve been working on <a href="https://www.ironmarines.com/">Iron Marines</a> at Ironhide Game Studio, a Real time Strategy Game for mobile devices. During its development, we created a Fog of War solution that works pretty well for the game but it lacks some of the common features other RTS games have, and how to improve that is something I wanted to learn at some point in my life.</p>
<p>Recently, after reading a <a href="https://engineering.riotgames.com/news/story-fog-and-war">Riot Games Engineering blog post about Fog of War in League of Legends</a>, I got motivated and started prototyping a new implementation.</p>
<p>In this blog post I will explain Iron Marines’ Fog of War solution in detail and then I will write another blog post about the new solution and explain why I consider it is better than the first one.</p>
<h1 id="fog-of-war-in-strategy-games">Fog of War in Strategy Games</h1>
<p>It normally represents the missing information about the battle, for example, not knowing how the terrain is yet, or outdated information, for example, the old position of an enemy base. Player units and buildings provide vision that removes Fog during the game revealing information about the terrain and the current location and state of the enemies.</p>
<p><img src="/wp-content/uploads/2018/08/dune-2-ss3.gif" alt="" /></p>
<p style="text-align: center;">
Example: Dune 2 and its Fog of War representing the unknown territory (by the way, you can <a href="https://epicport.com/en/dune2">play Dune 2 online</a>).
</p>
<p><img src="/wp-content/uploads/2018/08/Warcraft_2-300x188.png" alt="" /></p>
<p style="text-align: center;">
Example: Warcraft: Orcs and Humans' Fog of War (it seems you can play <a href="https://www.myabandonware.com/game/warcraft-orcs-humans-250/play-250">Warcraft online too</a>).
</p>
<p>The concept of Fog of War is being used in strategy games since more than 20 years now, which is a lot for video games.</p>
<h1 id="process">Process</h1>
<p>We started by researching other games and deciding what we wanted before start implementing anything.</p>
<p>After that, we decided to target a similar solution to Starcraft (by the way, it is free to play now, just download Battle.net and create an account). In that game, units and buildings have a range of vision that provide vision to the Player. Unexplored territory is covered with full opacity black fog while previously explored territory is covered by half opacity fog, revealing what the Player know about it, information that doesn’t change during the game.</p>
<p><img src="/wp-content/uploads/2018/08/SCScrnShot_082518_153611-1024x768.png" alt="" /></p>
<p>Enemy units and buildings are visible only if they are inside Player’s vision but buildings leave over a last known location after they are not visible anymore. I believe the main reason for that they can’t normally move (with the exception of some Terran buildings) so it is logical to assume they will stay in that position after losing vision and might be vital information about the battle.</p>
<p><img src="/wp-content/uploads/2018/08/SCScrnShot_082518_153737-1024x768.png" alt="" /></p>
<h1 id="iron-marines">Iron Marines</h1>
<p>Given those rules, we created mock images to see how we wanted it to look in our game before started implementing anything.</p>
<p><img src="/wp-content/uploads/2018/08/Stage1_fadeout_test5_with_objective_scaled.png" alt="" /></p>
<p style="text-align: center;">
Mock Image 1: Testing terrain with different kind of Fog in one of the stages of Iron Marines.
</p>
<p><img src="/wp-content/uploads/2018/08/Stage1_fadeout_test7_enemies_scaled.png" alt="" /></p>
<p style="text-align: center;">
Mock Image 2: Testing now with enemy units to see when they should be visible or not.
</p>
<p><img src="/wp-content/uploads/2018/08/image3-1024x887.png" alt="" /></p>
<p>We started by prototyping the logic to see if it works for our game or not and how we should adapt it.</p>
<p>For that, we used an int matrix representing a discrete version of the game world where the Player’s vision is. A matrix’s entry with value 0 means the Player has no vision at that position and a value of 1 or greater means it has.</p>
<p><img src="/wp-content/uploads/2018/08/fog_matrix.png" alt="" /></p>
<p style="text-align: center;">
Image: in this matrix there are 3 visions, and one has greater range.
</p>
<p>Units and buildings’ visions will increment 1 to the value of all entries that represent world positions inside their vision range. Each time they move, we first decrease 1 from its previous position and then we increment 1 in the new position.</p>
<p>We have a matrix for each Player that is used for showing or hiding enemy units and buildings and for auto targeting abilities that can’t fire outside Player’s vision.</p>
<p>To determine if an enemy unit or building is visible or not, we first get the corresponding entry of the matrix by transforming its world position and check if the stored value is greater than 0 or not. If not, we change its GameObject layer to one that is <a href="https://docs.unity3d.com/ScriptReference/Camera-cullingMask.html">culled from the main camera</a> to avoid rendering it, we named that layer “hidden”. If it is visible, we change it back to the default layer, so it starts being rendered again.</p>
<p><img src="/wp-content/uploads/2018/08/ironmarines_enemy_hidden2-1024x519.png" alt="" /></p>
<p>Image: shows how enemy units are not rendered in the Game view. I explain later why buildings are rendered even outside the Player’s vision.</p>
<h2 id="visuals">Visuals</h2>
<p>We started by just rendering a black or grey color quad over the game world for each matrix’s entry, here is an image showing how it looks like (it is the only one I found in the chest of memories):</p>
<p><img src="/wp-content/uploads/2018/08/Screen-Shot-2015-08-19-at-17.45.28-1024x620.png" alt="" /></p>
<p>This allowed us to prototype and decide some features we didn’t want. In particular, we avoided blocking vision by obstacles like mountains or trees since we preferred to avoid the feeling of confinement and also we don’t have multiple levels of terrain like other games do. I will talk more about that feature in the next blog post.</p>
<p>After we knew what we wanted, and tested in the game for a while, we decided to start improving the visual solution.</p>
<p>The improved version consists in rendering a texture with the Fog of War over the entire game world, similar to what we did when we created the visual mocks.</p>
<p>For that, we created a GameObject with a MeshRenderer and scaled it to cover the game world. That mesh renders a texture named FogTexture, which contains the Fog information, using a Shader that considers pixels’ colors as an inverted alpha channel, from White color as full transparent to Black color as full opaque.</p>
<p>Now, in order to fill the FogTexture, we created a separated Camera, named FogCamera, that renders to the texture using a RenderTexture. For each object that provides vision in the game world, we created a corresponding GameObject inside the FogCamera by transforming its position accordingly and scaling it based on the vision’s range. We use a separated Unity’s Layer that is culled from other cameras to only render those GameObjects in the FogCamera.</p>
<p>To complete the process, each of those objects have a SpriteRenderer with a small white Ellipse texture to render white pixels inside the RenderTexture.</p>
<p><em>Note: we use an Ellipse instead of a Circle to simulate the game perspective.</em></p>
<p><img src="/wp-content/uploads/2018/08/FogVision-1.png" alt="" /></p>
<p style="text-align: center;">
Image: This is the texture used for each vision, it is a white Ellipse with transparency (I had to make the transparency opaque so the reader can see it).
</p>
<p><img src="/wp-content/uploads/2018/08/fog_without_previous-300x240.png" alt="" /></p>
<p style="text-align: center;">
Image: this is an example of the GameObjects and the FogCamera.
</p>
<p>In order to make the FogTexture look smooth over the game, we applied a small blur to the FogCamera when rendering to the RenderTexture. We tested different blur shaders and different configurations until we found one that worked fine on multiple mobile devices. Here is how it looks like:</p>
<p><img src="/wp-content/uploads/2018/08/render_texture_blur_config.png" alt="" /></p>
<p>And here is how the Fog looks like in the game, without and with blur:<img src="/wp-content/uploads/2018/08/fog_without_previous_ingame_noblur.png" alt="" /></p>
<p><img src="/wp-content/uploads/2018/08/fog_without_previous_ingame.png" alt="" /></p>
<p>For the purpose of rendering previously revealed territory, we had to add a previous step to the process. In this step, we configured another camera, named PreviousFogCamera, using a RenderTexture too, named PreviousVisionTexture, and we first render the visions there (using the same procedure). The main difference is that the camera is configured to not clear the buffer by using the “Don’t Clear” clear flag, so we can keep the data from previous frames.</p>
<p>After that, we render both the PreviousVisionTexture in gray color and the vision’s GameObjects in the FogTexture using the FogCamera. The final result looks like this:</p>
<p><img src="/wp-content/uploads/2018/08/fog_with_previous.png" alt="" /></p>
<p style="text-align: center;">
Image: it shows the revealed territory in the FogCamera.
</p>
<p><img src="/wp-content/uploads/2018/08/previous_fog_25.png" alt="" /></p>
<p style="text-align: center;">
Image: and here is an example of how the Fog with previous revealed territory looks in the game.
</p>
<h2 id="buildings">Buildings</h2>
<p>Since buildings in Iron Marines are big and they don’t move like Starcraft, we wanted to follow a similar solution.</p>
<p>In order to do that, we identified buildings we wanted to show below the Fog by adding a Component and configuring they were going to be rendered when not inside the Player’s vision.</p>
<p>Then, there is a System that, when a GameObject with that Component enters the Player’s vision for the first time, it creates another GameObject and configures it accordingly. That GameObject is automatically turned on when the building is not inside the Player’s vision anymore and turned off when the building is inside vision. If, by some reason the building was destroyed while not in inside vision, the GameObject doesn’t disappear until the Player discovers its new state.</p>
<p>We added a small easing when entering and leaving the Player’s vision to make it look a bit smoother. Here is a video showing how it looks like:</p>
<div class="wp-video">
<video class="wp-video-shortcode" id="video-3089-3" loop="1" preload="metadata" controls="controls"><source type="video/mp4" src="/wp-content/uploads/2018/08/ironmarines_fog_structures.mp4?_=3" /><a href="/wp-content/uploads/2018/08/ironmarines_fog_structures.mp4">/wp-content/uploads/2018/08/ironmarines_fog_structures.mp4</a></video>
</div>
<h1 id="conclusion">Conclusion</h1>
<p>Our solution lacks some of the common Fog of War features but it works perfectly for our game and looks really nice. It also performed pretty well on mobile devices, which is our main target, and if not done properly it could have affected the game negatively. We are really proud and happy with what we achieved developing Iron Marines.</p>
<p>That was, in great part, how we implemented Fog of War for Iron Marines. I hope you liked both the solution and the article. In the next blog post I will talk more about the new solution which includes more features.</p>
<p>Thanks for reading!</p>arielsanFor the last 3 years, I’ve been working on Iron Marines at Ironhide Game Studio, a Real time Strategy Game for mobile devices. During its development, we created a Fog of War solution that works pretty well for the game but it lacks some of the common features other RTS games have, and how to improve that is something I wanted to learn at some point in my life. Recently, after reading a Riot Games Engineering blog post about Fog of War in League of Legends, I got motivated and started prototyping a new implementation. In this blog post I will explain Iron Marines’ Fog of War solution in detail and then I will write another blog post about the new solution and explain why I consider it is better than the first one. Fog of War in Strategy Games It normally represents the missing information about the battle, for example, not knowing how the terrain is yet, or outdated information, for example, the old position of an enemy base. Player units and buildings provide vision that removes Fog during the game revealing information about the terrain and the current location and state of the enemies. Example: Dune 2 and its Fog of War representing the unknown territory (by the way, you can play Dune 2 online). Example: Warcraft: Orcs and Humans' Fog of War (it seems you can play Warcraft online too). The concept of Fog of War is being used in strategy games since more than 20 years now, which is a lot for video games. Process We started by researching other games and deciding what we wanted before start implementing anything. After that, we decided to target a similar solution to Starcraft (by the way, it is free to play now, just download Battle.net and create an account). In that game, units and buildings have a range of vision that provide vision to the Player. Unexplored territory is covered with full opacity black fog while previously explored territory is covered by half opacity fog, revealing what the Player know about it, information that doesn’t change during the game. Enemy units and buildings are visible only if they are inside Player’s vision but buildings leave over a last known location after they are not visible anymore. I believe the main reason for that they can’t normally move (with the exception of some Terran buildings) so it is logical to assume they will stay in that position after losing vision and might be vital information about the battle. Iron Marines Given those rules, we created mock images to see how we wanted it to look in our game before started implementing anything. Mock Image 1: Testing terrain with different kind of Fog in one of the stages of Iron Marines. Mock Image 2: Testing now with enemy units to see when they should be visible or not. We started by prototyping the logic to see if it works for our game or not and how we should adapt it. For that, we used an int matrix representing a discrete version of the game world where the Player’s vision is. A matrix’s entry with value 0 means the Player has no vision at that position and a value of 1 or greater means it has. Image: in this matrix there are 3 visions, and one has greater range. Units and buildings’ visions will increment 1 to the value of all entries that represent world positions inside their vision range. Each time they move, we first decrease 1 from its previous position and then we increment 1 in the new position. We have a matrix for each Player that is used for showing or hiding enemy units and buildings and for auto targeting abilities that can’t fire outside Player’s vision. To determine if an enemy unit or building is visible or not, we first get the corresponding entry of the matrix by transforming its world position and check if the stored value is greater than 0 or not. If not, we change its GameObject layer to one that is culled from the main camera to avoid rendering it, we named that layer “hidden”. If it is visible, we change it back to the default layer, so it starts being rendered again. Image: shows how enemy units are not rendered in the Game view. I explain later why buildings are rendered even outside the Player’s vision. Visuals We started by just rendering a black or grey color quad over the game world for each matrix’s entry, here is an image showing how it looks like (it is the only one I found in the chest of memories): This allowed us to prototype and decide some features we didn’t want. In particular, we avoided blocking vision by obstacles like mountains or trees since we preferred to avoid the feeling of confinement and also we don’t have multiple levels of terrain like other games do. I will talk more about that feature in the next blog post. After we knew what we wanted, and tested in the game for a while, we decided to start improving the visual solution. The improved version consists in rendering a texture with the Fog of War over the entire game world, similar to what we did when we created the visual mocks. For that, we created a GameObject with a MeshRenderer and scaled it to cover the game world. That mesh renders a texture named FogTexture, which contains the Fog information, using a Shader that considers pixels’ colors as an inverted alpha channel, from White color as full transparent to Black color as full opaque. Now, in order to fill the FogTexture, we created a separated Camera, named FogCamera, that renders to the texture using a RenderTexture. For each object that provides vision in the game world, we created a corresponding GameObject inside the FogCamera by transforming its position accordingly and scaling it based on the vision’s range. We use a separated Unity’s Layer that is culled from other cameras to only render those GameObjects in the FogCamera. To complete the process, each of those objects have a SpriteRenderer with a small white Ellipse texture to render white pixels inside the RenderTexture. Note: we use an Ellipse instead of a Circle to simulate the game perspective. Image: This is the texture used for each vision, it is a white Ellipse with transparency (I had to make the transparency opaque so the reader can see it). Image: this is an example of the GameObjects and the FogCamera. In order to make the FogTexture look smooth over the game, we applied a small blur to the FogCamera when rendering to the RenderTexture. We tested different blur shaders and different configurations until we found one that worked fine on multiple mobile devices. Here is how it looks like: And here is how the Fog looks like in the game, without and with blur: For the purpose of rendering previously revealed territory, we had to add a previous step to the process. In this step, we configured another camera, named PreviousFogCamera, using a RenderTexture too, named PreviousVisionTexture, and we first render the visions there (using the same procedure). The main difference is that the camera is configured to not clear the buffer by using the “Don’t Clear” clear flag, so we can keep the data from previous frames. After that, we render both the PreviousVisionTexture in gray color and the vision’s GameObjects in the FogTexture using the FogCamera. The final result looks like this: Image: it shows the revealed territory in the FogCamera. Image: and here is an example of how the Fog with previous revealed territory looks in the game. Buildings Since buildings in Iron Marines are big and they don’t move like Starcraft, we wanted to follow a similar solution. In order to do that, we identified buildings we wanted to show below the Fog by adding a Component and configuring they were going to be rendered when not inside the Player’s vision. Then, there is a System that, when a GameObject with that Component enters the Player’s vision for the first time, it creates another GameObject and configures it accordingly. That GameObject is automatically turned on when the building is not inside the Player’s vision anymore and turned off when the building is inside vision. If, by some reason the building was destroyed while not in inside vision, the GameObject doesn’t disappear until the Player discovers its new state. We added a small easing when entering and leaving the Player’s vision to make it look a bit smoother. Here is a video showing how it looks like: /wp-content/uploads/2018/08/ironmarines_fog_structures.mp4 Conclusion Our solution lacks some of the common Fog of War features but it works perfectly for our game and looks really nice. It also performed pretty well on mobile devices, which is our main target, and if not done properly it could have affected the game negatively. We are really proud and happy with what we achieved developing Iron Marines. That was, in great part, how we implemented Fog of War for Iron Marines. I hope you liked both the solution and the article. In the next blog post I will talk more about the new solution which includes more features. Thanks for reading!How we used Entity Component System (ECS) approach at Gemserk - 2/22017-12-30T18:00:20-03:002017-12-30T18:00:20-03:00https://blog.gemserk.com/2017/12/30/how-we-used-entity-component-system-ecs-approach-at-gemserk-22<p>So, after <a href="/2017/12/27/how-we-used-entity-component-system-ecs-approach-at-gemserk-12/">our first attempt on using ECS</a>, when we started to develop mobile games and moved to the <a href="https://libgdx.badlogicgames.com/">LibGDX</a> framework, we decided to abandon our ComponentsEngine and start over.</p>
<p>We were <a href="http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/">still reading about ECS</a> while we were creating our <a href="https://github.com/gemserk/commons-gdx">set of tools and code</a> over LibGDX. At some point in time, some of the Java community developers started <a href="https://github.com/gemserk/artemis/tree/gemserk">Artemis</a>, a lightweight ECS, and we decided to give it a try.</p>
<h1 id="artemis">Artemis</h1>
<p>This is a simplified core architecture diagram:</p>
<p><img src="/wp-content/uploads/2017/12/uml_artemis-1.png" alt="" /></p>
<p style="text-align: left;">
<em>Note: we used a modified version of Artemis with some additions <a href="/2012/01/03/reusing-artemis-entities-by-enabling-disabling-and-storing-them/">like enable/disable an Entity</a>.</em>
</p>
<p>In this pure approach, Entities and Components are just data, and they are related by identifiers, like these tables in a relational database:</p>
<p><img src="/wp-content/uploads/2017/12/uml_artemis_db.png" alt="" /></p>
<p>Where we have two entities, both with a PositionComponent and only one of them with MovementComponent.</p>
<p>An example of this components in code:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">PositionComponent</span> <span class="o">:</span> <span class="n">Component</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="n">x</span><span class="o">,</span> <span class="n">y</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">MovementComponent</span><span class="o">:</span> <span class="n">Component</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="n">speed</span><span class="o">;</span>
<span class="o">}</span>
</code></pre></div></div>
<p>EntitySystems perform the game logic. They normally work on a subset of Components from an Entity but they could need it in order to enable/disable/destroy it (if it is part of its logic).</p>
<p>An example of a System is <a href="https://raw.githubusercontent.com/gemserk/commons-gdx/master/commons-gdx-artemis/src/main/java/com/gemserk/commons/artemis/systems/LimitLinearVelocitySystem.java">LimitLinearVelocitySystem</a>, used in multiple of our games to limit the physics velocity of an Entity with PhysicsComponent and LimitVelocityLimitComponent:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">process</span><span class="o">(</span><span class="n">Entity</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">PhysicsComponent</span> <span class="n">physicsComponent</span> <span class="o">=</span>
<span class="n">Components</span><span class="o">.</span><span class="na">getPhysicsComponent</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="n">Body</span> <span class="n">body</span> <span class="o">=</span> <span class="n">physicsComponent</span><span class="o">.</span><span class="na">getPhysics</span><span class="o">().</span><span class="na">getBody</span><span class="o">();</span>
<span class="n">LinearVelocityLimitComponent</span> <span class="n">limitComponent</span> <span class="o">=</span>
<span class="n">e</span><span class="o">.</span><span class="na">getComponent</span><span class="o">(</span><span class="n">LinearVelocityLimitComponent</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">Vector2</span> <span class="n">linearVelocity</span> <span class="o">=</span> <span class="n">body</span><span class="o">.</span><span class="na">getLinearVelocity</span><span class="o">();</span>
<span class="kt">float</span> <span class="n">speed</span> <span class="o">=</span> <span class="n">linearVelocity</span><span class="o">.</span><span class="na">len</span><span class="o">();</span>
<span class="kt">float</span> <span class="n">maxSpeed</span> <span class="o">=</span> <span class="n">limitComponent</span><span class="o">.</span><span class="na">getLimit</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">speed</span> <span class="o">&</span><span class="n">gt</span><span class="o">;</span> <span class="n">maxSpeed</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">float</span> <span class="n">factor</span> <span class="o">=</span> <span class="n">maxSpeed</span> <span class="o">/</span> <span class="n">speed</span><span class="o">;</span>
<span class="n">linearVelocity</span><span class="o">.</span><span class="na">mul</span><span class="o">(</span><span class="n">factor</span><span class="o">);</span>
<span class="n">body</span><span class="o">.</span><span class="na">setLinearVelocity</span><span class="o">(</span><span class="n">linearVelocity</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>There are some extra classes like the TagManager which allows assigning a unique string identifier to an Entity in order to find it, and the GroupManager which allows adding entities to groups identified by a name, which is more like how tags are used everywhere else.</p>
<p>Even though it could look similar to our ComponentsEngine where the Properties in that engine correspond to the Components in this one, and Components to Systems, there is an important difference: Systems are not part of an Entity and work horizontally over all entities with specific Components (data). So, in this approach, changing only data from entities indeed change their behaviour in the game, so it is really data driven.</p>
<p>Since Entities and Components are just data, their instances in memory are easier to reuse. An Entity is just an id, so it is obvious. A Component is a set of data that doesn’t care too much which Entity it belongs to. So, after the Entity doesn’t need it anymore, it could be reused elsewhere, improving a lot memory usage and garbage collection.</p>
<p>Artemis, and other pure ECS implementations, are really lightweight and performant frameworks. The real power comes from the Systems and Components built over them. In our case, we created a lot of Systems that we started to reuse between games, from <a href="https://github.com/gemserk/superflyingthing">SuperFlyingThing</a> to VampireRunner and even in Clash of the Olympians.</p>
<h2 id="scripting">Scripting</h2>
<p>One of the most interesting ones is the <a href="/2011/11/13/scripting-with-artemis/">Scripting framework we created over Artemis.</a> It was really useful and gave us a lot of power to overcome some of the limitations we were facing with the pure approach when we need to create a specific logic for a specific moment during the game and (probably) never again and we didn’t want a System for that.</p>
<p>They work similar to Unity MonoBehaviours and our logic Components from ComponentsEngine, and they also belong to the Entity lifecycle. One difference, however, is that they try to avoid storing data in their instances as much as possible and instead try to store and read data from Components, like Systems do.</p>
<p>Here is an example Script from one of our games:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nc">MovementScript</span> <span class="kd">extends</span> <span class="n">ScriptJavaImpl</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">update</span><span class="o">(</span><span class="n">World</span> <span class="n">world</span><span class="o">,</span> <span class="n">Entity</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">MovementComponent</span> <span class="n">movementComponent</span> <span class="o">=</span> <span class="n">Components</span><span class="o">.</span><span class="na">getMovementComponent</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="n">SpatialComponent</span> <span class="n">spatialComponent</span> <span class="o">=</span> <span class="n">Components</span><span class="o">.</span><span class="na">getSpatialComponent</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="n">ControllerComponent</span> <span class="n">controllerComponent</span> <span class="o">=</span> <span class="n">Components</span><span class="o">.</span><span class="na">getControllerComponent</span><span class="o">(</span><span class="n">e</span><span class="o">);</span>
<span class="n">Controller</span> <span class="n">controller</span> <span class="o">=</span> <span class="n">controllerComponent</span><span class="o">.</span><span class="na">controller</span><span class="o">;</span>
<span class="n">Movement</span> <span class="n">movement</span> <span class="o">=</span> <span class="n">movementComponent</span><span class="o">.</span><span class="na">getMovement</span><span class="o">();</span>
<span class="n">Spatial</span> <span class="n">spatial</span> <span class="o">=</span> <span class="n">spatialComponent</span><span class="o">.</span><span class="na">getSpatial</span><span class="o">();</span>
<span class="kt">float</span> <span class="n">rotationAngle</span> <span class="o">=</span> <span class="n">controllerComponent</span><span class="o">.</span><span class="na">rotationSpeed</span> <span class="o">*</span> <span class="n">GlobalTime</span><span class="o">.</span><span class="na">getDelta</span><span class="o">();</span>
<span class="n">Vector2</span> <span class="n">linearVelocity</span> <span class="o">=</span> <span class="n">movement</span><span class="o">.</span><span class="na">getLinearVelocity</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">controller</span><span class="o">.</span><span class="na">left</span><span class="o">)</span> <span class="o">{</span>
<span class="n">spatial</span><span class="o">.</span><span class="na">setAngle</span><span class="o">(</span><span class="n">spatial</span><span class="o">.</span><span class="na">getAngle</span><span class="o">()</span> <span class="o">+</span> <span class="n">rotationAngle</span><span class="o">);</span>
<span class="n">linearVelocity</span><span class="o">.</span><span class="na">rotate</span><span class="o">(</span><span class="n">rotationAngle</span><span class="o">);</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(</span><span class="n">controller</span><span class="o">.</span><span class="na">right</span><span class="o">)</span> <span class="o">{</span>
<span class="n">spatial</span><span class="o">.</span><span class="na">setAngle</span><span class="o">(</span><span class="n">spatial</span><span class="o">.</span><span class="na">getAngle</span><span class="o">()</span> <span class="o">-</span> <span class="n">rotationAngle</span><span class="o">);</span>
<span class="n">linearVelocity</span><span class="o">.</span><span class="na">rotate</span><span class="o">(-</span><span class="n">rotationAngle</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p><em>Note: GlobalTime.getDelta() is similar to Unity’s Time API.</em></p>
<p>One problem about the Scripting framework is that it is not always clear when some logic should be in a Script or a System, and that made reusability a bit harder. In the case of the example above, it is obvious it should be moved to a System.</p>
<h2 id="templates">Templates</h2>
<p>Another useful thing we did over Artemis was <a href="https://github.com/gemserk/commons-gdx/blob/master/commons-gdx-artemis/src/main/java/com/gemserk/commons/artemis/templates/EntityTemplate.java">using templates to build entities</a> in a specific way, similar to what we had in ComponentsEngine.</p>
<p>We used also a concept of Parameters in templates in order to customize parts of them. Similar to ComponentsEngine, templates could apply other templates and different templates could be applied to the same Entity.</p>
<p>Here is an example of an Entity template:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">apply</span><span class="o">(</span><span class="n">Entity</span> <span class="n">entity</span><span class="o">)</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">id</span> <span class="o">=</span> <span class="n">parameters</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"id"</span><span class="o">);</span>
<span class="n">String</span> <span class="n">targetPortalId</span> <span class="o">=</span> <span class="n">parameters</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"targetPortalId"</span><span class="o">);</span>
<span class="n">String</span> <span class="n">spriteId</span> <span class="o">=</span> <span class="n">parameters</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"sprite"</span><span class="o">,</span> <span class="s">"PortalSprite"</span><span class="o">);</span>
<span class="n">Spatial</span> <span class="n">spatial</span> <span class="o">=</span> <span class="n">parameters</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"spatial"</span><span class="o">);</span>
<span class="n">Script</span> <span class="n">script</span> <span class="o">=</span> <span class="n">parameters</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="s">"script"</span><span class="o">,</span> <span class="k">new</span> <span class="n">PortalScript</span><span class="o">());</span>
<span class="n">Sprite</span> <span class="n">sprite</span> <span class="o">=</span> <span class="n">resourceManager</span><span class="o">.</span><span class="na">getResourceValue</span><span class="o">(</span><span class="n">spriteId</span><span class="o">);</span>
<span class="n">entity</span><span class="o">.</span><span class="na">addComponent</span><span class="o">(</span><span class="k">new</span> <span class="n">TagComponent</span><span class="o">(</span><span class="n">id</span><span class="o">));</span>
<span class="n">entity</span><span class="o">.</span><span class="na">addComponent</span><span class="o">(</span><span class="k">new</span> <span class="n">SpriteComponent</span><span class="o">(</span><span class="n">sprite</span><span class="o">,</span> <span class="n">Colors</span><span class="o">.</span><span class="na">darkBlue</span><span class="o">));</span>
<span class="n">entity</span><span class="o">.</span><span class="na">addComponent</span><span class="o">(</span><span class="k">new</span> <span class="n">Components</span><span class="o">.</span><span class="na">PortalComponent</span><span class="o">(</span><span class="n">targetPortalId</span><span class="o">,</span> <span class="n">spatial</span><span class="o">.</span><span class="na">getAngle</span><span class="o">()));</span>
<span class="n">entity</span><span class="o">.</span><span class="na">addComponent</span><span class="o">(</span><span class="k">new</span> <span class="n">RenderableComponent</span><span class="o">(-</span><span class="mi">5</span><span class="o">));</span>
<span class="n">entity</span><span class="o">.</span><span class="na">addComponent</span><span class="o">(</span><span class="k">new</span> <span class="n">SpatialComponent</span><span class="o">(</span><span class="n">spatial</span><span class="o">));</span>
<span class="n">entity</span><span class="o">.</span><span class="na">addComponent</span><span class="o">(</span><span class="k">new</span> <span class="n">ScriptComponent</span><span class="o">(</span><span class="n">script</span><span class="o">));</span>
<span class="n">Body</span> <span class="n">body</span> <span class="o">=</span> <span class="n">bodyBuilder</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">fixture</span><span class="o">(</span><span class="n">bodyBuilder</span><span class="o">.</span><span class="na">fixtureDefBuilder</span><span class="o">()</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">circleShape</span><span class="o">(</span><span class="n">spatial</span><span class="o">.</span><span class="na">getWidth</span><span class="o">()</span> <span class="o">*</span> <span class="mf">0.35f</span><span class="o">)</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">categoryBits</span><span class="o">(</span><span class="n">CategoryBits</span><span class="o">.</span><span class="na">ObstacleCategoryBits</span><span class="o">)</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">maskBits</span><span class="o">((</span><span class="kt">short</span><span class="o">)</span> <span class="o">(</span><span class="n">CategoryBits</span><span class="o">.</span><span class="na">AllCategoryBits</span> <span class="o">&</span> <span class="o">~</span><span class="n">CategoryBits</span><span class="o">.</span><span class="na">ObstacleCategoryBits</span><span class="o">))</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">sensor</span><span class="o">())</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">position</span><span class="o">(</span><span class="n">spatial</span><span class="o">.</span><span class="na">getX</span><span class="o">(),</span> <span class="n">spatial</span><span class="o">.</span><span class="na">getY</span><span class="o">())</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">mass</span><span class="o">(</span><span class="mi">1</span><span class="n">f</span><span class="o">)</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">type</span><span class="o">(</span><span class="n">BodyType</span><span class="o">.</span><span class="na">StaticBody</span><span class="o">)</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">userData</span><span class="o">(</span><span class="n">entity</span><span class="o">)</span> <span class="c1">//</span>
<span class="o">.</span><span class="na">build</span><span class="o">();</span>
<span class="n">entity</span><span class="o">.</span><span class="na">addComponent</span><span class="o">(</span><span class="k">new</span> <span class="n">PhysicsComponent</span><span class="o">(</span><span class="k">new</span> <span class="n">PhysicsImpl</span><span class="o">(</span><span class="n">body</span><span class="o">)));</span>
<span class="o">}</span>
</code></pre></div></div>
<p>That template configures a Portal entity in SuperFlyingThing which teleports the main ship from one place to another. <a href="https://github.com/gemserk/superflyingthing/tree/master/superflyingthing-core/src/main/java/com/gemserk/games/superflyingthing/templates">Click here</a> for the list of templates used in that game.</p>
<h2 id="interacting-with-other-systems">Interacting with other systems</h2>
<p>Sometimes you already have a solution for something, like the physics engine, and you want to integrate it with the ECS. <a href="/2012/02/02/how-we-use-box2d-with-artemis/">The way we found</a> was to create a way to synchronize data from that system to the ECS and vice versa, sometimes having to replicate a bit of data in order to have it easier for the game to use it.</p>
<h1 id="finally">Finally</h1>
<p>Even though we had to do some modifications and we know it could still be improved, we loved using a pure ECS in the way we did.</p>
<p>It was used to build different kind of games/prototypes and even a full game like the <a href="/2013/01/05/clash-of-the-olympians-for-android/">Clash of the Olympians</a> for mobile devices, and it worked pretty well.</p>
<h1 id="what-about-now">What about now?</h1>
<p>Right now we are not using any of this in Unity. However we never lost interest nor feith in ECS, and there are starting to appear new solutions over Unity in the last years that caught our attention. <a href="https://github.com/sschmid/Entitas-CSharp">Entitas</a> is one of them. The Unity team is working towards this path too as shown in this <a href="https://www.youtube.com/watch?v=tGmnZdY5Y-E">video</a>. Someone who din’t want to wait started <a href="https://github.com/Spy-Shifty/BrokenBricksECS">implementing that solution</a> in his own way. We’ve also watched some Unite and GDC talks about using this approach in big games and some of them even have a Scripting layer too, which is awesome since, in some way, it validates we weren’t so wrong ;).</p>
<p>I am exited to try ECS approach again in the near future. I believe it could be a really good foundation for multiplayer games and that is something I’m really interested in doing at some point in my life.</p>
<p>Thanks for reading.</p>
<h1 id="references">References</h1>
<ul>
<li><a href="https://github.com/gemserk/artemis/wiki/Mini-Tutorial">A mini tutorial on how to use Artemis</a>.</li>
<li>The source code of <a href="https://github.com/gemserk/artemis/tree/gemserk">Artemis + our modifications</a>.</li>
<li>A blog post on the <a href="/2012/01/03/reusing-artemis-entities-by-enabling-disabling-and-storing-them/">enable/disable</a> addition over Artemis.</li>
<li>A blog post explaining our <a href="/2011/11/13/scripting-with-artemis/">Scripting framework over Artemis</a>.</li>
<li>How we managed to use external data like <a href="/2012/02/02/how-we-use-box2d-with-artemis/">box2d physics inside the Artemis</a>.</li>
<li>All <a href="https://github.com/gemserk/commons-gdx/tree/master/commons-gdx-artemis">our code over artemis</a>, like the Systems used in different games.</li>
<li><a href="https://github.com/gemserk/superflyingthing/blob/master/superflyingthing-core/src/main/java/com/gemserk/games/superflyingthing/components/Components.java">Example components</a> used in SuperFlyingThing game.</li>
<li><a href="https://github.com/gemserk/commons-gdx/tree/master/commons-gdx-artemis/src/main/java/com/gemserk/commons/artemis/systems">Example systems</a> we reused among different games.</li>
<li><a href="http://t-machine.org/index.php/2007/09/03/entity-systems-are-the-future-of-mmog-development-part-1/">The first</a> of a serie of great articles about ECS.</li>
<li><a href="http://entity-systems.wikidot.com/artemis-entity-system-framework">A website explaining Artemis</a>.</li>
</ul>arielsanSo, after our first attempt on using ECS, when we started to develop mobile games and moved to the LibGDX framework, we decided to abandon our ComponentsEngine and start over. We were still reading about ECS while we were creating our set of tools and code over LibGDX. At some point in time, some of the Java community developers started Artemis, a lightweight ECS, and we decided to give it a try. Artemis This is a simplified core architecture diagram: Note: we used a modified version of Artemis with some additions like enable/disable an Entity. In this pure approach, Entities and Components are just data, and they are related by identifiers, like these tables in a relational database: Where we have two entities, both with a PositionComponent and only one of them with MovementComponent. An example of this components in code: public class PositionComponent : Component { public float x, y; } public class MovementComponent: Component { public float speed; } EntitySystems perform the game logic. They normally work on a subset of Components from an Entity but they could need it in order to enable/disable/destroy it (if it is part of its logic). An example of a System is LimitLinearVelocitySystem, used in multiple of our games to limit the physics velocity of an Entity with PhysicsComponent and LimitVelocityLimitComponent: public void process(Entity e) { PhysicsComponent physicsComponent = Components.getPhysicsComponent(e); Body body = physicsComponent.getPhysics().getBody(); LinearVelocityLimitComponent limitComponent = e.getComponent(LinearVelocityLimitComponent.class); Vector2 linearVelocity = body.getLinearVelocity(); float speed = linearVelocity.len(); float maxSpeed = limitComponent.getLimit(); if (speed &gt; maxSpeed) { float factor = maxSpeed / speed; linearVelocity.mul(factor); body.setLinearVelocity(linearVelocity); } } There are some extra classes like the TagManager which allows assigning a unique string identifier to an Entity in order to find it, and the GroupManager which allows adding entities to groups identified by a name, which is more like how tags are used everywhere else. Even though it could look similar to our ComponentsEngine where the Properties in that engine correspond to the Components in this one, and Components to Systems, there is an important difference: Systems are not part of an Entity and work horizontally over all entities with specific Components (data). So, in this approach, changing only data from entities indeed change their behaviour in the game, so it is really data driven. Since Entities and Components are just data, their instances in memory are easier to reuse. An Entity is just an id, so it is obvious. A Component is a set of data that doesn’t care too much which Entity it belongs to. So, after the Entity doesn’t need it anymore, it could be reused elsewhere, improving a lot memory usage and garbage collection. Artemis, and other pure ECS implementations, are really lightweight and performant frameworks. The real power comes from the Systems and Components built over them. In our case, we created a lot of Systems that we started to reuse between games, from SuperFlyingThing to VampireRunner and even in Clash of the Olympians. Scripting One of the most interesting ones is the Scripting framework we created over Artemis. It was really useful and gave us a lot of power to overcome some of the limitations we were facing with the pure approach when we need to create a specific logic for a specific moment during the game and (probably) never again and we didn’t want a System for that. They work similar to Unity MonoBehaviours and our logic Components from ComponentsEngine, and they also belong to the Entity lifecycle. One difference, however, is that they try to avoid storing data in their instances as much as possible and instead try to store and read data from Components, like Systems do. Here is an example Script from one of our games: public class MovementScript extends ScriptJavaImpl { @Override public void update(World world, Entity e) { MovementComponent movementComponent = Components.getMovementComponent(e); SpatialComponent spatialComponent = Components.getSpatialComponent(e); ControllerComponent controllerComponent = Components.getControllerComponent(e); Controller controller = controllerComponent.controller; Movement movement = movementComponent.getMovement(); Spatial spatial = spatialComponent.getSpatial(); float rotationAngle = controllerComponent.rotationSpeed * GlobalTime.getDelta(); Vector2 linearVelocity = movement.getLinearVelocity(); if (controller.left) { spatial.setAngle(spatial.getAngle() + rotationAngle); linearVelocity.rotate(rotationAngle); } else if (controller.right) { spatial.setAngle(spatial.getAngle() - rotationAngle); linearVelocity.rotate(-rotationAngle); } } } Note: GlobalTime.getDelta() is similar to Unity’s Time API. One problem about the Scripting framework is that it is not always clear when some logic should be in a Script or a System, and that made reusability a bit harder. In the case of the example above, it is obvious it should be moved to a System. Templates Another useful thing we did over Artemis was using templates to build entities in a specific way, similar to what we had in ComponentsEngine. We used also a concept of Parameters in templates in order to customize parts of them. Similar to ComponentsEngine, templates could apply other templates and different templates could be applied to the same Entity. Here is an example of an Entity template: public void apply(Entity entity) { String id = parameters.get("id"); String targetPortalId = parameters.get("targetPortalId"); String spriteId = parameters.get("sprite", "PortalSprite"); Spatial spatial = parameters.get("spatial"); Script script = parameters.get("script", new PortalScript()); Sprite sprite = resourceManager.getResourceValue(spriteId); entity.addComponent(new TagComponent(id)); entity.addComponent(new SpriteComponent(sprite, Colors.darkBlue)); entity.addComponent(new Components.PortalComponent(targetPortalId, spatial.getAngle())); entity.addComponent(new RenderableComponent(-5)); entity.addComponent(new SpatialComponent(spatial)); entity.addComponent(new ScriptComponent(script)); Body body = bodyBuilder // .fixture(bodyBuilder.fixtureDefBuilder() // .circleShape(spatial.getWidth() * 0.35f) // .categoryBits(CategoryBits.ObstacleCategoryBits) // .maskBits((short) (CategoryBits.AllCategoryBits & ~CategoryBits.ObstacleCategoryBits)) // .sensor()) // .position(spatial.getX(), spatial.getY()) // .mass(1f) // .type(BodyType.StaticBody) // .userData(entity) // .build(); entity.addComponent(new PhysicsComponent(new PhysicsImpl(body))); } That template configures a Portal entity in SuperFlyingThing which teleports the main ship from one place to another. Click here for the list of templates used in that game. Interacting with other systems Sometimes you already have a solution for something, like the physics engine, and you want to integrate it with the ECS. The way we found was to create a way to synchronize data from that system to the ECS and vice versa, sometimes having to replicate a bit of data in order to have it easier for the game to use it. Finally Even though we had to do some modifications and we know it could still be improved, we loved using a pure ECS in the way we did. It was used to build different kind of games/prototypes and even a full game like the Clash of the Olympians for mobile devices, and it worked pretty well. What about now? Right now we are not using any of this in Unity. However we never lost interest nor feith in ECS, and there are starting to appear new solutions over Unity in the last years that caught our attention. Entitas is one of them. The Unity team is working towards this path too as shown in this video. Someone who din’t want to wait started implementing that solution in his own way. We’ve also watched some Unite and GDC talks about using this approach in big games and some of them even have a Scripting layer too, which is awesome since, in some way, it validates we weren’t so wrong ;). I am exited to try ECS approach again in the near future. I believe it could be a really good foundation for multiplayer games and that is something I’m really interested in doing at some point in my life. Thanks for reading. References A mini tutorial on how to use Artemis. The source code of Artemis + our modifications. A blog post on the enable/disable addition over Artemis. A blog post explaining our Scripting framework over Artemis. How we managed to use external data like box2d physics inside the Artemis. All our code over artemis, like the Systems used in different games. Example components used in SuperFlyingThing game. Example systems we reused among different games. The first of a serie of great articles about ECS. A website explaining Artemis.How we used Entity Component System (ECS) approach at Gemserk - 1/22017-12-27T22:13:46-03:002017-12-27T22:13:46-03:00https://blog.gemserk.com/2017/12/27/how-we-used-entity-component-system-ecs-approach-at-gemserk-12<p>When we started Gemserk <a href="/2010/01/28/welcome/">eight years ago</a>, we didn’t know which was the best way to make games. So before starting, we did some research. After reading some articles and presentations we were really interested in trying an Entity Component System (ECS) approach for our games. However, since we didn’t find a clear guide or implementation at that point we had to create our own solution while exploring and understanding it. We named our engine <a href="https://github.com/gemserk/componentsengine">ComponentsEngine.</a></p>
<h1 id="components-engine">Components Engine</h1>
<p>The following image shows a simplified core architecture diagram:</p>
<p><img src="/wp-content/uploads/2017/12/uml_componentsengine-2.png" alt="" /></p>
<p><em>Note: part of the design was inspired by a Flash ECS engine named <a href="https://github.com/PushButtonLabs/PushButtonEngine/tree/master">PushButtonEngine</a>.</em></p>
<p>An Entity is just a holder of state and logic. In an ECS, anything can be an Entity, from an enemy ship to the concept of a player or even a file path to a level definition. It depends a lot on the game you are making and how you want to structure it.</p>
<p>A Property is part of the state of an Entity, like the health or the position in the world, anything that means something for the state of the game. It can be accessed and modified from outside.</p>
<p>Components perform logic updating one or more Properties to change the Entity state. A component could for example change the position of an Entity given a speed and a moving direction.</p>
<p>They normally communicate with each other either by modifying common Properties (when on the same Entity) or by sending and receiving Messages through a MessageDispatcher (when on the same or on different Entities). They just have to register a method to handle a message. In some way, this is pretty similar to using SendMessage() method in Unity and having the proper methods in the MonoBehaviours that need to react to those messages.</p>
<p>EntityTemplates are an easy way to define and build specific game entities, they just add Properties and Components (and more stuff) to make an Entity behave in one way or another.</p>
<p>For example, a ShipTemplate could add position, velocity and health properties and some components to perform movement and to process damage from bullet hits:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kt">void</span> <span class="nf">build</span><span class="o">()</span> <span class="o">{</span>
<span class="c1">// ... more stuff </span>
<span class="n">property</span><span class="o">(</span><span class="s">"position"</span><span class="o">,</span> <span class="k">new</span> <span class="n">Vector2f</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">0</span><span class="o">));</span>
<span class="n">property</span><span class="o">(</span><span class="s">"direction"</span><span class="o">,</span> <span class="k">new</span> <span class="n">Vector2f</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="mi">0</span><span class="o">));</span>
<span class="n">property</span><span class="o">(</span><span class="s">"speed"</span><span class="o">,</span> <span class="mf">5.0f</span><span class="o">);</span>
<span class="n">property</span><span class="o">(</span><span class="s">"currentHealth"</span><span class="o">,</span> <span class="mf">100.0f</span><span class="o">);</span>
<span class="n">property</span><span class="o">(</span><span class="s">"maxHealth"</span><span class="o">,</span> <span class="mf">100.0f</span><span class="o">);</span>
<span class="n">component</span><span class="o">(</span><span class="k">new</span> <span class="n">MovementComponent</span><span class="o">());</span>
<span class="n">component</span><span class="o">(</span><span class="k">new</span> <span class="n">HealthComponent</span><span class="o">());</span>
<span class="o">}</span>
</code></pre></div></div>
<p>An example of the MovementComponent:</p>
<div class="language-java highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">public</span> <span class="kd">class</span> <span class="nf">MovementComponent</span><span class="o">()</span> <span class="o">{</span>
<span class="nd">@EntityProperty</span>
<span class="n">Vector2f</span> <span class="n">position</span><span class="o">;</span>
<span class="nd">@EntityProperty</span>
<span class="n">Vector2f</span> <span class="n">direction</span><span class="o">;</span>
<span class="nd">@EntityProperty</span>
<span class="n">Float</span> <span class="n">speed</span><span class="o">;</span>
<span class="nd">@Handles</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">update</span><span class="o">(</span><span class="n">Message</span> <span class="n">message</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Property</span><span class="o">&</span><span class="n">lt</span><span class="o">;</span><span class="n">Float</span><span class="o">&</span><span class="n">gt</span><span class="o">;</span> <span class="n">dt</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="na">getProperty</span><span class="o">(</span><span class="s">"deltaTime"</span><span class="o">);</span>
<span class="n">position</span> <span class="o">+=</span> <span class="n">direction</span> <span class="o">*</span> <span class="n">speed</span> <span class="o">*</span> <span class="n">dt</span><span class="o">.</span><span class="na">get</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</code></pre></div></div>
<p>EntityTemplates are similar to Unity Prefabs or Unreal Engine Blueprints, representing in some way a (not pure) Prototype pattern.</p>
<p>Some interesting stuff of our engine:</p>
<ul>
<li>We can apply multiple templates to the same Entity. In this way, we could add generic features, like motion for example, by applying common templates. So, we could do something like OrcTemplate.apply(e) to add the orc properties and components and then MovableTemplate.apply(e), so now we have an Orc that moves.</li>
<li>Templates can apply other templates inside them. So we could do the same as before but inside OrcTemplate, we could apply MovableTemplate there. Or even use this to create specific templates, like OrcBossTemplate which is an Orc with a special ability.</li>
<li>Entities have also tags which are defined when applying a template too and are used to quickly identify entities of interest. For example, if we want to identify all bullets in the game, we could add the tag “Bullet” during the Entity creation and then, when processing a special power, we get all the bullets in the scene and make them explode. <em>Note: in some ECS a “flag” component is used for this purpose.</em></li>
<li>The Property abstraction is really powerful, it can be implemented in any way, for example, an expression property like “my current health is my speed * 2”. We used that while prototyping.</li>
</ul>
<p>Some bad stuff:</p>
<ul>
<li>Execution speed wasn’t good, we had a lot of layers in the middle, a lot of reflection, send and receive messages (even for the update method), a lot of boxing and unboxing, etc. It worked ok in desktop but wasn’t a viable solution for mobile devices.</li>
<li>The logic started to be distributed all around and it wasn’t easy to reuse, and we started to have tons of special cases, when we couldn’t reuse something we simply copy-pasted and changed it.</li>
<li>There was a lot of code in the Components to get/set properties instead of just doing the important logic.</li>
<li>Indirection in Properties code was powerful but we end up with stuff like this (and we didn’t like it since it was too much code overhead):</li>
</ul>
<p><code class="highlighter-rouge">e.getProperty("key").value = e.getProperty("key").value + 1.</code></p>
<ul>
<li>We didn’t manage to have a good data driven approach which is one of the best points of ECS. In order to have different behaviours we were forced to add both properties, components and even tags instead of just changing data.</li>
</ul>
<p><em>Note: Some of these points can be improved but we never worked on that.</em></p>
<p>Even though we don’t think the achitecture is bad, it guided us to do stuff in a way we didn’t like it and didn’t scale. We feel that Unity does the same thing with its GameObjects and MonoBehaviours, all the examples in their documentation go in that direction.</p>
<p>That was our first try to the ECS approach. In case you are interested, <a href="https://github.com/gemserk/componentsengine">ComponentsEngine</a> and <a href="https://github.com/gemserk/componentsengine-games">all the games we did</a> with it are on Github and even though they are probably not compiling, they could be used as reference.</p>
<p>This post will continue with how we later transitioned to use a more pure approach with <a href="https://github.com/gemserk/artemis">Artemis</a>, when we were more dedicated to mobile games.</p>
<h1 id="references">References</h1>
<p><a href="http://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/">Evolve your hierarchy</a> - Classic article about Entity Component System.</p>
<p><a href="https://github.com/PushButtonLabs/PushButtonEngine/tree/master">PushButtonEngine</a> - Flash Entity Component System we used as reference when developing our ComponentsEngine.</p>
<p><a href="http://www.richardlord.net/presentations/game-architecture-is-different.html">Game architecture is different</a> - A quick transformation from normal game architecture to ECS.</p>
<p><a href="http://slick.ninjacave.com/">Slick2D</a> - The game library we were using during ComponentsEngine development.</p>arielsanWhen we started Gemserk eight years ago, we didn’t know which was the best way to make games. So before starting, we did some research. After reading some articles and presentations we were really interested in trying an Entity Component System (ECS) approach for our games. However, since we didn’t find a clear guide or implementation at that point we had to create our own solution while exploring and understanding it. We named our engine ComponentsEngine. Components Engine The following image shows a simplified core architecture diagram: Note: part of the design was inspired by a Flash ECS engine named PushButtonEngine. An Entity is just a holder of state and logic. In an ECS, anything can be an Entity, from an enemy ship to the concept of a player or even a file path to a level definition. It depends a lot on the game you are making and how you want to structure it. A Property is part of the state of an Entity, like the health or the position in the world, anything that means something for the state of the game. It can be accessed and modified from outside. Components perform logic updating one or more Properties to change the Entity state. A component could for example change the position of an Entity given a speed and a moving direction. They normally communicate with each other either by modifying common Properties (when on the same Entity) or by sending and receiving Messages through a MessageDispatcher (when on the same or on different Entities). They just have to register a method to handle a message. In some way, this is pretty similar to using SendMessage() method in Unity and having the proper methods in the MonoBehaviours that need to react to those messages. EntityTemplates are an easy way to define and build specific game entities, they just add Properties and Components (and more stuff) to make an Entity behave in one way or another. For example, a ShipTemplate could add position, velocity and health properties and some components to perform movement and to process damage from bullet hits: public void build() { // ... more stuff property("position", new Vector2f(0, 0)); property("direction", new Vector2f(1, 0)); property("speed", 5.0f); property("currentHealth", 100.0f); property("maxHealth", 100.0f); component(new MovementComponent()); component(new HealthComponent()); } An example of the MovementComponent: public class MovementComponent() { @EntityProperty Vector2f position; @EntityProperty Vector2f direction; @EntityProperty Float speed; @Handles public void update(Message message) { Property&lt;Float&gt; dt = message.getProperty("deltaTime"); position += direction * speed * dt.get(); } } EntityTemplates are similar to Unity Prefabs or Unreal Engine Blueprints, representing in some way a (not pure) Prototype pattern. Some interesting stuff of our engine: We can apply multiple templates to the same Entity. In this way, we could add generic features, like motion for example, by applying common templates. So, we could do something like OrcTemplate.apply(e) to add the orc properties and components and then MovableTemplate.apply(e), so now we have an Orc that moves. Templates can apply other templates inside them. So we could do the same as before but inside OrcTemplate, we could apply MovableTemplate there. Or even use this to create specific templates, like OrcBossTemplate which is an Orc with a special ability. Entities have also tags which are defined when applying a template too and are used to quickly identify entities of interest. For example, if we want to identify all bullets in the game, we could add the tag “Bullet” during the Entity creation and then, when processing a special power, we get all the bullets in the scene and make them explode. Note: in some ECS a “flag” component is used for this purpose. The Property abstraction is really powerful, it can be implemented in any way, for example, an expression property like “my current health is my speed * 2”. We used that while prototyping. Some bad stuff: Execution speed wasn’t good, we had a lot of layers in the middle, a lot of reflection, send and receive messages (even for the update method), a lot of boxing and unboxing, etc. It worked ok in desktop but wasn’t a viable solution for mobile devices. The logic started to be distributed all around and it wasn’t easy to reuse, and we started to have tons of special cases, when we couldn’t reuse something we simply copy-pasted and changed it. There was a lot of code in the Components to get/set properties instead of just doing the important logic. Indirection in Properties code was powerful but we end up with stuff like this (and we didn’t like it since it was too much code overhead): e.getProperty("key").value = e.getProperty("key").value + 1. We didn’t manage to have a good data driven approach which is one of the best points of ECS. In order to have different behaviours we were forced to add both properties, components and even tags instead of just changing data. Note: Some of these points can be improved but we never worked on that. Even though we don’t think the achitecture is bad, it guided us to do stuff in a way we didn’t like it and didn’t scale. We feel that Unity does the same thing with its GameObjects and MonoBehaviours, all the examples in their documentation go in that direction. That was our first try to the ECS approach. In case you are interested, ComponentsEngine and all the games we did with it are on Github and even though they are probably not compiling, they could be used as reference. This post will continue with how we later transitioned to use a more pure approach with Artemis, when we were more dedicated to mobile games. References Evolve your hierarchy - Classic article about Entity Component System. PushButtonEngine - Flash Entity Component System we used as reference when developing our ComponentsEngine. Game architecture is different - A quick transformation from normal game architecture to ECS. Slick2D - The game library we were using during ComponentsEngine development.