Jekyll2022-07-12T01:12:42+01:00/Lea HayesWelcome to my personal domain where you can find my blog and take a look at some of the projects that I've worked on.Game jam with Phaser2017-10-05T00:00:00+01:002017-10-05T00:00:00+01:00/2017/10/05/game-jam-with-phaser<p>It has been a tough week. My dad passed away after having been ill with Crohn’s disease
for many years. He started to deteriorate quite rapidly recently. It was heart breaking
seeing him on his final days at the hospital.</p>
<p>I decided to have myself a little game jam. The planet is being showered by a mysterious
sentient goop that is taking the world by storm. Goop is very strongly attracted to other
goop and wants to take possession of all of the planet’s lifeforms.</p>
<p>I figured it would be fun try tryout <a href="phaser.io">Phaser</a>, a HTML5 based framework for creating canvas
and WebGL games, since a friend was talking about it recently and I’ve encountered it in
my web travels a few times.</p>
<p>The framework has been quite easy to use and is reasonably well documented. The only issue
that I encountered was that occasionally the screen would flip vertically for a single
frame whilst my transition was happening. After some poking around I found that the world
transforms were being inverted by the framework whilst capturing the display using a
render texture. With some trial-and-error experimentation I found that the problem could
be solved simply by calling <code class="highlighter-rouge">world.updateTransform</code> after rendering to the render texture.</p>
<p>The game is an endless runner where pre-defined chunks are chosen at random and then
cycled horizontally. At most there are only ever two chunks which are reused for the
duration of each game:</p>
<p><img src="/assets/blog/2017/10/05/cycling-chunks.png" alt="Illustration of cycling of chunks" /></p>
<p>I designed each of the chunks using the <a href="http://www.mapeditor.org/">Tiled</a> map editor which are then chosen from at
random when populating chunks as they are cycled. The pre-defined chunks are arranged into
sets so that easier ones are encountered early on and then more challanging ones are
introduced as the game progresses. Easier chunks are also removed from circulation as the
game becomes harder.</p>
<p>There are two simple rules that must be followed when designing chunks for this game to
avoid putting Goop into a situation where it cannot move through a wall. Each chunk must
start with a death in the lower-left corner. This prevents the following situation from
occurring between two chunks:</p>
<p><img src="/assets/blog/2017/10/05/chunk-design-pattern.png" alt="Chunk map design pattern" /></p>
<p>There are 5 regular tiles and then 4 marker tiles that are used to spawn interactive
actors. Here is what a chunk looks like in the <a href="http://www.mapeditor.org/">Tiled</a> map editor:</p>
<p><img src="/assets/blog/2017/10/05/chunk-map.png" alt="One of the chunk maps" /></p>
<p>I wrote a simple script using <a href="nodejs.org">Node.js</a> to combine the chunk map data files to reduce them
into a single HTTP request rather than one per chunk map.</p>
<p>I had quite a lot of fun designing the artwork for this little game. As usual I started
of using just placeholder blocks until the game played how I had imagined. I sketched out
how I wanted the background layers to look using <a href="https://procreate.art/">ProCreate</a> on the iPad Pro and then went
around the edges of my sketch in Photoshop using vectors to get a clean sharp look. The
sprites were made entirely in Photoshop using vectors.</p>
<p>The game can be played for free <a href="/">here</a>.</p>
<p><img src="/assets/blog/2017/10/05/goopy-spider.png" alt="Goopy spider" /></p>It has been a tough week. My dad passed away after having been ill with Crohn’s disease
for many years. He started to deteriorate quite rapidly recently. It was heart breaking
seeing him on his final days at the hospital.Building an interlinked Github wiki from markdown topics2017-09-30T00:00:00+01:002017-09-30T00:00:00+01:00/2017/09/30/building-an-interlinked-github-wiki-from-markdown-topics<p>I use markdown wherever possible since it is a very simple and clean syntax to work with
and is easy to read as-is. One of the areas that I’ve wanted to adopt markdown for a while
is for documentation but somehow without compromising on the high quality linking that I
have between topics.</p>
<p>With <a href="http://dita.xml.org/">DITA</a> topics are bound into the distributable materials using <a href="http://docs.oasis-open.org/dita/v1.2/os/spec/archSpec/dita_spec_intro_bookmap.html#dita_spec_intro_bookmap">book maps</a>. The book
map essentially adds structure to topic files and sets out topics that are somehow related
to one another. The DITA tooling can then use this information to automatically generate
all the good stuff like table of contents, breadcrumbs, next/previous page links, child
topic listings and related topic listings.</p>
<p>So it seemed somewhat logical to adopt a similar format for the markdown topic files;
except using YAML instead of XML. The same YAML book map could be used to render output
HTML pages using a template engine like <a href="https://mozilla.github.io/nunjucks/">nunjucks</a> if desired; but for the time being
outputting Github wiki style markdown is all that is needed.</p>
<p>Previously the DITA topics had URL friendly slug names to identify them. Since Github wiki
actually encodes the topic title into the filename it made sense to adopt the same
approach for naming the input topics. Whilst this naming convention has the disadvantage
that certain symbols cannot be used in titles, it ensures that topics are easy to find and
that the naming of source and output files is consistent.</p>
<p>I developed a CLI tool using node.js which parses a YAML encoded book map file to produce
linking between topics using Github wiki style links. The tool also converts the links of
embedded images from regular markdown syntax into the Github wiki syntax.</p>
<p>For anyone interested in using this tool, checkout its repository on Github:
<a href="https://github.com/rotorz/github-wiki-from-markdown-book">https://github.com/rotorz/github-wiki-from-markdown-book</a></p>
<h2 id="examples">Examples:</h2>
<h3 id="rotorzunity3d-tile-system">rotorz/unity3d-tile-system</h3>
<p><strong>Source:</strong> <a href="https://github.com/rotorz/unity3d-tile-system/tree/master/docs">https://github.com/rotorz/unity3d-tile-system/tree/master/docs</a><br />
<strong>Output:</strong> <a href="https://github.com/rotorz/unity3d-tile-system/wiki">https://github.com/rotorz/unity3d-tile-system/wiki</a></p>
<h3 id="rotorzunity3d-reorderable-list">rotorz/unity3d-reorderable-list</h3>
<p><strong>Source:</strong> <a href="https://github.com/rotorz/unity3d-reorderable-list/tree/master/docs">https://github.com/rotorz/unity3d-reorderable-list/tree/master/docs</a><br />
<strong>Output:</strong> <a href="https://github.com/rotorz/unity3d-reorderable-list/wiki">https://github.com/rotorz/unity3d-reorderable-list/wiki</a></p>I use markdown wherever possible since it is a very simple and clean syntax to work with
and is easy to read as-is. One of the areas that I’ve wanted to adopt markdown for a while
is for documentation but somehow without compromising on the high quality linking that I
have between topics.Get-text style localization in Unity2017-08-18T00:00:00+01:002017-08-18T00:00:00+01:00/2017/08/18/get-text-style-localization-in-unity<p>In past Unity projects I have used basic string table lookup to localize UI text using
carefully named keys. Whilst straightforward in terms of implementation this has a number
of downsides such as being unable to properly handle the plural forms of some languages;
not to mention the problem of having to come up with meaningful keys and locating strings
in source code.</p>
<p>With get-text the default language strings are used as the keys for localized text and
there is provision for dealing with multiple plural forms as well as providing extra
semantics such as context and proper names.</p>
<p>So why change now? Well, since I am in the process of releasing packages with open source
licenses I realize that it will be easier for anyone wanting to use or contribute to
maintain the software or create new localizations. The open source <a href="https://www.gnu.org/software/gettext/">gettext tooling</a> and
<a href="https://poedit.net/">POEdit</a> are fantastic tools to manage localizations.</p>
<p>I’ve created a simple wrapper library around an open source MIT-licensed <a href="https://github.com/neris/NGettext">NGettext</a>
implementation for C# (compatible with AOT platforms). It is up to user code as to how
language domains are structured and loaded. In my projects the language domains would be
initialized at the composition root and then injected into the various UI components.</p>
<p>For example,</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">labelNameField</span><span class="p">.</span><span class="n">text</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="n">lang</span><span class="p">.</span><span class="nf">ParticularText</span><span class="p">(</span><span class="s">"Input"</span><span class="p">,</span> <span class="s">"Name"</span><span class="p">);</span>
</code></pre></div></div>
<p>Language domains for editor extensions can be defined by creating a new class that extends
the <code class="highlighter-rouge">PackageLanguage<T></code> generic class:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">[DiscoverablePackageLanguage]</span>
<span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">MyPackageLang</span> <span class="p">:</span> <span class="n">PackageLanguage</span><span class="p"><</span><span class="n">MyPackageLang</span><span class="p">></span>
<span class="p">{</span>
<span class="k">public</span> <span class="nf">MyPackageLang</span><span class="p">()</span>
<span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="s">"@my-vendor-name/my-package"</span><span class="p">,</span> <span class="n">CultureInfo</span><span class="p">.</span><span class="nf">GetCultureInfo</span><span class="p">(</span><span class="s">"en-US"</span><span class="p">))</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="c1">// Custom functionality can be implemented here if required...</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Editor text can then be localized using the <code class="highlighter-rouge">MyPackageLang</code> class:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">GUILayout</span><span class="p">.</span><span class="nf">Label</span><span class="p">(</span><span class="n">MyPackageLang</span><span class="p">.</span><span class="nf">Text</span><span class="p">(</span><span class="s">"Create new instance using a template:"</span><span class="p">));</span>
<span class="n">prefab</span> <span class="p">=</span> <span class="n">GUILayout</span><span class="p">.</span><span class="nf">ObjectField</span><span class="p">(</span><span class="n">MyPackageLang</span><span class="p">.</span><span class="nf">ParticularText</span><span class="p">(</span><span class="s">"Property"</span><span class="p">,</span> <span class="s">"Prefab"</span><span class="p">),</span> <span class="n">prefab</span><span class="p">);</span>
</code></pre></div></div>
<p>Localizations are provided in the compiled .mo format which can be placed into the
package’s “Languages” folder “Plugins/Packages/@my-vendor-name/my-package/Languages” or
into the package’s data folder “Plugins/PackageData/@my-vendor-name/my-package/Languages”.</p>In past Unity projects I have used basic string table lookup to localize UI text using
carefully named keys. Whilst straightforward in terms of implementation this has a number
of downsides such as being unable to properly handle the plural forms of some languages;
not to mention the problem of having to come up with meaningful keys and locating strings
in source code.Installing npm packages into a Unity project2017-03-28T00:00:00+01:002017-03-28T00:00:00+01:00/2017/03/28/installing-npm-packages-into-a-unity-project<p>Installing npm packages that are enabled to work with the <a href="https://www.npmjs.com/package/unity3d-package-syncer">unity3d-package-syncer</a> tool is
a fairly straightforward process!</p>
<p>First of all your project will need to be initialized with a “package.json” file so that
npm can install, update and uninstall packages. With this in place you can install the
<a href="https://www.npmjs.com/package/unity3d-package-syncer">unity3d-package-syncer</a> tool which will help you to synchronize packages into your Unity
project’s “Assets” folder:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install <span class="nt">--save</span> unity3d-package-syncer
</code></pre></div></div>
<p>You will then need to ensure that you have an npm script inside your “package.json” file
that will trigger package synchronization:</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">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"my-unity-project"</span><span class="p">,</span><span class="w">
</span><span class="s2">"version"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1.0.0"</span><span class="p">,</span><span class="w">
</span><span class="s2">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span><span class="w">
</span><span class="s2">"scripts"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="s2">"sync"</span><span class="p">:</span><span class="w"> </span><span class="s2">"unity3d--sync"</span><span class="w">
</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">"unity3d-package-syncer"</span><span class="p">:</span><span class="w"> </span><span class="s2">"^1.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>Finally you can install any npm packages that you want; both those that will synchronize
with your Unity project and those that are required for any node based automation. Your
project’s “sync” script (as defined in your “package.json” file) can then be invoked:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install <span class="nt">--save</span> unity3d-package-example
npm run sync
</code></pre></div></div>
<p>The output of this command should look something like this:</p>
<p><img src="/assets/blog/2017/03/28/install-package.gif" alt="npm run sync output" /></p>
<p>If we look inside the project’s “Assets” folder we should then see something like this:</p>
<p><img src="/assets/blog/2017/03/28/unity-project.png" alt="Unity project with 'unity3d-package-example' package installed" /></p>
<p>If you wanted to save a few keystrokes then you can install multiple packages into your
Unity project and synchronize any <a href="https://www.npmjs.com/package/unity3d-package-syncer">unity3d-package-syncer</a>-enabled packages with a single
command line. For instance, the following command would install and synchronize 3 packages
‘foo’, ‘bar’ and ‘baz’.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install <span class="nt">-s</span> foo bar baz <span class="o">&&</span> npm run sync
</code></pre></div></div>
<p>And of course, you can install <strong>any</strong> regular node packages that you want to. For
instance, if you needed to do some sort of template processing then you might choose to
install the marvelous <a href="https://mozilla.github.io/nunjucks/">nunjucks</a> package.</p>Installing npm packages that are enabled to work with the unity3d-package-syncer tool is
a fairly straightforward process!Creating an npm package with DLLs instead of scripts2017-03-27T00:00:00+01:002017-03-27T00:00:00+01:00/2017/03/27/creating-an-npm-package-with-dlls-instead-of-scripts<p>The overall process is essentially the same as before except source files should be placed
into a folder somewhere outside of the “assets” folder. A workflow can then be added using
an npm script, a makefile, a shell script, a batch file, a gulp file, or whatever type of
automation system that you prefer to use to initiate the building of the DLLs.</p>
<p>Built DLLs can then be copied into the “assets” folder structure so that they will be
properly synchronized into Unity projects. This does mean that built DLLs should be
committed to the package’s repository.</p>
<p>For instance, your package directory structure might look something like this (if using a
similar directory structure to what uGUI uses):</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>your-package/
|-- assets/
| |-- Editor/
| | |-- MyEditorClassLibrary.dll # Editor DLL
| | |-- MyEditorClassLibrary.dll.meta # EditorWindow's, etc.
| |-- Standalone/
| | |-- MyRuntimeClassLibrary.dll # Standalone DLL with no editor goop!
| | |-- MyRuntimeClassLibrary.dll.meta # MonoBehaviour's etc.
| |-- Editor.meta
| |-- Source.meta
| |-- MyRuntimeClassLibrary.dll # Runtime DLL with editor-specifics.
| |-- MyRuntimeClassLibrary.dll.meta # Like standalone with OnDrawGizmos.
|-- source/
| |-- MyRuntimeClassLibrary/
| | |-- Properties/
| | | |-- AssemblyInfo.cs
| | |-- MyBehaviourClass.cs
| | |-- MyRuntimeClassLibrary.csproj
| |-- MyEditorClassLibrary/
| | |-- Properties/
| | | |-- AssemblyInfo.cs
| | |-- MyBehaviourClassEditor.cs
| | |-- MyEditorClassLibrary.csproj
| |-- MySolution.sln
|-- Makefile
|-- package.json
|-- etc.
</code></pre></div></div>
<blockquote>
<p><strong>Note</strong> - It’s still important to include .meta files for the DLLs since this helps
Unity to maintain links between scripts and assets.</p>
</blockquote>
<p>For those interested in using DLLs to improve Unity’s “Plugins” directory build iteration
times; I’ve heard rumors that there may be a better solution coming soon!</p>The overall process is essentially the same as before except source files should be placed
into a folder somewhere outside of the “assets” folder. A workflow can then be added using
an npm script, a makefile, a shell script, a batch file, a gulp file, or whatever type of
automation system that you prefer to use to initiate the building of the DLLs.Structuring an npm package for Unity2017-03-26T00:00:00+00:002017-03-26T00:00:00+00:00/2017/03/26/structuring-an-npm-package-for-unity<p>As with all npm packages; each package requires a “package.json” file to identify the
package and any dependencies that it may have.</p>
<p>The <a href="https://www.npmjs.com/package/unity3d-package-syncer">unity3d-package-syncer</a> tool will automatically synchronize packages that have the
“unity3d-package” keyword in the “keywords” section of the “package.json” file.</p>
<p>The directory structure of the package is entirely up to you; however any assets, scripts
or DLLs that are to be synchronized into Unity projects must be placed inside the “assets”
folder of your npm package. There should be a “README.md” and “LICENSE” file at the root
of the package since these will also be synchronized into Unity projects.</p>
<p>The minimal directory structure would look something like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>my-package/
|-- assets/
| |-- Editor/
| | |- ExampleBehaviourEditor.cs
| | |- ExampleBehaviourEditor.cs.meta
| |-- Source/
| | |- ExampleBehaviour.cs
| | |- ExampleBehaviour.cs.meta
| |-- Editor.meta
| |-- Source.meta
|-- README.md
|-- LICENSE
|-- package.json
</code></pre></div></div>
<blockquote>
<p><strong>Note</strong> - It’s important to include .meta files for source files since this helps Unity
to maintain links between scripts and assets.</p>
</blockquote>
<p>A minimal “package.json” file would look something like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>{
"name": "my-package",
...
}
</code></pre></div></div>As with all npm packages; each package requires a “package.json” file to identify the
package and any dependencies that it may have.Package management for Unity projects2017-03-20T00:00:00+00:002017-03-20T00:00:00+00:00/2017/03/20/package-management-for-unity-projects<p>As many of us have found; when working with even small projects you end up having many
variations of reusable source code scattered across the projects. In some situations you
will even find yourself having a project that has many versions of the exact same JSON
library since each asset bundles it within a unique (or sometimes clashing) namespace.</p>
<p>Clearly this is a problem that needs to be addressed! The obvious solution is to utilize
a package manager so that common dependencies can be shared. A package manager also makes
it easier to update to newer versions of a package whilst at the same time allowing you
to use a specific version of a package when needed.</p>
<p>So if you need to make an important change to a package that is common to a number of your
projects, you can make that change centrally and then simply rebuild each of the projects
using the latest version of that package. Another nice advantage is that this encourages
you to manage each reusable unit within their own repositories.</p>
<p><img src="/assets/blog/2017/03/20/projects-and-packages.png" alt="Projects and Packages" /></p>
<p>At the time of writing, Unity doesn’t actually have its own package manager; and to make
matters worse, none of the existing package managers are ideal. Having evaluated a few
options I found that <a href="https://www.nuget.org/">NuGet</a> and npm were the most viable however each with their own
shortcomings.</p>
<p><a href="https://www.nuget.org/">NuGet</a> is quite complex to setup for this use case and revolves around having compiled
assemblies. One of the things that I wanted to move towards, especially for open source
projects, was to switch over to source distribution rather than DLL distribution since it
is far easier to debug problems.</p>
<p>npm on the other hand is rather straightforward to setup and provides all of the features
necessary to manage packages and their dependencies. In fact npm5 can even install npm
packages directly from a git repository using <a href="semver.org">semver</a> encoded tags. This is nice because
it means that we don’t have to clutter the npm registry with packages that don’t really
fit into the regular node.js ecosystem. However, npm puts all packages into a hard-coded
“node_modules” directory.</p>
<p>At first I raised a question in the npm issue tracker which asked about a feature whereby
a custom directory name could be used for installed packages. I did some searching and
found that <a href="https://github.com/shadowmint/">shadowmint</a> had been using npm for Unity focused packages (see <a href="https://github.com/shadowmint/unity-package-template">unity-package-template</a>)
where each package effectively installs itself into the Unity project. Whilst this works I
felt uncomfortable with potentially having quite inconsistent package syncing logic across
many packages. Not to mention that the packages become exclusive to Unity projects (when
UE4 has C# support it’s highly plausible that such packages could work with both).</p>
<p>So I did some experimentation and found a couple of different ways to sync npm packages
into the Unity project. I found that it was fairly straightforward to create a package
whose soul purpose is to sync such packages <a href="https://www.npmjs.com/package/unity3d-package-syncer">unity3d-package-syncer</a>. This can then be
run any time packages are installed, updated or uninstalled.</p>
<p>I soon discovered that actually I didn’t want to synchronize the entire contents of the
package folder into the Unity project since the folder would often contain javascript
source files that Unity would misinterpret as UnityScript. In addition packages could
contain various things that are only relevant to the development of the package such as
makefiles, unit tests, etc. This rendered the issue of npm forcing you to use the
“node_modules” directory a moot point since you actually don’t want to install directly
into the Unity project’s “Assets” folder.</p>
<p>I chose to synchronize packages into the “Plugins” directory of the Unity project because
this avoids the frequent recompilation of package scripts each time user scripts are
modified since Unity places them into different assemblies. The “Plugins” directory also
allows packages to declare internals without exposing them to project specific scripts.</p>
<p>This doesn’t prevent you from constructing packages where DLLs are compiled from sources
that are then synchronized into the Unity projects. It is straightforward to setup such
a workflow.</p>
<h2 id="interesting-reads">Interesting Reads</h2>
<ul>
<li>
<p><a href="https://www.reddit.com/r/Unity3D/comments/409ymg/need_a_real_package_manager_for_unity_try_npm/">Need a real package manager for Unity? Try npm</a></p>
</li>
<li>
<p><a href="http://www.what-could-possibly-go-wrong.com/unity-and-nuget/">Unity and NuGet + JSON.net</a></p>
</li>
<li>
<p><a href="https://github.com/modesttree/Projeny">modesttree/Projeny</a></p>
</li>
</ul>As many of us have found; when working with even small projects you end up having many
variations of reusable source code scattered across the projects. In some situations you
will even find yourself having a project that has many versions of the exact same JSON
library since each asset bundles it within a unique (or sometimes clashing) namespace.Managing states with a lightweight FSM2017-01-10T00:00:00+00:002017-01-10T00:00:00+00:00/2017/01/10/managing-states-with-a-lightweight-fsm<p>Games will typically have a number of states and sub-states and there are endless ways in
which these states can be defined from using a switch statement, to using delegates, state
pattern, coroutines, scenes, animation events, etc. Each approach brings its own
advantages and disadvantages and some are better suited depending on the use case.</p>
<p><img src="/assets/blog/2017/01/10/examples.png" alt="Examples of state machines" /></p>
<p>One thing that I will say is that relying on animation events can be quite unpredictable
since sometimes they do not trigger. In a client project we found that Unity’s animation
system skips over animation events when there is a spike in the framerate. This was really
bad because randomly it would not advance to the next stage.</p>
<p>Unity actually includes a state machine called Mechanim which was designed primarily to
manage the states of animations although can be used as a general purpose state machine by
implementing state behavior classes. Despite being a powerful system for animation it
seems to lack some of the flexibility and simplicity that I require from a general purpose
state machine.</p>
<p>The design of my general purpose state machine has evolved over past projects. Each state
machine instance is started as a long running coroutine which is extremely useful when
defining procedural animation and time-based events. It works very well with the <a href="http://dotween.demigiant.com/">DOTween</a>
tweening library that I use. Transitions can optionally be specified to manage the
transition from one state to another; this is useful when adding fancy screen transitions.</p>
<p>Coroutine performance has gotten a lot better in recent releases of Unity. Obviously they
still come at a relatively small cost but they are a useful tool and the advantages of
using them for my use cases far outweigh that cost.</p>
<p>My lightweight fsm implementation will work in any regular .NET / Mono application since
it makes minimal usage of the Unity API. The only Unity-specific class is the
<code class="highlighter-rouge">StateComponent</code> base class which is completely ignored when used outside of the Unity
engine.</p>
<p><img src="/assets/blog/2017/01/10/overview-fsm.png" alt="Projects and Packages" /></p>
<p>State transitions can be initiated by specifying either the target <code class="highlighter-rouge">IState</code> or the name of
the target state. For this reason it is useful to be able to resolve the <code class="highlighter-rouge">IState</code> of a
given name even allowing for more complex state resolution logic if desired. For example,
a more complex state resolver could select between multiple “TitleMenu” states based upon
whether the game has been completed or some in-app-purchase has been purchased.</p>
<p>Likewise it is useful to be able to resolve the transition that should be used when
transitioning from one state to another. A transition is an optional object that can
sequence the transition from the current state to the next. This can be useful when
adding fancy transitions between screens.</p>
<p>My <code class="highlighter-rouge">StateMachine<TStateName></code> class can be constructed by providing a state resolver and
a transition resolver or alternatively a state graph. A state graph is simply an object
that provides both state and transition resolution logic. A basic <code class="highlighter-rouge">StateGraph<TStateName></code>
implementation is provided which allows states and transitions to be registered but
obviously it is possible to use an entirely custom implementation.</p>
<p><img src="/assets/blog/2017/01/10/overview-graph.png" alt="Projects and Packages" /></p>
<p>In my projects I use this state machine library in various different ways. I have two base
classes <code class="highlighter-rouge">State</code> and <code class="highlighter-rouge">StateComponent</code> which can be used to implement states as POCOs or
as components that can be attached to game objects.</p>
<p>I also made a reusable <code class="highlighter-rouge">EmptyState</code> sealed class which is a singleton that does nothing.
This state can be used when states have no special functionality or when blocking out new
state machines.</p>
<p><img src="/assets/blog/2017/01/10/overview-state.png" alt="Projects and Packages" /></p>
<p>Each state of a <code class="highlighter-rouge">IStateMachine<TStateName></code> is identified using a name that is defined
using an enum. This is then used as the generic type parameter when constructing a state
machine.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">enum</span> <span class="n">GameStateName</span>
<span class="p">{</span>
<span class="n">Intro</span><span class="p">,</span>
<span class="n">TitleMenu</span><span class="p">,</span>
<span class="n">Playing</span><span class="p">,</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I like to expose each state to the world by providing a context object; but this is
entirely optional. A context can optionally implement the <code class="highlighter-rouge">IStateContext<GameStateName></code>
interface which provides some useful methods to transition to the next state. Additional
transition logic can of course be added to the context where needed (such as to exit to
the desktop).</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">interface</span> <span class="nc">IGameStateContext</span> <span class="p">:</span> <span class="n">IStateContext</span><span class="p"><</span><span class="n">GameStateName</span><span class="p">></span>
<span class="p">{</span>
<span class="k">void</span> <span class="nf">ExitGame</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The context object can be provided to the state in a number of ways including constructor
injection, property injection or via some sort of <code class="highlighter-rouge">Initialize</code> method. I like to put this
common logic into an abstract base class:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">GameState</span> <span class="p">:</span> <span class="n">State</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">IGameStateContext</span> <span class="n">Context</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="p">}</span>
</code></pre></div></div>
<p>In the following example I have a <code class="highlighter-rouge">GameController</code> which is essentially just a navigation
controller that navigates the main states of the game. Each of these states can define
sub-states if they need to be broken down further. For example, depending on the type of
game the “Playing” state could be broken down into various sub-states such as “Prepare”,
“Standard” and “GameOver”.</p>
<p>With this particular example each game state is essentially a presenter which populates
the properties and observes the events of an associated view (essentially the MVP design
pattern). I use dependency injection to instantiate the object hierarchy but any object
creation method can of course be used.</p>
<p>In this case the <code class="highlighter-rouge">GameController</code> acts as the context of its states. If preferred the
context can be encapsulated by implementing a private <code class="highlighter-rouge">GameController.Context</code> class;
although I don’t feel that the extra level of indirection adds any real value here.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">GameController</span> <span class="p">:</span> <span class="n">IGameStateContext</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">StateMachine</span><span class="p"><</span><span class="n">GameStateName</span><span class="p">></span> <span class="n">stateMachine</span><span class="p">;</span>
<span class="c1">// Dependencies are injected into the constructor.</span>
<span class="k">public</span> <span class="nf">GameController</span><span class="p">(</span>
<span class="n">IntroGameState</span> <span class="n">introState</span><span class="p">,</span>
<span class="n">TitleMenuGameState</span> <span class="n">titleMenuState</span><span class="p">,</span>
<span class="n">PlayingGameState</span> <span class="n">playingState</span>
<span class="p">)</span> <span class="p">{</span>
<span class="c1">// Assign context to each of the states.</span>
<span class="n">introState</span><span class="p">.</span><span class="n">Context</span> <span class="p">=</span> <span class="k">this</span><span class="p">;</span>
<span class="n">titleMenuState</span><span class="p">.</span><span class="n">Context</span> <span class="p">=</span> <span class="k">this</span><span class="p">;</span>
<span class="n">playingState</span><span class="p">.</span><span class="n">Context</span> <span class="p">=</span> <span class="k">this</span><span class="p">;</span>
<span class="c1">// Associate each state name with their instances.</span>
<span class="kt">var</span> <span class="n">graph</span> <span class="p">=</span> <span class="k">new</span> <span class="n">StateGraph</span><span class="p"><</span><span class="n">GameStateName</span><span class="p">>();</span>
<span class="n">graph</span><span class="p">.</span><span class="nf">RegisterState</span><span class="p">(</span><span class="n">GameStateName</span><span class="p">.</span><span class="n">Intro</span><span class="p">,</span> <span class="n">introState</span><span class="p">);</span>
<span class="n">graph</span><span class="p">.</span><span class="nf">RegisterState</span><span class="p">(</span><span class="n">GameStateName</span><span class="p">.</span><span class="n">TitleMenu</span><span class="p">,</span> <span class="n">titleMenuState</span><span class="p">);</span>
<span class="n">graph</span><span class="p">.</span><span class="nf">RegisterState</span><span class="p">(</span><span class="n">GameStateName</span><span class="p">.</span><span class="n">Playing</span><span class="p">,</span> <span class="n">playingState</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">stateMachine</span> <span class="p">=</span> <span class="k">new</span> <span class="n">StateMachine</span><span class="p"><</span><span class="n">GameStateName</span><span class="p">>(</span><span class="n">graph</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="n">IEnumerator</span> <span class="nf">Execute</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Execute the state machine starting with the intro state.</span>
<span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="n">stateMachine</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="n">GameStateName</span><span class="p">.</span><span class="n">Intro</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">ExitGame</span><span class="p">()</span>
<span class="p">{</span>
<span class="n">Application</span><span class="p">.</span><span class="nf">Quit</span><span class="p">();</span>
<span class="p">}</span>
<span class="c1">// A little boilerplate to allow states to transition between one another</span>
<span class="c1">// since `IGameStateContext` implements the `IStateContext<GameStateName>`.</span>
<span class="k">void</span> <span class="n">IStateContext</span><span class="p"><</span><span class="n">GameStateName</span><span class="p">>.</span><span class="nf">ExitTo</span><span class="p">(</span><span class="n">GameStateName</span> <span class="n">stateName</span><span class="p">,</span> <span class="n">IState</span> <span class="n">state</span><span class="p">,</span> <span class="n">IStateTransition</span> <span class="n">transition</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">stateMachine</span><span class="p">.</span><span class="nf">ExitTo</span><span class="p">(</span><span class="n">stateName</span><span class="p">,</span> <span class="n">state</span><span class="p">,</span> <span class="n">transition</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">void</span> <span class="n">IStateContext</span><span class="p"><</span><span class="n">GameStateName</span><span class="p">>.</span><span class="nf">ExitTo</span><span class="p">(</span><span class="n">GameStateName</span> <span class="n">stateName</span><span class="p">,</span> <span class="n">IState</span> <span class="n">state</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">stateMachine</span><span class="p">.</span><span class="nf">ExitTo</span><span class="p">(</span><span class="n">stateName</span><span class="p">,</span> <span class="n">state</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">void</span> <span class="n">IStateContext</span><span class="p"><</span><span class="n">GameStateName</span><span class="p">>.</span><span class="nf">ExitTo</span><span class="p">(</span><span class="n">GameStateName</span> <span class="n">stateName</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">stateMachine</span><span class="p">.</span><span class="nf">ExitTo</span><span class="p">(</span><span class="n">stateName</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Transitions can be explicitly defined on the state graph using <code class="highlighter-rouge">graph.RegisterTransition</code>
when custom transition behavior is desired. With this design it is not necessary to define
which transitions are legal on the graph since each state is responsible for selecting the
state that it would like to exit to. However, state transition validation can easily be
added to a custom state machine implementation if desired.</p>
<p>Here is a very basic “Intro” game state which waits for two seconds before advancing to
the “TitleMenu”. The associated view is shown upon entering the state and then hidden upon
exiting to the next state.</p>
<p>For small games I like to define a “MenuSystem” prefab that contains all of the menu
panels and huds. The root-most object has a “MenuSystem” component that implements a
<code class="highlighter-rouge">IMenuSystem</code> interface providing access to each of the views.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">IntroGameState</span> <span class="p">:</span> <span class="n">GameState</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">IIntroView</span> <span class="n">view</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">IntroGameState</span><span class="p">(</span>
<span class="n">IMenuSystem</span> <span class="n">menuSystem</span>
<span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span> <span class="p">=</span> <span class="n">menuSystem</span><span class="p">.</span><span class="n">IntroView</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnEntering</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Show view upon entering state.</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="nf">Show</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="n">IEnumerator</span> <span class="nf">OnExecute</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Wait for a couple of seconds and then exit to the title menu.</span>
<span class="k">yield</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">WaitForSeconds</span><span class="p">(</span><span class="m">2f</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="nf">ExitTo</span><span class="p">(</span><span class="n">GameStateName</span><span class="p">.</span><span class="n">TitleMenu</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnExiting</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Hide view upon exiting state.</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="nf">Hide</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In the following situation the game state subscribes to a couple of actions from its
view’s interface so that it can start a new game or exit to the desktop. It is useful to
subscribe to these events when entering the state and then to unsubscribe again when
exiting the state so that events are only handled whilst the state is active.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">TitleMenuGameState</span> <span class="p">:</span> <span class="n">GameState</span>
<span class="p">{</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">ITitleMenuView</span> <span class="n">view</span><span class="p">;</span>
<span class="k">private</span> <span class="k">readonly</span> <span class="n">IPlayerProfile</span> <span class="n">playerProfile</span><span class="p">;</span>
<span class="k">public</span> <span class="nf">TitleMenuGameState</span><span class="p">(</span>
<span class="n">IMenuSystem</span> <span class="n">menuSystem</span><span class="p">,</span>
<span class="n">IPlayerProfile</span> <span class="n">playerProfile</span>
<span class="p">)</span> <span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span> <span class="p">=</span> <span class="n">menuSystem</span><span class="p">.</span><span class="n">TitleMenuView</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="n">playerProfile</span> <span class="p">=</span> <span class="n">playerProfile</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnEntering</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Initialize view from player profile.</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="n">BestScore</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="n">playerProfile</span><span class="p">.</span><span class="n">BestScore</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="n">PreviousScore</span> <span class="p">=</span> <span class="k">this</span><span class="p">.</span><span class="n">playerProfile</span><span class="p">.</span><span class="n">PreviousScore</span><span class="p">;</span>
<span class="c1">// Subscribe to the view's input events.</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="n">PlayGameAction</span> <span class="p">+=</span> <span class="k">this</span><span class="p">.</span><span class="n">View_PlayGameAction</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="n">ExitGameAction</span> <span class="p">+=</span> <span class="k">this</span><span class="p">.</span><span class="n">View_ExitGameAction</span><span class="p">;</span>
<span class="c1">// Show the title menu view.</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="nf">Show</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">OnExiting</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Be sure to unsubscribe from the view's events again:</span>
<span class="c1">// - Ignore further input (i.e. button click during hide animation).</span>
<span class="c1">// - The view might be reused.</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="n">PlayGameAction</span> <span class="p">-=</span> <span class="k">this</span><span class="p">.</span><span class="n">View_PlayGameAction</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="n">ExitGameAction</span> <span class="p">-=</span> <span class="k">this</span><span class="p">.</span><span class="n">View_ExitGameAction</span><span class="p">;</span>
<span class="c1">// Hide the title menu view again.</span>
<span class="k">this</span><span class="p">.</span><span class="n">view</span><span class="p">.</span><span class="nf">Hide</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">View_PlayGameAction</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Exit to the playing state when the view indicates that the player</span>
<span class="c1">// would like to play a new game; for instance, by clicking the</span>
<span class="c1">// "Play Game" button.</span>
<span class="k">this</span><span class="p">.</span><span class="n">Context</span><span class="p">.</span><span class="nf">ExitTo</span><span class="p">(</span><span class="n">GameStateName</span><span class="p">.</span><span class="n">Playing</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">View_ExitGameAction</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Exit the game when the view indicates that the player would like</span>
<span class="c1">// to; for instance, by clicking the "Exit Game" button or by pressing</span>
<span class="c1">// the escape key.</span>
<span class="k">this</span><span class="p">.</span><span class="n">Context</span><span class="p">.</span><span class="nf">ExitGame</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>In the above examples I demonstrated how I use a state machine to manage high level game
states; but the same mechanism can also be used to manage states elsewhere such as for an
actor.</p>
<p>In the following example the spider actor has four states that are implemented as
components so that they can be attached to the actor game object (or on nested game
objects). The states are then wired up using the inspector. This is a powerful mechanism
because it allows for a “SuperEvilSpider” prefab to be created that has, for example, an
alternative extra mean “Attack” state.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">SpiderActor</span> <span class="p">:</span> <span class="n">MonoBehaviour</span><span class="p">,</span> <span class="n">ISpiderStateContext</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">SpiderState</span> <span class="n">idleState</span> <span class="p">=</span> <span class="k">null</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">SpiderState</span> <span class="n">wanderState</span> <span class="p">=</span> <span class="k">null</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">SpiderState</span> <span class="n">attackState</span> <span class="p">=</span> <span class="k">null</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">SpiderState</span> <span class="n">deathState</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
<span class="k">private</span> <span class="n">StateMachine</span><span class="p"><</span><span class="n">SpiderStateName</span><span class="p">></span> <span class="n">stateMachine</span><span class="p">;</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">Awake</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InitializeStates</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">ExecuteStateMachine</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InitializeStates</span><span class="p">()</span>
<span class="p">{</span>
<span class="c1">// Assert that components were specified for each of the states.</span>
<span class="n">Assert</span><span class="p">.</span><span class="nf">IsNotNull</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">idleState</span><span class="p">);</span>
<span class="n">Assert</span><span class="p">.</span><span class="nf">IsNotNull</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">wanderState</span><span class="p">);</span>
<span class="n">Assert</span><span class="p">.</span><span class="nf">IsNotNull</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">attackState</span><span class="p">);</span>
<span class="n">Assert</span><span class="p">.</span><span class="nf">IsNotNull</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">deathState</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">graph</span> <span class="p">=</span> <span class="k">new</span> <span class="n">StateGraph</span><span class="p"><</span><span class="n">SpiderStateName</span><span class="p">>();</span>
<span class="n">graph</span><span class="p">.</span><span class="nf">RegisterState</span><span class="p">(</span><span class="n">SpiderStateName</span><span class="p">.</span><span class="n">Idle</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">idleState</span><span class="p">);</span>
<span class="n">graph</span><span class="p">.</span><span class="nf">RegisterState</span><span class="p">(</span><span class="n">SpiderStateName</span><span class="p">.</span><span class="n">Wander</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">wanderState</span><span class="p">);</span>
<span class="n">graph</span><span class="p">.</span><span class="nf">RegisterState</span><span class="p">(</span><span class="n">SpiderStateName</span><span class="p">.</span><span class="n">Attack</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">attackState</span><span class="p">);</span>
<span class="n">graph</span><span class="p">.</span><span class="nf">RegisterState</span><span class="p">(</span><span class="n">SpiderStateName</span><span class="p">.</span><span class="n">Death</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">deathState</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">stateMachine</span> <span class="p">=</span> <span class="k">new</span> <span class="n">StateMachine</span><span class="p"><</span><span class="n">SpiderStateName</span><span class="p">>(</span><span class="n">graph</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">idleState</span><span class="p">.</span><span class="nf">Initialize</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">wanderState</span><span class="p">.</span><span class="nf">Initialize</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">attackState</span><span class="p">.</span><span class="nf">Initialize</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">deathState</span><span class="p">.</span><span class="nf">Initialize</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">ExecuteStateMachine</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">StartCoroutine</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">stateMachine</span><span class="p">.</span><span class="nf">Execute</span><span class="p">(</span><span class="n">SpiderStateName</span><span class="p">.</span><span class="n">Idle</span><span class="p">));</span>
<span class="p">}</span>
<span class="c1">//!TODO: Implement something interesting!</span>
<span class="p">}</span>
</code></pre></div></div>
<p>For this example I chose to use an <code class="highlighter-rouge">Initialize</code> method to initialize the actor with its
context and allowing it to perform additional initialization logic using that context.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">SpiderState</span> <span class="p">:</span> <span class="n">StateComponent</span>
<span class="p">{</span>
<span class="k">public</span> <span class="n">ISpiderStateContext</span> <span class="n">Context</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Initialize</span><span class="p">(</span><span class="n">ISpiderStateContext</span> <span class="n">context</span><span class="p">)</span>
<span class="p">{</span>
<span class="n">Assert</span><span class="p">.</span><span class="nf">IsNull</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">Context</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">Context</span> <span class="p">=</span> <span class="n">context</span><span class="p">;</span>
<span class="k">this</span><span class="p">.</span><span class="nf">OnInitialize</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">protected</span> <span class="k">virtual</span> <span class="k">void</span> <span class="nf">OnInitialize</span><span class="p">()</span>
<span class="p">{</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Each spider state is then just an implementation of <code class="highlighter-rouge">SpiderState</code>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">SpiderState_Attack</span> <span class="p">:</span> <span class="n">SpiderState</span>
<span class="p">{</span>
<span class="c1">//!TODO: Implement something interesting!</span>
<span class="p">}</span>
<span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">SpiderState_ExtraMeanAttack</span> <span class="p">:</span> <span class="n">SpiderState</span>
<span class="p">{</span>
<span class="c1">//!TODO: Implement something interesting!</span>
<span class="p">}</span>
</code></pre></div></div>Games will typically have a number of states and sub-states and there are endless ways in
which these states can be defined from using a switch statement, to using delegates, state
pattern, coroutines, scenes, animation events, etc. Each approach brings its own
advantages and disadvantages and some are better suited depending on the use case.Tweening with DOTween2017-01-06T00:00:00+00:002017-01-06T00:00:00+00:00/2017/01/06/tweening-with-dotween<p>There are several really good tweening libraries for Unity although I must say <a href="http://dotween.demigiant.com/">DOTween</a>
is my favorite since it has a wealth of features and performs well even on mobile. DOTween
is open source although there is a <a href="https://assetstore.unity.com/packages/tools/visual-scripting/dotween-pro-32416">DOTween Pro</a> version which includes extra features
such as visual editors but most importantly allows you to show some support to the
fantastic developer of this asset.</p>
<p>DOTween augments various types with extension methods making it easy to tween a large
variety of properties. The available tweening methods are grouped together in the
IntelliSense popup since they all begin with the prefix “DO”. DOTween provides a fluid
style API which I feel provides a clean way of defining animations.</p>
<p>For example, an object can be transformed on it’s Y-axis with:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">enemy</span><span class="p">.</span><span class="n">transform</span>
<span class="p">.</span><span class="nf">DOMoveY</span><span class="p">(</span><span class="n">targetY</span><span class="p">,</span> <span class="m">0.8f</span><span class="p">)</span>
<span class="p">.</span><span class="nf">SetEase</span><span class="p">(</span><span class="n">Ease</span><span class="p">.</span><span class="n">OutQuint</span><span class="p">);</span>
</code></pre></div></div>
<p>DOTween offers a lot of control over how the tweening will be processed; for instance, you
can pick between absolute and relative transformations. DOTween provides a rich selection
of easing functions; I find the <a href="http://easings.net">http://easings.net</a> website useful for previewing how
each of the easing functions will behave.</p>
<p>One of my favorite features of DOTween is it’s sequences feature which allows you to
define a sequence of tweens which can occur in parallel or in series. Sequences are
composed from a number of tweens, intervals, callbacks, etc. This allows you to compose
complex animations but interestingly can also be used to schedule tasks without having to
manage them manually:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">DOTween</span><span class="p">.</span><span class="nf">Sequence</span><span class="p">()</span>
<span class="p">.</span><span class="nf">AppendInterval</span><span class="p">(</span><span class="n">delayInSeconds</span><span class="p">)</span>
<span class="p">.</span><span class="nf">AppendCallback</span><span class="p">(()</span> <span class="p">=></span> <span class="p">{</span>
<span class="c1">// do something...</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Since sequences can include callbacks it is possible to initiate a sequence of tweens
followed by callbacks to perform any sort of logic including cleanup or state transitions.
Consider an example where a projectile collides with an explosive barrel; a sequence of
actions can occur:</p>
<ol>
<li>Spawn explosion special effect; such as a particle system.</li>
<li>Start animating the barrel breaking down into fragments.</li>
<li>Despawn the explosion special effect.</li>
</ol>
<p>For example,</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Transform</span> <span class="n">effectInstance</span> <span class="p">=</span> <span class="n">prefabPool</span><span class="p">.</span><span class="nf">Spawn</span><span class="p">(</span><span class="n">explosionEffectPrefab</span><span class="p">.</span><span class="n">transform</span><span class="p">);</span>
<span class="n">effectInstance</span><span class="p">.</span><span class="n">position</span> <span class="p">=</span> <span class="n">barrelGameObject</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">DOTween</span><span class="p">.</span><span class="nf">Sequence</span><span class="p">()</span>
<span class="p">.</span><span class="nf">SetId</span><span class="p">(</span><span class="n">barrelGameObject</span><span class="p">)</span>
<span class="p">.</span><span class="nf">Append</span><span class="p">(</span>
<span class="n">barrelGameObject</span><span class="p">.</span><span class="n">transform</span>
<span class="p">.</span><span class="nf">DOScale</span><span class="p">(</span><span class="m">0f</span><span class="p">,</span> <span class="n">shrinkDurationInSeconds</span><span class="p">)</span>
<span class="p">.</span><span class="nf">SetEase</span><span class="p">(</span><span class="n">Ease</span><span class="p">.</span><span class="n">InQuad</span><span class="p">)</span>
<span class="p">)</span>
<span class="p">.</span><span class="nf">AppendInterval</span><span class="p">(</span><span class="n">delayInSeconds</span><span class="p">)</span>
<span class="p">.</span><span class="nf">OnKill</span><span class="p">(()</span> <span class="p">=></span> <span class="p">{</span>
<span class="n">prefabPool</span><span class="p">.</span><span class="nf">Despawn</span><span class="p">(</span><span class="n">effectInstance</span><span class="p">);</span>
<span class="n">prefabPool</span><span class="p">.</span><span class="nf">Despawn</span><span class="p">(</span><span class="n">barrelGameObject</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<p>When starting a tween any value can be provided as an identifier for that tween. I find it
useful to provide an identifier of the owning object so that the tween can be canceled
if the object is destroyed before the tween is completed with <code class="highlighter-rouge">DOTween.Kill(id)</code>.</p>
<p>DOTween will invoke the <code class="highlighter-rouge">OnKill</code> callback when the tween either completes or when it is
killed prematurely. This is a useful place to cleanup unwanted objects such as a temporary
particle system special effect.</p>
<p>DOTween also works really well with Unity’s coroutine support; it provides methods which
return a <code class="highlighter-rouge">YieldInstruction</code> which can be yielded by a coroutine:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">override</span> <span class="n">IEnumerator</span> <span class="nf">DestroyCoroutine</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">yield</span> <span class="k">return</span> <span class="k">this</span><span class="p">.</span><span class="n">transform</span>
<span class="p">.</span><span class="nf">DOScale</span><span class="p">(</span><span class="m">0f</span><span class="p">,</span> <span class="k">this</span><span class="p">.</span><span class="n">durationInSeconds</span><span class="p">)</span>
<span class="p">.</span><span class="nf">SetEase</span><span class="p">(</span><span class="n">Ease</span><span class="p">.</span><span class="n">OutBack</span><span class="p">)</span>
<span class="p">.</span><span class="nf">WaitForCompletion</span><span class="p">();</span>
<span class="nf">Destroy</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">gameObject</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>There are several really good tweening libraries for Unity although I must say DOTween
is my favorite since it has a wealth of features and performs well even on mobile. DOTween
is open source although there is a DOTween Pro version which includes extra features
such as visual editors but most importantly allows you to show some support to the
fantastic developer of this asset.Services and configuration assets for Unity projects2016-10-17T00:00:00+01:002016-10-17T00:00:00+01:00/2016/10/17/services-and-configuration-assets-in-unity-projects<p>With many of the projects that I have worked on it has been necessary to support a variety
of build targets that are either configured differently or make use of entirely different
services. In early projects I would simply use the various symbols that Unity defines such
as <code class="highlighter-rouge">UNITY_ANDROID</code> but this falls short when supporting multiple Android based platforms.
Not to mention dealing with projects that contain multiple reskins of the same core game
each with a range of different platforms.</p>
<p>Over the course of several projects my approached evolved into having a dedicated
configuration asset per build target. For game projects that are home to multiple reskins
this means having a set of configuration assets per reskin. Since I use <a href="https://github.com/modesttree/Zenject">Zenject</a> to
perform dependency injection it is fairly straightforward to inject entirely different
implementations based purely upon configuration.</p>
<p>Here is an example of a configuration asset which in this particular case is inheriting
some configuration that is common to all targets of the game:</p>
<p><img src="/assets/blog/2016/10/17/configuration-asset.png" alt="Screenshot of configuration asset inspector" /></p>
<p>Each service is essentially just a contract that is declared and uniquely identified using
.NET’s type system. For instance, the “Goals” service could be declared as follows:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">Goals_Service</span> <span class="p">:</span> <span class="n">Service</span>
<span class="p">{</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The “Goals” service will then automatically appear in the configuration asset inspector
as something that could potentially be configured and installed. In order to install some
implementation of the “Goals” service at least one dedicated installer will need to be
implemented.</p>
<p>A <code class="highlighter-rouge">ZenjectServiceInstaller<TService></code> is essentially just a <a href="https://github.com/modesttree/Zenject#scriptableobject-installer">ScriptableObjectInstaller</a>
from the <a href="https://github.com/modesttree/Zenject">Zenject</a> dependency injection framework. Whilst I choose to use Zenject for
dependency injection in my projects; this same technique could easily be used with other
dependency injection frameworks.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">abstract</span> <span class="k">class</span> <span class="nc">Goals_Installer</span> <span class="p">:</span> <span class="n">ZenjectServiceInstaller</span><span class="p"><</span><span class="n">Goals_Service</span><span class="p">></span>
<span class="p">{</span>
<span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">InstallBindings</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">IGoalManager</span><span class="p">>()</span>
<span class="p">.</span><span class="n">To</span><span class="p"><</span><span class="n">GoalManager</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>If only one installer is available then simply clicking the (+) button to the side of the
service in the configuration asset inspector will add the installer component to the
configuration asset. If multiple installer implementations are available then they will be
displayed in a drop-down menu allowing the user to select which specialized installer
should be used to install that service.</p>
<p><img src="/assets/blog/2016/10/17/multiple-installers.png" alt="Screenshot of service that has multiple installers" /></p>
<p>This is especially useful for situations where there might be platform specific
implementations of a service; such as how achievements are reported. You might want to
configure and install a “Steamworks” implementation for standalone desktop releases whilst
using Unity’s “Social API” implementation for mobile releases; or even utilize some sort
of fake implementation for platforms that do not have any specialized support for
reporting achievements.</p>
<p>A fake implementation could be anything from providing a “Null” implementation that simply
does nothing when achievements are reported to a custom achievements solution which shows
a custom in-game UI.</p>
<p>Each completed configuration asset represents a build target of the Unity project; so
effectively one for each build target. It is also possible to have different
configurations for multiple platforms that use the same technology; such as Android for
the Google Play and WildTangent stores. Common configuration can also be inherited from
shared configuration assets if desired.</p>
<p>The “TargetConfigurationSelector” asset simply marks the active build target. In my
projects I simply have <a href="https://ancientlightstudios.com/utomate/">uTomate</a> wire this up automatically upon initiating a build.</p>
<p><img src="/assets/blog/2016/10/17/directory-structure.png" alt="Screenshot of configuration directory structure" /></p>
<p>Configurations and installers are assets that extend Unity’s <code class="highlighter-rouge">ScriptableObject</code> asset
allowing the installers to be added as sub-objects of configuration assets:</p>
<p><img src="/assets/blog/2016/10/17/installer-sub-objects.png" alt="Screenshot of installer sub-objects" /></p>
<p>Whilst the installers can be configured using the inspector by selecting the configuration
sub-objects; this is usually not necessary since they are inlined into the inspector of
the configuration asset.</p>
<p>I devised a simple naming convention that can optionally be used when implementing
services and installers. In addition helping to keep the classes organized this trait is
used by the configuration and installer asset inspectors to provide a clean and readable
UI for the person that is wiring up the configurations.</p>
<p>For example, if there were multiple options for installing an achievement reporting
service and a specialized “Steamworks” service is installed then the configuration asset
inspector would read “Accolades Service (Steamworks)”.</p>
<p>Each target configuration can then specify its own platform-specific properties such as
leaderboard and achievement identifiers:</p>
<p><img src="/assets/blog/2016/10/17/platform-specific-configuration.png" alt="Screenshot of platform specific configuration" /></p>
<p>The user can open up the installer source file by selecting from the installer component’s
context menu in exactly the same way that they would if they wanted to view the source of
a <code class="highlighter-rouge">MonoBehaviour</code> derived class.</p>
<p>Services can be defined in source files that are included somewhere within a Unity project
or in compiled assemblies if desired. In my projects services are primarily defined within
packages. Often there is an abstract package that defines the service along with the
minimal required interfaces that must be implemented in order to use the service.</p>
<p>A separate package is then created for each specialized implementation of the service; for
instance “accolades” would define the service and interfaces whilst “accolades_steamworks”
would provide a steamworks specific implementation and installer.</p>
<p>For small games I found that it was only necessary to have a single “Main” service per
game project to install all of the games services and wire up things like the menu system.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">[Dependency(typeof(Goals_Service))]</span>
<span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">Main_Service</span> <span class="p">:</span> <span class="n">Service</span>
<span class="p">{</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Notice how the <code class="highlighter-rouge">Main_Service</code> has a <code class="highlighter-rouge">Dependency</code> attribute. The dependency attribute
specifies the services that are required (in this case) by <code class="highlighter-rouge">Main_Service</code> and as such must
be installed first. The dependency attribute can be used on services and/or installers and
are used internally to build a graph of services and their dependencies. This graph is not
necessarily the same as the package dependency graph.</p>
<p>It is useful to use the <code class="highlighter-rouge">Dependency</code> attribute on services where it is always necessary
for the other service(s) to be present (for example, a service that reports achievements
based on goal progression would always require the “accolades” and “goals” services).</p>
<p>It is useful to use the <code class="highlighter-rouge">Dependency</code> attribute on installers when the service dependency
is only required for a specific service implementation. In my use cases this situation has
been far less common.</p>
<p>Here is how an installer for the <code class="highlighter-rouge">Main_Service</code> might look:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">Main_Installer</span> <span class="p">:</span> <span class="n">ZenjectServiceInstaller</span><span class="p"><</span><span class="n">Main_Service</span><span class="p">></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">SkinDataAsset</span> <span class="n">skin</span> <span class="p">=</span> <span class="k">null</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">EventSystem</span> <span class="n">eventSystemPrefab</span> <span class="p">=</span> <span class="k">null</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">AudioManager</span> <span class="n">audioManagerPrefab</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
<span class="k">public</span> <span class="k">override</span> <span class="k">void</span> <span class="nf">InstallBindings</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InstallGeneralPrefabPool</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InstallGameManager</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InstallDataServices</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InstallLeaderboardReporter</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InstallAudioManager</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InstallPlayableActors</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InstallEventSystem</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="nf">InstallMenuSystem</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InstallGeneralPrefabPool</span><span class="p">()</span>
<span class="p">{</span>
<span class="kt">var</span> <span class="n">poolContainerGO</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">GameObject</span><span class="p">(</span><span class="s">"GeneralPrefabPool"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">poolContainer</span> <span class="p">=</span> <span class="n">poolContainerGO</span><span class="p">.</span><span class="n">transform</span><span class="p">;</span>
<span class="nf">DontDestroyOnLoad</span><span class="p">(</span><span class="n">poolContainerGO</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">IGeneralPrefabPool</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">FromInstance</span><span class="p">(</span><span class="k">new</span> <span class="nf">GeneralPrefabPool</span><span class="p">(</span><span class="n">poolContainer</span><span class="p">));</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InstallGameManager</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">ISkin</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">FromInstance</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">skin</span><span class="p">);</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">IOutfitPrefabProvider</span><span class="p">>()</span>
<span class="p">.</span><span class="n">To</span><span class="p"><</span><span class="n">PlayerProfileOutfitPrefabProvider</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">TitleMenuScreen</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsTransient</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">PlayingScreen</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsTransient</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">OutfitSelectorScreen</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsTransient</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">StandardPlayState</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsTransient</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">GameOverPlayState</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsTransient</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">TutorialPlayState</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsTransient</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">GameManager</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InstallDataServices</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">IPlayerProfile</span><span class="p">>()</span>
<span class="p">.</span><span class="n">To</span><span class="p"><</span><span class="n">StandardPlayerProfile</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">()</span>
<span class="p">.</span><span class="nf">WithArguments</span><span class="p">(</span><span class="k">new</span> <span class="n">StandardPlayerProfile</span><span class="p">.</span><span class="n">Options</span> <span class="p">{</span>
<span class="n">MaxRecentScoreCount</span> <span class="p">=</span> <span class="m">10</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InstallLeaderboardReporter</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">PlayerProfileLeaderboardReporter</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">();</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">LeaderboardScoreReporterFailureRecovery</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InstallAudioManager</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">IAudioManager</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">FromPrefab</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">audioManagerPrefab</span><span class="p">)</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InstallPlayableActors</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">IPlayableActorManager</span><span class="p">>()</span>
<span class="p">.</span><span class="n">To</span><span class="p"><</span><span class="n">PlayableActorManager</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InstallEventSystem</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">EventSystem</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">FromPrefab</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">eventSystemPrefab</span><span class="p">)</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">()</span>
<span class="p">.</span><span class="nf">NonLazy</span><span class="p">();</span>
<span class="p">}</span>
<span class="k">private</span> <span class="k">void</span> <span class="nf">InstallMenuSystem</span><span class="p">()</span>
<span class="p">{</span>
<span class="k">this</span><span class="p">.</span><span class="n">Container</span><span class="p">.</span><span class="n">Bind</span><span class="p"><</span><span class="n">IMenuSystem</span><span class="p">>()</span>
<span class="p">.</span><span class="nf">FromPrefab</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">skin</span><span class="p">.</span><span class="n">MenuSystemPrefab</span><span class="p">)</span>
<span class="p">.</span><span class="nf">AsSingle</span><span class="p">();</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>With this approach it is very easy to define multiple skins of the same game project
simply by creating a set of configuration assets for each skin. Unity’s build process will
only include assets that are directly referenced by each build and so assets from, say,
the “Space” skin will not be included when building, say, the “Candy” skin.</p>
<p>The “Skin” field references a data asset that defines all of the prefabs and rules that
are used for that ‘reskin’ of the game. For example; a “Space” reskin of the game might
have a menu system that is stylized with stars and planets whilst the “Candy” reskin of
the game might have a menu system that is stylized with iced buns and chocolate buttons.</p>
<p>The actual dependency injection process can be initiated in a number of ways. In my
projects I have a scene composition root in an empty scene which uses the
“TargetConfigurationSelector” asset to access and install the active target configuration:</p>
<p><img src="/assets/blog/2016/10/17/scene-context.png" alt="Screenshot of scene composition root" /></p>
<p>I then have some sort of a “Bootstrap” object which will start automatically after Zenject
has injected the scene. I tend to just start the game manager as a coroutine since I tend
to implement this as a state machine:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">sealed</span> <span class="k">class</span> <span class="nc">Bootstrap</span> <span class="p">:</span> <span class="n">MonoBehaviour</span>
<span class="p">{</span>
<span class="p">[</span><span class="n">Inject</span><span class="p">]</span>
<span class="k">private</span> <span class="n">GameManager</span> <span class="n">gameManager</span> <span class="p">=</span> <span class="k">null</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="k">this</span><span class="p">.</span><span class="nf">StartCoroutine</span><span class="p">(</span><span class="k">this</span><span class="p">.</span><span class="n">gameManager</span><span class="p">.</span><span class="nf">Execute</span><span class="p">());</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>With many of the projects that I have worked on it has been necessary to support a variety
of build targets that are either configured differently or make use of entirely different
services. In early projects I would simply use the various symbols that Unity defines such
as UNITY_ANDROID but this falls short when supporting multiple Android based platforms.
Not to mention dealing with projects that contain multiple reskins of the same core game
each with a range of different platforms.