<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Johan Steen</title>
    <description>The latest articles on Forem by Johan Steen (@johansteen).</description>
    <link>https://forem.com/johansteen</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F328604%2F17a541ff-de47-4b2f-8944-88be0deb59f7.jpeg</url>
      <title>Forem: Johan Steen</title>
      <link>https://forem.com/johansteen</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/johansteen"/>
    <language>en</language>
    <item>
      <title>SpriteKit Safe Area</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Tue, 09 May 2023 07:11:14 +0000</pubDate>
      <link>https://forem.com/johansteen/spritekit-safe-area-20en</link>
      <guid>https://forem.com/johansteen/spritekit-safe-area-20en</guid>
      <description>&lt;p&gt;To ensure that no important elements are obstructed on devices with notches or curved corners, the screen's safe area values are available to help with the layout. When building an app with SwiftUI, AppKit, or UIKit, taking safe areas into account is quite simple and straightforward.&lt;/p&gt;

&lt;p&gt;As the story usually goes with SpriteKit, it is not as simple out of the box, and we have to take a few extra steps to handle safe areas in a &lt;code&gt;SKScene&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There are many ways to skin a cat, and here's the workflow I've come up with that has worked very well for my SpriteKit projects.&lt;/p&gt;

&lt;p&gt;I try to avoid having to make different versions of my code for different devices as much as possible, and that philosophy also applies when it comes to safe areas. To cover any scenario, I like to add collapsing margins combined with the safe areas, to have the content placed where I want it on all devices without any other modifications.&lt;/p&gt;

&lt;p&gt;When there is no safe area, we are going to want to use a margin between the screen's edge and the content. On devices with a safe area, the safe area will be used instead of the margin. Basically, we intend to collapse the margin with the safe area, to make the same setup work predictably enough on any device.&lt;/p&gt;

&lt;p&gt;Let's study a few examples to narrow it down, we'll pretend that the circle shape represents an important HUD element that we want to place in the top left corner of the screen.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l7Z5s1VN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kessaxfrcwnkgz7p7zer.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l7Z5s1VN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kessaxfrcwnkgz7p7zer.png" alt="Collapsed Margins on device with safe areas" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The version to the left illustrates what we'd get if we do nothing and just place the element in the top left corner. On a modern iPhone, a portion of the element will be obstructed by the rounded corner.&lt;/p&gt;

&lt;p&gt;Most likely, we'd like to add a margin, and also use the safe area of the screen. If we were to put the element in a container with a margin for left and top edges, and then also use the safe area, we would end up with the middle scenario on a modern iPhone. We have a nice margin from the top, but on the left side we have both the safe area and the margin. In this case, it would most likely look the best to only use the safe area on the left side.&lt;/p&gt;

&lt;p&gt;That leaves us with the version to the right, where the left margin is collapsed as there is a safe area, while we still use the margin on the top edge, as there is no safe area there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jLjZIQEL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0njbgq6t6rcaynrj0ib4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jLjZIQEL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0njbgq6t6rcaynrj0ib4.png" alt="Margins on device without safe area" width="800" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On a device with no safe areas, where the content would line up with the edge if we only used the safe area values, the margin will kick in on both the top and the left side.&lt;/p&gt;

&lt;h2&gt;
  
  
  SKScene Safe Areas
&lt;/h2&gt;

&lt;p&gt;Before we get started, my workflow is based on the assumption that the SpriteKit scene adapts to the size based on the viewport, like I've lined out in a previous article, &lt;a href="https://blog.bitbebop.com/spritekit-game-aspect-ratio-resolution/"&gt;Multiple Aspect Ratios and Resolutions with SpriteKit&lt;/a&gt;. If you use another &lt;code&gt;scaleMode&lt;/code&gt; for your projects, you might need to adjust accordingly.&lt;/p&gt;

&lt;p&gt;With that out of the way, let's get down to business. The hosting view for the SpriteKit scene, &lt;code&gt;SKView&lt;/code&gt;, provides a &lt;code&gt;safeAreaInsets&lt;/code&gt; property that inherited from UIView. While this provides all necessary information about the device safe areas, the values are not directly usable, as a SpriteKit scene has its own coordinate system and then scaled inside SKView. To get something usable in &lt;code&gt;SKScene&lt;/code&gt; we are going to recalculate these values.&lt;/p&gt;

&lt;p&gt;For our convenience, let's extend &lt;code&gt;SKScene&lt;/code&gt; and give it its own &lt;code&gt;safeAreaInsets&lt;/code&gt; property. We are going to need a struct that can hold the SKScene specific values.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;SKScene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will allow us to have an API similar to the one provided via SKView, but with more relevant values for working with SpriteKit.&lt;/p&gt;

&lt;p&gt;With the struct in place, we will have to figure out how much the SpriteKit &lt;code&gt;SKScene&lt;/code&gt; has scaled in relationship to the hosting &lt;code&gt;SKView&lt;/code&gt;. Let's add a property that calculates that information.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;fileprivate&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;fatalError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Scene has no hosting view"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now use the struct and the scaleFactor, to add the final property that will provide us with relevant safe area values for the &lt;code&gt;SKScene&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the scene has not yet been added to a view we return the shorthand static zero property of the &lt;code&gt;SafeAreaInsets&lt;/code&gt; struct, else we multiply the view's safe area insets with how much the scene has scaled, to get safe area values that work as-is for the current SpriteKit scene.&lt;/p&gt;

&lt;p&gt;To put it all together, we have ended up with this extension.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;SKScene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;fileprivate&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;fatalError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Scene has no hosting view"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;frame&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kt"&gt;SafeAreaInsets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nv"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nv"&gt;right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;scaleFactor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  First Scene Gotcha
&lt;/h2&gt;

&lt;p&gt;When the first scene is presented, &lt;code&gt;SKView&lt;/code&gt; has not yet got the &lt;code&gt;SafeAreaInsets&lt;/code&gt; and returns &lt;code&gt;0&lt;/code&gt; for all edges. Once the view is displayed, the inset updates to the correct values.&lt;/p&gt;

&lt;p&gt;For every following scene being presented, the view will have the correct values right away. If the first scene presented does not need to care about safe areas, it could likely be a loading scene where safe area play no part, then this gotcha is really nothing to care about.&lt;/p&gt;

&lt;p&gt;In the case where the first presented scene needs to care about safe areas, that can be resolved by extending &lt;code&gt;SKView&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;open&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;safeAreaInsetsDidChange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didChangeSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the system provides the app with the safe area values, &lt;code&gt;safeAreaInsetsDidChange&lt;/code&gt; will be triggered in &lt;code&gt;SKView&lt;/code&gt;. We hook in to that method to notify the presented scene about the change.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didChangeSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;oldSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didChangeSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nf"&gt;layoutScene&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the presented scene, we can then use &lt;code&gt;didChangeSize&lt;/code&gt; once the &lt;code&gt;SafeAreaInsets&lt;/code&gt; becomes available, so the scene has a chance to do its positioning of elements there to ensure the layout for the first presented scene will look correct on all devices.&lt;/p&gt;

&lt;p&gt;If the game supports both portrait and landscape mode, this should probably be handled in every scene to adjust the layout if the player rotates the device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Collapsing Margins
&lt;/h2&gt;

&lt;p&gt;Now, let's take a look at handling margins. Let's say that we have a player card that should be placed in the top left corner. To simplify things, let's say that we have set the anchor points of our scene to have the top left corner at &lt;code&gt;(0, 0)&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didChangeSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;oldSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didChangeSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;leftOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;topOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;

  &lt;span class="n"&gt;playerCard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;leftOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;topOffset&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By placing the card using the safe area values to offset the asset from the edges of the screen, we are ending up with this as a result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VI2_LgAA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kcuf2flyiw5g1rewnxy5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VI2_LgAA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kcuf2flyiw5g1rewnxy5.png" alt="Safe area and device orientation without collapsing margins" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we display the scene in portrait mode, we get an offset from the top of the screen, while we have no margin on the left side. When rotating the screen to landscape mode, we instead get an offset on the left edge of the screen, but we now have no margin at the top.&lt;/p&gt;

&lt;p&gt;So what we want to do is this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Portrait mode:&lt;/strong&gt; Left edge use margin, top edge use safe area.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Landscape mode:&lt;/strong&gt; Left edge use safe area, top edge use margin.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can easily be accomplished by using &lt;code&gt;max()&lt;/code&gt;, let's expand the layout code from before by adding a margin of &lt;code&gt;16.0&lt;/code&gt; and then using max to collapse it with the safe area.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didChangeSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;oldSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didChangeSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;margin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;16.0&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;leftOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;topOffset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;safeAreaInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;playerCard&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGPoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;leftOffset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nv"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;topOffset&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this change we are ending up with something that looks much healthier where we have a margin kicking in when there is no safe area available.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pslIdNrC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6b7rahiauoyukqjy6g7b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pslIdNrC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6b7rahiauoyukqjy6g7b.png" alt="Safe area and device orientation cith collapsing margins" width="800" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope this approach can serve as a start to get a solid foundation for how to handle safe areas and margins for content living near the edges of the screen. See this as a starting point and spur ideas how to take this further to set up a layout and positioning system with SpriteKit. As a first next step, I can definitely see the collapsing of margins being automated into a property or method.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>gamedev</category>
      <category>spritekit</category>
    </item>
    <item>
      <title>Game Event System with Swift</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Mon, 25 Jul 2022 04:23:40 +0000</pubDate>
      <link>https://forem.com/johansteen/game-event-system-with-swift-40db</link>
      <guid>https://forem.com/johansteen/game-event-system-with-swift-40db</guid>
      <description>&lt;p&gt;A game can usually be broken down into different systems, which are the building blocks of the game's architecture.&lt;/p&gt;

&lt;p&gt;One system could manage the on screen HUD, another the player, a third the enemies, and so on, and all these systems need to communicate with each other in one way or another. It is very easy to end up with a dependency nightmare between the different game systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency Nightmare
&lt;/h2&gt;

&lt;p&gt;We begin with an example of a problematic architecture, one that we are going to try to avoid by using game events for a more modular approach.&lt;/p&gt;

&lt;p&gt;Let's say that we have an enemy entity that we want to test in isolation to save some time. There's really no need to startup the entire game world to see the animations, how the enemy responds to certain interactions, or similar things. So we are going to use a barebone scene where we can drop in an enemy entity and to be able to do some quick tests in a live environment.&lt;/p&gt;

&lt;p&gt;We setup the barebone scene and add some initialization code to instantiate our enemy. But it won't compile; the enemy entity depends on the existence of the &lt;code&gt;EnemyManager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So we also instantiate the &lt;code&gt;EnemyManager&lt;/code&gt; in our test scene and give it another go. Won't compile again, the &lt;code&gt;EnemyManager&lt;/code&gt; can't find the &lt;code&gt;Player&lt;/code&gt;, a dependency that is used to let enemies make their AI decisions.&lt;/p&gt;

&lt;p&gt;Okay, so we are adding the player to the test scene too. And let's run it.&lt;/p&gt;

&lt;p&gt;Ouch, the Player needs the &lt;code&gt;InventoryManager&lt;/code&gt;. Okay, let add that one as well. And go! Nooooooo! The player also needs the &lt;code&gt;HUDManager&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Eventually we've pretty much rebuilt the entire game architecture inside what was supposed to be our lean and mean debug scene.&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Events
&lt;/h2&gt;

&lt;p&gt;Which brings us to events. By using events to communicate between the game's different systems, we get a much more decoupled architecture. When a system raises an event, it doesn't care who listens to it, and a system that listens for an event doesn't care who raised it.&lt;/p&gt;

&lt;p&gt;This makes it very easy to take out any object from the game and drop it in an isolated environment or scene and it will pretty much work right away. And we can decorate our test scene with event triggers so we can trigger any event we want on demand and observe the behavior, without actually having to add the system that would trigger the event in the game.&lt;/p&gt;

&lt;p&gt;This architecture helps us get rid of hard dependencies between our game's systems.&lt;/p&gt;

&lt;p&gt;And of course, when it comes to the actual gameplay scenes, the more decoupled and isolated our systems are, the more reusable the systems will become for future projects, and as a bonus, way easier to debug and test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Observers vs Broadcasters
&lt;/h2&gt;

&lt;p&gt;When it comes to handling events, there are primarily two design patterns that are highly popular, either using observers or broadcasters with listeners.&lt;/p&gt;

&lt;p&gt;I've implemented and used both approaches in different projects, and while I like many things about the observer pattern, it relies on dependencies between objects in one way or another. Which is what we are trying to avoid.&lt;/p&gt;

&lt;p&gt;I've used solutions similar to this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;HealthComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Observable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;health&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;didSet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;notifyObservers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entityHealthChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, the HUD can observe the health component to instantly update the health bar whenever the player's health changes. But this requires that the HUD is aware of the player object, to register with it, which gives us a hard-wired dependency.&lt;/p&gt;

&lt;p&gt;So I personally rarely use this pattern anymore, and instead I most of the time rely on broadcasting events and having listeners, which provides a much more decoupled architecture.&lt;/p&gt;

&lt;p&gt;The drawback can be that it can be harder to read and follow the event flow in code when there are no hard connections between the systems. Someone new to the code base would have to spend some time looking up and finding out what is listening to what events, as the compiler can't help with that.&lt;/p&gt;

&lt;p&gt;I now handle that by logging events when running the game in debug mode, so I can at any time request the log and see what events that were triggered, and which objects that responded to each event. That more or less take care of that drawback.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;That was a lot of background and theory, but now when we have decided that we want to broadcast events between systems, let's look at how we can implement that functionality in Swift. We are going to make our own implementation as we want maximum performance. We don't want to rely on &lt;code&gt;NotficationCenter&lt;/code&gt; or other built-in solutions that are less performant&lt;sup id="fnref1"&gt;1&lt;/sup&gt; than what we can build ourselves.&lt;/p&gt;

&lt;h3&gt;
  
  
  Event Channels
&lt;/h3&gt;

&lt;p&gt;We are going to use event channels that we broadcast on, and pass along any relevant data. Interested parties can listen to channels of interest and react to events.&lt;/p&gt;

&lt;p&gt;So we are going to setup an Event class that each event channel that we create will instantiate and be available for systems to broadcast on or listen to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We are going to use Swift generics for this class, when we define an event channel we also determine with the generic what kind of data we will pass along with the event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;enemyDestroyedEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Enemy&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we create an &lt;code&gt;enemyDestroyedEvent&lt;/code&gt; channel where we will pass along an instance of an Enemy object. When an enemy is destroyed the enemy will broadcast and pass along itself on this channel just before it removes itself from the game.&lt;/p&gt;

&lt;p&gt;A number of other systems might listen to this event; the audio system could take the Enemy object and determine which sound effect to play; the UI system shows a score floating for a short period of time where the enemy was destroyed. The VFX system instantiates an explosion animation on screen at the enemy's last position.&lt;/p&gt;

&lt;p&gt;Our &lt;code&gt;Event&lt;/code&gt; class is going to need to store a collection of listeners for each channel so the channel knows which objects that should be notified when the event is raised.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;typealias&lt;/span&gt; &lt;span class="kt"&gt;EventAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Void&lt;/span&gt;

&lt;span class="c1"&gt;/// Listener wrapper to be able to use a weak reference to the listener.&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;Listener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// Weak reference to the listener.&lt;/span&gt;
  &lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AnyObject&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;

  &lt;span class="c1"&gt;/// Action closure provided by the listener.&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;EventAction&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;ObjectIdentifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[:]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We don't want to risk that the event channel keeps the object alive if the object is removed from the game, so we use a &lt;code&gt;Listener&lt;/code&gt; struct as a wrapper around the object that listens, so we can have a weak reference to the listener. We are using &lt;code&gt;ObjectIdentifier&lt;/code&gt; as the key for the listener, so it's easy to find the listener in the collection if we need to remove it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;EventAction&lt;/code&gt; &lt;code&gt;typealias&lt;/code&gt; gives us some sugared syntax.&lt;/p&gt;

&lt;p&gt;Now we have a place to store the listeners for an event channel, so let's add some methods so objects can let the channel know that they want to listen for events.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Register a new listener for the event.&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AnyObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;@escaping&lt;/span&gt; &lt;span class="kt"&gt;EventAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ObjectIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Listener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Unregister a listener for the event.&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;removeListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;AnyObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ObjectIdentifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thanks to the solid structure where we store the listeners, the &lt;code&gt;addListener()&lt;/code&gt;, and &lt;code&gt;removeListener()&lt;/code&gt; methods become very straightforward. We basically just have to get the &lt;code&gt;ObjectIdentifier&lt;/code&gt; for the listener and add/remove it from the collection.&lt;/p&gt;

&lt;p&gt;And finally, we are going to need a method to broadcast events to listeners.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Raise the event to notify all registered listeners.&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;listeners&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If the listening object is no longer in memory,&lt;/span&gt;
    &lt;span class="c1"&gt;// we can clean up the listener for its ID.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;listener&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;listeners&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;continue&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;listener&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we raise the event to iterate through the collection of listeners to notify them. As we used a weak reference to the listener to not keep them alive if they are removed from the game, we also check here so the listener is still around. If it's not, we take the opportunity to clean up the collection by removing it.&lt;/p&gt;

&lt;p&gt;And that's it; this class gives us everything we need to broadcast and listen to events.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Event Channels
&lt;/h3&gt;

&lt;p&gt;That leaves us with how to use the event channels when we need to communicate between the game's different systems. There are many approaches to choose from. I prefer to use a &lt;code&gt;GameEvent&lt;/code&gt; singleton as a communication central where I define all channels that the game uses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;GameEvent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;shared&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;GameEvent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="c1"&gt;// Event Channels.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scoreChangedEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;GameData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;livesChangedEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;GameData&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;enemyDestroyedEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;Enemy&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;playerDamagedEvent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Event&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;HealthComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the place where I'm collecting and organizing all event channels that the game will need, and by exposing it as a singleton, I can simply use it from anywhere in the game code.&lt;/p&gt;

&lt;p&gt;For an object to register itself as a listener, we would use the &lt;code&gt;addListener()&lt;/code&gt; method in the event channel.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;AudioComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;GameEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;playerDamagedEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onPlayerDamaged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;onPlayerDamaged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Play the sound effect when player is taking damage.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have a component that handles playing sound effects. By having it listen to the &lt;code&gt;playerDamageEvent&lt;/code&gt; it can play the appropriate sound effect every time the player is damaged. Also, the health bar in the HUD would listen to this event and maybe also an animation component that would play a damage animation, and possibly emit some particles.&lt;/p&gt;

&lt;p&gt;To be useful, events must also be raised.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;HealthComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;takeDamage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Do some other damage related things...&lt;/span&gt;

      &lt;span class="kt"&gt;GameEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;playerDamagedEvent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is more or less self-explanatory. This would be the health component for the player that raises the event every time the player takes damage, so other systems can react to it. The component passes along itself with the event, so listeners that relies on data in the health component can do so. The HUD most likely is going to check the health percentage for the component when the visuals on screen are updated.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is my preferred way to pass data between game systems and I find it highly powerful and flexible. The complete decoupling between objects provides possibilities for very interesting solutions. As an object is not aware, care, or even interested in what listens to its events, you can wire up pretty much anything with anything.&lt;/p&gt;

&lt;p&gt;With that in mind, each game component can be kept very clean and only focus on one thing. The health component only needs to track health; everything else in the game that depends on health is handled by other systems, more relevant for the separate purpose, and events are the delivery mechanism between them.&lt;/p&gt;

&lt;p&gt;The UI is driven by events from the health component; a destroy component is driven by the same events. An audio component can also listen to the event in question. Anything that makes sense can listen to events, without having to introduce a dependency between objects.&lt;/p&gt;

&lt;p&gt;But don't forget... With great power comes great responsibility.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://stackoverflow.com/a/28309749/1152087"&gt;Performance Results&lt;/a&gt;. Test results of Notification Center performance. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>gamedev</category>
      <category>swift</category>
    </item>
    <item>
      <title>Game Center Achievements with Swift</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Fri, 15 Jul 2022 09:15:19 +0000</pubDate>
      <link>https://forem.com/johansteen/game-center-achievements-with-swift-3599</link>
      <guid>https://forem.com/johansteen/game-center-achievements-with-swift-3599</guid>
      <description>&lt;p&gt;I start early on in the development of a game to think about achievements and make notes during the development progress whenever I add something to the game that could also add some sort of additional challenge for the player in one way or another, to make it into a possible candidate to become an achievement.&lt;/p&gt;

&lt;p&gt;Implementing achievements in a game is a great way to add some additional fun things to do in the game, and to give players more enjoyment. To be able to collect an achievement is an opportunity to make the players feel good while playing, and not only to keep grinding to collect points towards a new high score.&lt;/p&gt;

&lt;p&gt;Achievements can also be used as hints and help to direct the player to try unusual things or to find some hidden area or mechanic they might not have found out about.&lt;/p&gt;

&lt;p&gt;As a gamer myself, I do enjoy spending some extra time in games I buy to keep collecting achievements, event after I have beaten the game.&lt;/p&gt;

&lt;p&gt;All in all, achievements can help to add some extra playtime to the game and give some extra joy to the players, which makes me feel its worth the extra time to implement some meaningful achievements for the players to collect.&lt;/p&gt;

&lt;p&gt;When I did my first implementation, I immediately saw the danger that the logic to check for achievement progress could add some serious code pollution. I wanted to come up with an approach to keep it as decoupled as possible from the actual game code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Center for Progress Storage
&lt;/h2&gt;

&lt;p&gt;Also, I did not want to worry about storing progress myself, but instead delegated that responsibility to Apple and Game Center. By letting Game Center be the only source of truth for the player's progress, players get progress synced between all their devices as a bonus. So a player who progresses towards an achievement on the iPhone, will see the same progress advancement when opening up the game on the Apple TV.&lt;/p&gt;

&lt;p&gt;The only drawback with this solution is that Game Center only stores integers, while a custom solution could track floats and have much more fine-grained tracking towards a goal if needing more than 100 steps.&lt;/p&gt;

&lt;p&gt;I found the convenience of not having to store things myself and not having to make a custom iCloud-based sync solution more important, than being able to have other value types for more fine-grained progress tracking.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Achievement Logic
&lt;/h2&gt;

&lt;p&gt;I came up with an approach where I make a class for each achievement in the game, and let the class contain the unique logic to track the progress of that achievement.&lt;/p&gt;

&lt;p&gt;Doing it this way, I can keep all the achievement logic code contained completely separate from the rest of the game code. The game code should only need to worry about when to let the achievement know when it's time to run its logic.&lt;/p&gt;

&lt;p&gt;To handle this, I'm inheriting from &lt;code&gt;GKAchievement&lt;/code&gt; to add some additional logic while still being able to piggyback on the functionality to read from and report back the progress to Game Center using only one object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;BaseAchievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKAchievement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// Determine if the achievement has unreported progress.&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isDirty&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

  &lt;span class="c1"&gt;/// Increase progress towards getting the achievement.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// If achievement is already completed, no need to track progress.&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;isCompleted&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Run the logic to update the percentage.&lt;/span&gt;
    &lt;span class="nf"&gt;updatePercentComplete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Mark it as dirty.&lt;/span&gt;
    &lt;span class="n"&gt;isDirty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="c1"&gt;// Report immediately if achievement was completed.&lt;/span&gt;
    &lt;span class="nf"&gt;reportIfCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;/// Logic to update the percentage completed.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updatePercentComplete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;fatalError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Should be overriden in subclass"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;/// Report the achievement if it is completed.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;reportIfCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isCompleted&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kt"&gt;GameCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My &lt;code&gt;BaseAchievement&lt;/code&gt; class is the base for every achievement I add to the game. It gives us two additional features. First, a location for where to put the logic to track progress towards the achievement; and second, it handles deferred reporting.&lt;/p&gt;

&lt;p&gt;Some achievements execute the progress logic quite often; for instance, an achievement to have destroyed maybe 5000 enemies could potentially run the logic in very short intervals. I don't want the game to constantly connect to Game Center servers and report every single enemy. Instead, I defer that report to occur between game levels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Deferred Reporting
&lt;/h3&gt;

&lt;p&gt;Whenever the game trigger that progress towards an achievement has happened the &lt;code&gt;progress()&lt;/code&gt; method is executed. Unless the achievement is already completed, the logic to update the progress happens, and the achievement is marked as &lt;code&gt;isDirty&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By marking achievements that have progress happening as &lt;code&gt;isDirty&lt;/code&gt; is how we later can determine which achievements that have had changes, and then batch report all of them in one go, instead of constantly reporting them one by one as progress happens.&lt;/p&gt;

&lt;p&gt;The exception is if the progress has completed the achievements. If so, I want the report to happen right away with &lt;code&gt;reportIfCompleted()&lt;/code&gt; so the player gets the achievement banner shown on screen at the very moment the achievement was&lt;br&gt;
completed.&lt;/p&gt;
&lt;h3&gt;
  
  
  Progress Logic
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;updatePercentComplete()&lt;/code&gt; method is where the unique logic is located for each achievement. So when we make our achievements classes, this is the only method we need to implement for each achievement.&lt;/p&gt;

&lt;p&gt;Let's look at an achievement that will be awarded when the player has collected 100 upgrades.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Upgrade the Weapon 100 Times.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;UpgradeAchievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BaseAchievement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updatePercentComplete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;percentComplete&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This class increases progress by 1% each time the player collects an upgrade, and once it reaches 100%, the achievement will be completed. That won't happen until after many game sessions, as one session might just be a few upgrades. But as mentioned, Game Center keeps track of the progress between sessions and also between devices.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;As we execute code in this method, we could do any kind of logic required or any kind of conditions or comparisons for different achievement types.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Some achievements are one-shot achievements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Read the rules.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;LibrarianAchievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BaseAchievement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updatePercentComplete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;percentComplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;100.0&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The player gets the librarian achievement for reading the game's instructions page. There's not really any progress to collect, so we set the achievement to 100% right away.&lt;/p&gt;

&lt;p&gt;So, what to do when needing more fine grained progress tracking than 1-100?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Destroy 1000 Drones.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;WhackDroneAchievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BaseAchievement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updatePercentComplete&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;percentComplete&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code could easily be mistaken for a solution, as we progress with 0.1% per event, and &lt;code&gt;GKAchievement&lt;/code&gt; uses a double for the progress value, and by that we get 1000 levels. Which is sort of true. That is exactly what will happen locally.&lt;/p&gt;

&lt;p&gt;Unfortunately, Game Center only stores integers on the server even though a double is reported. So if reporting 5.4, it will only store a 5.&lt;/p&gt;

&lt;p&gt;So we can't use Game Center to track progress with more than 100 steps. If we really needed to store more than 100 steps, we'd have to track locally and then report or track with a custom cloud saving if tracking over devices, and then report each time we reach a reportable progress of the achievement.&lt;/p&gt;

&lt;p&gt;What I found, depending on how fast the achievement progresses, is that you many times can get away with tracking with floats locally and reporting the integer at the end of the session; it will work good enough. So, I will track with 0.1 units in the game and just accepts that if the player progress 3.9% only 3% will be recorded.&lt;/p&gt;

&lt;p&gt;Progress will be tracked slightly slower than what the player actually does, but I believe it won't be noticeable most of the time. It's been good enough for the games I've been developing so far. It has to be some really major part of the gameplay for me to consider using a custom cloud-synced solution instead, just to get more reportable steps between devices. If not needing sync between devices, it would be a lot simpler to track progress locally between sessions before&lt;br&gt;
reporting progress.&lt;/p&gt;
&lt;h2&gt;
  
  
  Triggering Achievement Logic
&lt;/h2&gt;

&lt;p&gt;Now we just need to trigger the execution of these classes. I wanted to have an as simple API as I possible could, so there would be a minimum of additional code to add to the game logic. I definitely wanted to use a dot syntax for the achievement names.&lt;/p&gt;

&lt;p&gt;So I came up with this, using a singleton combined with a factory for the achievements, which gives us a syntax like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Record the achievement.&lt;/span&gt;
&lt;span class="kt"&gt;GameCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;librarian&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code that handles the game's instruction page, has the above line of code to ensure the achievement gets handled.&lt;/p&gt;

&lt;p&gt;When an enemy is destroyed in the game, when the state machine enters the destroyed state for the enemy, we can run something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Progress towards achievement.&lt;/span&gt;
&lt;span class="kt"&gt;GameCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bring_pain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kt"&gt;GameCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;whack_drone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which records the progress towards two different achievements that are related to the event of a destroyed enemy. We don't need any conditions on these calls. As soon as an achievement is completed, these calls return immediately.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Achievement Factory
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;GameCenter&lt;/code&gt; class is a singleton that we call the progress method on with the achievement in question whenever we need to record progress, using a dot syntax.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kt"&gt;GameCenter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;survivor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In turn, &lt;code&gt;GameCenter&lt;/code&gt; passes on the request to record progress to the relevant achievement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Achievement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;Achievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;]?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To be able to do that with our achievement objects, I am using an enum that also has a factory and holds all achievement instances.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Manages available Game Center achievements&lt;/span&gt;
&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;Achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;CaseIterable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;champion&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;survivor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;veteran&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;librarian&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is what gives us the dot syntax so we get those clean and beautiful API calls from within our game code.&lt;/p&gt;

&lt;p&gt;Moving on, we need our enum to hold instances of all our achievement objects. We need to populate each instance with the current data stored in Game Center and we need them to be ready to track progress happening at any time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Collection of objects for all available achievements.&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;achievements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;Achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BaseAchievement&lt;/span&gt;&lt;span class="p"&gt;]()&lt;/span&gt;

&lt;span class="c1"&gt;/// Factory to make GKAchievement objects for Game Center IDs.&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Achievement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;BaseAchievement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;gkAchievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BaseAchievement&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt;

  &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="n"&gt;achievement&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;champion&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;ChampionAchievement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;collector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CollectorAchievement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;survivor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SurvivorAchievement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;veteran&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;VeteranAchievement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;librarian&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;LibrarianAchievement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="n"&gt;gkAchievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;showsCompletionBanner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We call the factory using the enum cases with dot syntax, and we get back an instance of the achievement object for the requested case. I'm pretty sure this could be done more dynamically so we don't have to use a switch statement.&lt;/p&gt;

&lt;p&gt;That's something for future enhancements. But for now, when my games don't have more than about ten or so achievements, this has worked out.&lt;/p&gt;

&lt;p&gt;This factory is supposed to be called when we have achievement data returned from Game Center so we can populate each underlying &lt;code&gt;GKAchivement&lt;/code&gt; with the current progress and the identifier the achievement has in the Game Center database.&lt;/p&gt;

&lt;p&gt;I create the achievements in Game Center database using my enum cases as identifiers, so I can simply use the &lt;code&gt;rawValue&lt;/code&gt; for each case to set the correct id for each achievement before I get a response from Game Center.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Create a local GKAchievement object for each Game Center achievement.&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;initAchievements&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;achievement&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;allCases&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Update local achievements with values from Game Center.&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;updateAchievements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;GKAchievement&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;achievements&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;achievement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Achievement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;rawValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Update percent completed.&lt;/span&gt;
      &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;]?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;percentComplete&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gkAchievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;percentComplete&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I uses these two methods to handle the collection of achievements. With init I can create achievements at any time without having to wait for a response from Game Center. By having unconnected achievements, makes the code work even if the player does not use Game Center, so I don't need to have conditions for that.&lt;/p&gt;

&lt;p&gt;The update method I can pass in an array of achievements and update the local copies in memory at any time with fresh data from Game Center.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reporting Achievement Progress
&lt;/h2&gt;

&lt;p&gt;During the startup of a game, where all different game systems are initialized, would be a good place to also sync up with Game Center and get the player's stored progress for the game's different achievements.&lt;/p&gt;

&lt;p&gt;I use Game Center for other things too, like Leaderboard. So during the game's authentication process with Game Center, I end the authentication by loading the progress, if authentication was successful.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;loadAchievements&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;Achievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initAchievements&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="kt"&gt;GKAchievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loadAchievements&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;os_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error in loading achievements: %@"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;describing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;achievements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;achievements&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Process the array of loaded achievements.&lt;/span&gt;
      &lt;span class="kt"&gt;Achievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;updateAchievements&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So here is where we use the methods in the enum we created earlier. Before we ask Game Center for the achievement progress, we create an empty set of Achievement objects. The request is asynchronous and it can potentially take some time until we get a response, or maybe no response at all if the player is offline.&lt;/p&gt;

&lt;p&gt;But if we have a successful response, we will use the update method from our enum so we have fresh data for the progress. If the player is offline, I've opted to not handle that case, and instead just not count progress for those sessions.&lt;/p&gt;

&lt;p&gt;Depending on the game and importance of achievements, one could choose to store progress locally in that case, to sync up once the player is back online. In my case I have decided it's not worth the effort for my more casual games. I might revise that thinking for future titles.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Report a single achievement to game center.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;BaseAchievement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Submit the achievement report to Game Center.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;BaseAchievement&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="n"&gt;isEnabled&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;achievements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;achievements&lt;/span&gt;

  &lt;span class="c1"&gt;// To follow best practices, remove achievements that has no new progress.&lt;/span&gt;
  &lt;span class="n"&gt;achievements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;achievements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isDirty&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// Reset the isDirty flag in achivements with progress.&lt;/span&gt;
  &lt;span class="n"&gt;achievements&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;forEach&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;achievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isDirty&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Submit the report to game center.&lt;/span&gt;
  &lt;span class="kt"&gt;GKAchievement&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;achievements&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;os_log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;game_center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Error in reporting achievements: %@"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;describing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, we need to get updated data back to Game Center. I have two methods that handle reporting. The main one that takes a collection of achievement objects to report, and then for convenience I have a report method that takes a single achievement object and passes it on as a collection to the actual report method.&lt;/p&gt;

&lt;p&gt;I use the convenience single achievement report method to report immediately during play time when an achievement completes, so the player gets an immediate response.&lt;/p&gt;

&lt;p&gt;And between levels, I pass in the entire achievement collection to report progress on every achievement before the next level begins.&lt;/p&gt;

&lt;p&gt;Before the &lt;code&gt;GKAchievement.report()&lt;/code&gt; call happens, which is what triggers the communication with the Game Center servers, we do a bit of tidying up. This is all happening in the &lt;code&gt;GameCenter&lt;/code&gt; singleton and first we check so the player has Game Center enabled. If Game Center for any reason can not be authenticated this will be set to false, and we will not attempt to report.&lt;/p&gt;

&lt;p&gt;If the player uses Game Center and is online, we will move on. Next we check the &lt;code&gt;isDirty&lt;/code&gt; flag we set in our achievement objects. So we can filter out any objects that have had no progress. Sending back objects without progress won't cause any issues with the data, but Apple recommends to only report objects that have had changes.&lt;/p&gt;

&lt;p&gt;And that pretty much sums it up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is the approach I've come up with to interact with Game Center, and to collect my players' progress towards the games different achievements while keeping the logic as separated as possible to avoid polluting the game's code with achievement logic.&lt;/p&gt;

&lt;p&gt;I'm always dabbling with and considering new and better approaches for my different game systems, and I'd love to hear if you have any other ideas or thoughts on how to improve on these concepts. Or if you have taken a completely different approach that I haven't even thought of. If so, please let me know, don't be a stranger.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Sprite Component in GameplayKit</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Fri, 01 Jul 2022 11:47:07 +0000</pubDate>
      <link>https://forem.com/johansteen/sprite-component-in-gameplaykit-cdm</link>
      <guid>https://forem.com/johansteen/sprite-component-in-gameplaykit-cdm</guid>
      <description>&lt;p&gt;Let's continue our journey to get a few useful core components for GameplayKit built, that almost every game will have use for that we write in Swift and using Apple's game frameworks.&lt;/p&gt;

&lt;p&gt;Last time we looked at making a &lt;a href="https://blog.bitbebop.com/gameplaykit-transform-component/"&gt;GameplayKit Transform Component&lt;/a&gt;, so let's pair that component up with a Sprite Component. A sprite and a transform component complement each other and provide a powerful, yet manageable, system to get things moving on screen.&lt;/p&gt;

&lt;p&gt;By having a dedicated component for rendering the visuals of our entities, we get a clear separation of concerns between transformation and the visual representation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Sprite Component
&lt;/h2&gt;

&lt;p&gt;To start off the sprite component, we will have an empty node that will serve as a root that holds one or many child nodes that make up the entity's visuals.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Handles visual representation of an `Entity`.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;SpriteComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// The root node to add children that will be rendered in the scene.&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This makes the sprite component completely stand alone. In my own production code I shared this with my transform component. If you've read my previous article about building a transform component, you might remember that we use an &lt;code&gt;SKNode&lt;/code&gt; there to hold the transformation data. As every entity in my setup always has a transform component, my sprite component references the same &lt;code&gt;SKNode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But for simplicity, in the example we are building here, we will let the sprite have its own. But keep in mind that you can get a very lean and elegant setup by sharing that node between some of the core components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sprite Properties
&lt;/h3&gt;

&lt;p&gt;Let's move on to the basic properties, we are using Swift's computed properties to wrap around some of the built-in properties of &lt;code&gt;SKNode&lt;/code&gt;, and then we add a few additional properties on top of that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Computed property that manages the name of the root node.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Computed property that manages the alpha of the root node.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;alpha&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpha&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;alpha&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Computed property that manages the zPosition of the root node.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;zPosition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zPosition&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To start it off, we basically wrap some common properties from &lt;code&gt;SKNode&lt;/code&gt; that I've found useful to be able to modify from other components that provide the unique behavior for the entity and are by that convenient to have exposed in the component.&lt;/p&gt;

&lt;p&gt;Now let's make it a bit more interesting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Determines if the node is visible in camera.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;inCamera&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;camera&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;camera&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I often need to know if an entity actually is in view or not and can make behavioral decisions for the entity based on that. I've found it incredibly useful to have an &lt;code&gt;inCamera&lt;/code&gt; property available to always be able to check the current state for any entity in the game.&lt;/p&gt;

&lt;p&gt;The next one is &lt;code&gt;isHidden&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;isHidden&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;didSet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isHidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;isHidden&lt;/span&gt;

    &lt;span class="c1"&gt;// Disable physicsbody while hidden to not trigger collisions.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;isHidden&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;physicsBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;physics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;PhysicsComponent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;physicsBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;physics&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;physicsBody&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This could also be a simple wrapper around the property in &lt;code&gt;SKNode&lt;/code&gt; as the first 3 properties were. As many of my entities also have a physics component with a physics body attached to them, I've found this to be the best location to handle that too.&lt;/p&gt;

&lt;p&gt;Setting a sprite to hidden, does not disable its physics body. So by hooking into &lt;code&gt;didSet&lt;/code&gt; in the &lt;code&gt;isHidden&lt;/code&gt; property we can handle enabling and disabling the physics for the entity here, so that is taken care of automatically when we need to hide our entities for one reason or another.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;PhysicsComponent&lt;/code&gt; is part of my core components that I include in every game, so I can pretty much assume in my other core components that the component exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Layering the Sprites
&lt;/h3&gt;

&lt;p&gt;Another crucial part of working with sprites is depth sorting to let SpriteKit know, in which order to stack overlapping sprites on screen.&lt;/p&gt;

&lt;p&gt;I've learned the hard way that manually assigning values to &lt;code&gt;zPosition&lt;/code&gt; for each sprite is a sure way towards losing track of the sorting order. Instead I prefer using a Swift enum to setup predetermined sprite layers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// The names and zPositions of layers in the game scene.&lt;/span&gt;
&lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;GameLayer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;bullet&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;pod&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;enemy&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;600&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;       &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;fx&lt;/span&gt;           &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;800&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;hud&lt;/span&gt;          &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;debug&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1500&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;touchControl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2000&lt;/span&gt;
  &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;overlay&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By using enum cases for the sprites, I ensure that a certain entity type gets consistent depth positioning, and if I want to reorder the layers, I can simply update the enum instead of having to go through every single affected entity.&lt;br&gt;
I might want to move bullets to be in front instead of being behind the player, which I can do directly in the enum.&lt;/p&gt;

&lt;p&gt;The constructor of the sprite component takes &lt;code&gt;GameLayer&lt;/code&gt; as its signature.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GameLayer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;layer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use that when we instantiate a sprite component in an entity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sprite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SpriteComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We pass in the game layer, using Swift's dot syntax, to determine which layer the entity will be rendered on in our gameplay scene.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Life Cycle
&lt;/h3&gt;

&lt;p&gt;We are using the built-in life cycle of &lt;code&gt;GKComponent&lt;/code&gt; that is called when the component is added and removed from an entity, to be able to do some relevant setup and cleanup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didAddToEntity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didAddToEntity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// Assign the entity to the node's entity property.&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;

  &lt;span class="c1"&gt;// Set the sprite root as the entity's node for transformations.&lt;/span&gt;
  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;)?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;SKNode&lt;/code&gt; has an entity property that takes a reference to a &lt;code&gt;GKEntity&lt;/code&gt;. To be able to get a reference to the entity directly from the sprite node is very convenient and useful.&lt;/p&gt;

&lt;p&gt;So we use this location to assign our entity to &lt;code&gt;SKNode&lt;/code&gt; so we can take advantage of that reference through the property.&lt;/p&gt;

&lt;p&gt;Optionally, if planning to share the &lt;code&gt;SKNode&lt;/code&gt; with the transform component, this would be a good place to handle that. In this example I update the transform component to use the node from the sprite component as the root for all transformations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;willRemoveFromEntity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;willRemoveFromEntity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;nil&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeAllActions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeAllChildren&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeFromParent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once it's time to remove the entity and its components from the game, we are good citizens and clean up after ourselves. We remove the entity reference as we don't want to cause any reference retain cycles. And then we stop any actions and clean up the sprite hierarchy.&lt;/p&gt;

&lt;p&gt;That should let us leave the game world in the same pristine condition as when we entered.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sprite Component Methods
&lt;/h3&gt;

&lt;p&gt;With the sprite properties setup, and the life cycle management and initialization in place, we can start adding some useful methods to interact with the component.&lt;/p&gt;

&lt;p&gt;First, we have the &lt;code&gt;add()&lt;/code&gt; methods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Adds a node as a child to the Sprite's root node.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the essential method to actually get some visuals assigned to the sprite component. I use this method to pass in the sprite to render in the component.&lt;/p&gt;

&lt;p&gt;You can keep calling this method to stack up the visuals in side the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sprite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SpriteComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;layer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;debris&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flame&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sparks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the example above, when I define an entity for an explosion effect, I push in 3 different layers to my sprite node to build the entity's visuals.&lt;/p&gt;

&lt;p&gt;Then I've recently come to like to have an additional &lt;code&gt;add(to:)&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Adds the sprite as a child to provided node.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The essential add method doesn't build a hierarchy, and I've had a few cases where I need to keep nesting, and then this method does the trick of adding that option to the component.&lt;/p&gt;

&lt;p&gt;And finally, we need to be able to adjust the hierarchy during runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Moves provided node from its previous parent to be a child of this root node.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;toParent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Moves the root node to be a child of the provided new parent node.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;toParent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Moves the root node to be a child of the root node in another entity.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get the SpriteComponent of the Entity to move to.&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;sprite&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SpriteComponent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Move this root node to be a child of the other entity's root node.&lt;/span&gt;
    &lt;span class="n"&gt;sprite&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;child&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first two move methods are simply wrapping around the move method in &lt;code&gt;SKNode&lt;/code&gt; which are useful to change the hierarchy on demand.&lt;/p&gt;

&lt;p&gt;Then we have our own more unique move method where we can move the visuals to another Entity. So we pass in the other entity, get a reference to that entity's sprite component, and then move our complete visual hierarchy to that entity instead.&lt;/p&gt;

&lt;p&gt;I initially thought this was a special case scenario when I needed it in one game. But when I've started new projects, I've kept reaching for this method, so I've decided to make it a permanent member of the sprite component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;To place the game visuals in a dedicated sprite component helps separate concerns and keep the code decoupled.&lt;/p&gt;

&lt;p&gt;Theoretically we should be able to add a Swift protocol for rendering, &lt;code&gt;RenderingProtocol&lt;/code&gt;, that the sprite component would conform to and we should then be be able to implement a mesh component and swap the game play over to using 3D meshes instead of sprites, without having to modify any other logic in our game entities. Well, theoretically.&lt;/p&gt;

&lt;p&gt;Anyway, to have a dedicated component for the sprite, we get a logical place where to house things like the in camera property.&lt;/p&gt;

&lt;p&gt;Continuing on, the sprite component would pair up nicely with an animation component that would manage animating the textures or handling flip book like animations on top of the sprite component.&lt;/p&gt;

&lt;p&gt;And of course, a physics component that manages the physics properties of the entity and that grabs a reference to the sprite component to add and remove itself to the &lt;code&gt;physicsBody&lt;/code&gt; property of the root node of the sprite component.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>swift</category>
      <category>spritekit</category>
      <category>gameplaykit</category>
    </item>
    <item>
      <title>Game Input System in Swift</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Sat, 28 May 2022 09:48:23 +0000</pubDate>
      <link>https://forem.com/johansteen/game-input-system-in-swift-2gbe</link>
      <guid>https://forem.com/johansteen/game-input-system-in-swift-2gbe</guid>
      <description>&lt;p&gt;Handling player input can be disproportionally difficult. One could think writing complex game algorithms would be the biggest challenge when it comes to game development. Writing an input system that can handle anything from touch to game controllers, mouse and keyboards combined with different devices and operating systems can be a whole mess of edge cases, gray hair, and trial and error.&lt;/p&gt;

&lt;p&gt;I decided to come up with a system once and for all that I could simply drop in to new game projects together with a configuration for how I want the input to work for that game, and then be done with it.&lt;/p&gt;

&lt;p&gt;These are the goals I wanted to achieve with the input system.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Completely decoupled from the game code.&lt;/li&gt;
&lt;li&gt;Highly reusable, preferably a separate package.&lt;/li&gt;
&lt;li&gt;Handle any kind of input device or screen.&lt;/li&gt;
&lt;li&gt;Work for both UI and Gameplay.&lt;/li&gt;
&lt;li&gt;Game code should not depend on which input is currently being used.&lt;/li&gt;
&lt;li&gt;Handle game controllers with relevant related events.&lt;/li&gt;
&lt;li&gt;Not be tied to a specific game framework.&lt;/li&gt;
&lt;li&gt;Have a "swifty" feel when configuring a game's input.&lt;/li&gt;
&lt;li&gt;Layout system to define touch input virtual controller.&lt;/li&gt;
&lt;li&gt;Apply custom artwork for thumbsticks and buttons in the virtual controller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We want to achieve a system that under the hood takes care of all the input handling and completely abstracts it away from the game.&lt;/p&gt;

&lt;p&gt;That is an end to switch or if conditions that checks for keypresses, mouse buttons, touch input and other devices wired up in the actual game code. It should also automatically handle game controller detection and all related events.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KmwmSo2B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxmsm8huc9vitfcyhasb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KmwmSo2B--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rxmsm8huc9vitfcyhasb.jpg" alt="Apple App Store Supports Game Controllers" width="880" height="284"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And of course, we are also going to want to ensure that the input system handles everything required to have the Game Controllers supported badge in Apple's App Store.&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Input Actions
&lt;/h2&gt;

&lt;p&gt;After trying some different concepts and ideas, I ended up going with an action-based approach. The concept is that the game polls or listens to actions instead of directly having to check for device input.&lt;/p&gt;

&lt;p&gt;Examples of actions can be "Jump" or "Move". The game only has to care about if a "Jump" action happened, and does not need to know what button or device that triggered the action to happen.&lt;/p&gt;

&lt;p&gt;The game defines a list of actions it needs for its gameplay and then the input system generates the actions for the game.&lt;/p&gt;

&lt;p&gt;When setting up a new game, each device the game supports is configured how it triggers the actions in the appropriate way for that kind of device.&lt;/p&gt;

&lt;p&gt;Once implemented, I've found this to be a solid approach for a highly decoupled system that ends up with very clean and easy maintainable code when used in a game project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Input Groups
&lt;/h2&gt;

&lt;p&gt;With the concept of Input Actions for a game, we have immediately solved many of the initial list of bullet points that I wanted to achieve.&lt;/p&gt;

&lt;p&gt;We have decoupled the input code from the game code so it can be reused and not tied specifically to a certain game framework. As the game only cares about actions, it does no longer depend on which device is currently generating the input.&lt;/p&gt;

&lt;p&gt;Next, we want to solve different input scenarios. A thumbstick or a D-pad on a game controller might need to be associated with more than one action. During gameplay it is associated with a "Move" action, while when we are displaying a UI to the player we want it to be associated with a "Navigation" action.&lt;/p&gt;

&lt;p&gt;This is the requirement that the system should work for both the UI and Gameplay. We handle that by introducing Input Groups.&lt;/p&gt;

&lt;p&gt;Each action will belong to a group, and only one group can be active at a time. And by switching which input group that is currently active, we can immediately change the input behavior of the game.&lt;/p&gt;

&lt;p&gt;We can have one group of actions for the UI and one group of actions for the gameplay. Then we can simply switch between the UI and Gameplay groups depending on which state the game is in.&lt;/p&gt;

&lt;p&gt;I like to use an approach where I have a finite state machine that tracks the overall game state. By default I set the input system to UI and then I use the enter and exit transitions for my Gameplay state to change the input group. Whenever the game enters &lt;code&gt;GameplayState&lt;/code&gt; I enable the Gameplay input group and whenever it exits &lt;code&gt;GameplayState&lt;/code&gt; I enable the UI input group.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the Input System
&lt;/h2&gt;

&lt;p&gt;Now we have an idea of how the input system should work. Now it's time to deal with the "Swifty" configuration. It was very important for me to come up with an API that I felt comfortable with. Maybe one of the most important aspects of the system, as I wanted it to feel logical and easy to setup the input for each new game.&lt;/p&gt;

&lt;p&gt;I decided on using one struct, &lt;code&gt;InputConfig&lt;/code&gt;, that I will add to each game and this strict will hold the entire input configuration for the game by binding devices with actions.&lt;/p&gt;

&lt;p&gt;So during the game's initialization, preferably when my &lt;code&gt;GameManager&lt;/code&gt; starts up, I'll simply have to create the config, and then the game is ready to use the actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;GameManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Configure input mapping.&lt;/span&gt;
    &lt;span class="kt"&gt;InputConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll keep it simple, all right.&lt;/p&gt;

&lt;p&gt;Then let's take a look at how we define the struct with all the game input mappings. I start by defining the input groups and input actions the game will use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Registers all input actions for the game.&lt;/span&gt;
&lt;span class="kd"&gt;struct&lt;/span&gt; &lt;span class="kt"&gt;InputConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// `Input Group` identifiers.&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;gameplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Gameplay"&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"UI"&lt;/span&gt;

    &lt;span class="c1"&gt;// `Input Action` identifiers.&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;moveAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"move"&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fireAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"fire"&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;jumpAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"jump"&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;pauseAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"pause"&lt;/span&gt;

    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;menuNavigate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"menu navigate"&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;menuSelect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"menu select"&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;menuExit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"menu exit"&lt;/span&gt;

    &lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;debugKill&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"debug kill"&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;debugNextLevel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"debug next level"&lt;/span&gt;
    &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;debugDropItem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"debug drop item"&lt;/span&gt;
    &lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I initially wanted to be able to use an enum for the identifiers, but I couldn't come up with a solid solution when the config also needs to be accessible and parsed by the separate input package. By using &lt;code&gt;static let&lt;/code&gt; we overcome that while still being able to reference them by dot syntax, so we can for instance listen to &lt;code&gt;.moveAction&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In the above example we define two groups that we are going to use, then four different gameplay actions, three UI actions, and finally some additional actions only included in &lt;code&gt;DEBUG&lt;/code&gt; builds that can be useful during play testing.&lt;/p&gt;

&lt;p&gt;This covers everything this example game is supposed to be able to do.&lt;/p&gt;

&lt;p&gt;Up next, we are going to map our actions to different devices. Let's check out the &lt;code&gt;.moveAction&lt;/code&gt; bindings.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;moveAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;moveAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="kt"&gt;GamepadBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leftStick&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="kt"&gt;CompositeKeyBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keySet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wasd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;InputAction&lt;/code&gt; is a core class of my game input system and it does most of the heavy lifting to be the bridge between the game and the input devices. So the InputAction takes three parameters; we need an identifier, a type, and the bindings.&lt;/p&gt;

&lt;p&gt;By identifying it with the &lt;code&gt;static let&lt;/code&gt; name we defined earlier, we get an association between the input action and that name, so we later on always can refer to it with &lt;code&gt;.moveAction&lt;/code&gt; syntax. Then we need to let the action know what kind of input control this is.&lt;/p&gt;

&lt;p&gt;I've added four different types of control to my &lt;code&gt;InputAction&lt;/code&gt; class at this time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.stick&lt;/code&gt; : A analog stick control like the thumbsticks on gamepads.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.button&lt;/code&gt; : A button expressed as a floating-point value.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.d-pad&lt;/code&gt; : A digital button control like the D-pad on gamepads.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.cursor&lt;/code&gt; : A position on the screen like a mouse pointer or Apple Pencil.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we have the bindings, which I provide as an array. In this example I provide bindings for Game controllers and keyboards. Each binding type adopts to an &lt;code&gt;InputBinding&lt;/code&gt; protocol and has its own custom set of possible controller elements relevant for that device binding.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;GamepadBinding&lt;/code&gt; has elements like &lt;code&gt;.leftStick&lt;/code&gt;, &lt;code&gt;.rightStick&lt;/code&gt;, &lt;code&gt;.buttonNorth&lt;/code&gt; and so on.&lt;/p&gt;

&lt;p&gt;While the keyboard has bindings for different keys like &lt;code&gt;p&lt;/code&gt; or &lt;code&gt;shift&lt;/code&gt;. For convenience I added a &lt;code&gt;CompositeKeyBinding&lt;/code&gt; on top of &lt;code&gt;KeyBinding&lt;/code&gt; as I found myself often needing that setup. So above I use a composite key binding and pass in the &lt;code&gt;.wasd&lt;/code&gt; keys.&lt;/p&gt;

&lt;p&gt;And of course, as it is an array, we can use multiple bindings from the same device type for one action. So to expand on the &lt;code&gt;.moveAction&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;moveAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;moveAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stick&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="kt"&gt;GamepadBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leftStick&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="kt"&gt;CompositeKeyBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keySet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wasd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="kt"&gt;CompositeKeyBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keySet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have a second composite binding with the cursor keys, so the player can use any of those keys, according to what they prefer. I use this in other places too, like the &lt;code&gt;.pauseAction&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;pauseAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pauseAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="kt"&gt;GamepadBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;buttonMenu&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="kt"&gt;KeyBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"p"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="kt"&gt;KeyBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Character&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;UnicodeScalar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x1b&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we assign pause to both the &lt;code&gt;p&lt;/code&gt; key and to the &lt;code&gt;esc&lt;/code&gt; key.&lt;/p&gt;

&lt;p&gt;Another example with multiple bindings would be the UI navigation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;navigateAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;menuNavigate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpad&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="kt"&gt;GamepadBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;leftStick&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="kt"&gt;GamepadBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dpad&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="kt"&gt;CompositeKeyBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keySet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;wasd&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="kt"&gt;CompositeKeyBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;keySet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we are giving the player four different options that all work at the same time to navigate the game's menu screens. And the system also handles using an analog left thumb stick as a directional pad input type, like in this case.&lt;/p&gt;

&lt;p&gt;With all the different actions for the game configured, all that remains is to group them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Assign the actions to an input group.&lt;/span&gt;
&lt;span class="kt"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;inputGroup&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="kt"&gt;InputGroup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameplay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;moveAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;jumpAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;fireAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;pauseAction&lt;/span&gt;
  &lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The input system is at its core a singleton, so we easily can access it without having to create an instance. We use that to our advantage, so when the configuration adds its groups to the input system, the system gets automatically initialized and brought alive to start listening for input and invoking actions.&lt;/p&gt;

&lt;p&gt;The game does not need to track an instance of its own for input handling. Setting up the config is all the game needs to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Touch Input
&lt;/h2&gt;

&lt;p&gt;In the previous example I didn't touch on the subject of assigning any bindings for touch controls, no pun intended.&lt;/p&gt;

&lt;p&gt;Binding actions to touch controllers works just the same. In the most basic setup, using the built-in default flat shapes as art, it would be added exactly like any other binding, with the addition of positioning the button on screen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fireAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fireAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;bindings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="kt"&gt;TouchButtonBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;horizontal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this works and the layout system takes things like margins and safe area into account, it's still too limited. I want to be able to make much more custom layouts with custom artwork.&lt;/p&gt;

&lt;p&gt;In a real scenario, I need a setup more like this, which is a controller from a game I'm currently working on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Bowuo9T---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pjzg59ljtgb1m0f82pbk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Bowuo9T---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pjzg59ljtgb1m0f82pbk.png" alt="Virtual Touch Controller Layout" width="880" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make a layout like this happen, the &lt;code&gt;TouchInputBinding&lt;/code&gt; struct have quite a few more parameters than the keyboard and mouse have.&lt;/p&gt;

&lt;p&gt;Setting up the previous devices has turned out to be quite a nice and neat piece of configuration code that is easy to overview. I didn't want to visually pollute the code with the touch bindings. So I added a method where I can add more bindings to an existing input action.&lt;/p&gt;

&lt;p&gt;By that I can make a choice, if I want to add the touch input bindings together with the other devices, or tag them on separately at the end. So far I've always tagged them on separately, so I can deal with layout, art, and so on in the same location.&lt;/p&gt;

&lt;p&gt;So in reality, when I do a full layout the configuration for a touch element will need an artwork reference, position, and size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Size shared by all buttons.&lt;/span&gt;
&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;buttonSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CGSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Setup the texture reference&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fireButtonGlyph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;TouchControllerTexture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Fire Button"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;buttonSize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nv"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;named&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"Fire Button"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="c1"&gt;// Add the binding to an existing action.&lt;/span&gt;
  &lt;span class="n"&gt;fireAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nv"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TouchButtonBinding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nv"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Position&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;horizontal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buttonSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nv"&gt;vertical&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;top&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buttonSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
      &lt;span class="nv"&gt;button&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TouchButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nv"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;fireButtonGlyph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nv"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TouchControllerTexture&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zero&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;none&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nv"&gt;pressedColor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;white&lt;/span&gt;
  &lt;span class="p"&gt;)))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The layout system still has room for improvements and is not yet as sophisticated as it could be. On the top of my list is to add a rule system so one element can be placed in relation to another element, and specify a vector with an offset.&lt;/p&gt;

&lt;p&gt;That would make tweaking and rearranging the layout much easier. But for now I've got by with these options where I can set the major screen location and then tweak that position that can take an additional adjustment value.&lt;/p&gt;

&lt;p&gt;Every touch element can take a background texture, which I in this example do not use, as the element provided its own.&lt;/p&gt;

&lt;p&gt;Once all elements are registered with the system, all assets are combined into one single texture in memory during runtime to reduce draw calls and batching for optimal performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Input System in a Game
&lt;/h2&gt;

&lt;p&gt;With the configuration done it's time to use the actions in our game. This is where we get rewarded. Not only is it easy to use the actions from this point on, we can also remap actions to new buttons or add new bindings without having to touch any of the game code.&lt;/p&gt;

&lt;p&gt;I prefer to use patterns in the line of delegates, so we are listening for events and don't do any kind of processing until an event actually occurs.&lt;/p&gt;

&lt;p&gt;In opposite to a polling system where we need to do some tiny processing on each update loop to see if an event has occurred.&lt;/p&gt;

&lt;p&gt;I implemented both options in the input system as I find them both useful for different reasons. I want to listen to the action event once I'm done implementing an input-dependent feature. At the same time, I find it convenient to have a polling option when I just quickly want to test something without having to add code for delegates or listen to an event.&lt;/p&gt;

&lt;p&gt;I also added support for analog events on everything. So I can always choose if I want to get a digital value or an analog value. That is, I can get a value that the button was pressed, or if needed I can also get the value of how hard the button was pressed.&lt;/p&gt;

&lt;p&gt;Taking the &lt;code&gt;.button&lt;/code&gt; input type as an example, we've 3 possible states to query about.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;triggered&lt;/code&gt;: Triggered is set on the frame, the button is pressed down.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;released&lt;/code&gt;: Released is set on the frame, the button is released.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;value&lt;/code&gt;: Value always holds the value of how much the button is pressed down, in the 0.0 - 1.0 range.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Polling for Input Actions
&lt;/h3&gt;

&lt;p&gt;Let's start by looking at an example where we poll an input action for an event.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;InputComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fireAction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;InputConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameplay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;InputConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fire&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt; &lt;span class="nv"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;fireAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;triggered&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Do something...&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We grab a reference to the action we are interested in, then we use the game's update loop to check the state of that action.&lt;/p&gt;

&lt;p&gt;As soon as some form of input device makes the input system trigger a fire action event, our condition will be true and we can run the code relevant for a fire action in out game.&lt;/p&gt;

&lt;p&gt;If I'm more interested in getting the analog value for an action I can use the &lt;code&gt;getValue()&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;fireValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fireAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"fire:"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fireValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Different input types return different value types. A &lt;code&gt;.stick&lt;/code&gt; input will return a &lt;code&gt;CGVector&lt;/code&gt; while a &lt;code&gt;.button&lt;/code&gt; input will return a &lt;code&gt;CGFloat&lt;/code&gt;. The &lt;code&gt;getValue()&lt;/code&gt; method is a generic method, so we have to cast it to the type we expect the action to return.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listen for Input Actions
&lt;/h3&gt;

&lt;p&gt;Polling is nice and convenient to make quick tests or prototype things. In the end, listening to actions is what I most likely will use, which is also supported by the input system.&lt;/p&gt;

&lt;p&gt;Each action can be assigned a delegate, so it's actually more or less dead simple to set up a listener.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;SomeComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;map&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;InputConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameplay&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;InputConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;moveAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;moveDidChange&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;moveDidChange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;inputAction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;InputAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;movement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGVector&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inputAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getValue&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Do something with the movement value.&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get a reference back to the &lt;code&gt;InputAction&lt;/code&gt; when the action is triggered, so we can cast and read the value and update our game state based on the input value.&lt;/p&gt;

&lt;h3&gt;
  
  
  Switching Input Group
&lt;/h3&gt;

&lt;p&gt;And finally, we are going to look at switching groups. As discussed earlier, we most likely are going to want to switch between UI input and gameplay input whenever we change between a gameplay state and the other states the game can be in.&lt;/p&gt;

&lt;p&gt;I prefer to handle that with a state machine for my game states.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;PlayingState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GameSceneState&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didEnter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;previousState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKState&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableActionMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;InputConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gameplay&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;willExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;nextState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Input&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shared&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableActionMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;InputConfig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ui&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example we change the input group each time we enter and exit the playing state of the game. Easy!&lt;/p&gt;

&lt;p&gt;And that's all the code to get all the input setup in a game that I need. All the remaining code from dealing with game controllers to keyboards to actually handling input and interaction with devices, lives in my reusable Swift package.&lt;/p&gt;

&lt;h2&gt;
  
  
  Under the Hood
&lt;/h2&gt;

&lt;p&gt;We have now looked at the concepts and ideas of how to make a rock-solid, decoupled and device-independent input system for games that is easy to interact with and setup from the game's code base.&lt;/p&gt;

&lt;p&gt;The actual inner workings that provide the different classes and value types we use are contained in my Game Input System Swift Package. To dive into the core of my library would be a bit too much for an article like this, we would turn it into a book.&lt;/p&gt;

&lt;p&gt;Instead, I hope my walkthrough how I've set up my system. My thinking behind the different choices I made and how I interact with the system is enough so you can build an input system and fill in the blanks to build it in your own way with how you prefer to interact with your system.&lt;/p&gt;

&lt;p&gt;And that my system can serve as a starting point to get your ideas flowing, and that you might get some insight to do things in ways you might not have thought of otherwise.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Core Structure
&lt;/h3&gt;

&lt;p&gt;My core structure is built around protocols and value types so I can easily extend it with new features and add new devices in the future.&lt;/p&gt;

&lt;p&gt;The most important protocols, classes and value types that could be useful to consider if building an input system with a similar approach as I've done.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;InputDevice&lt;/code&gt;: This is a protocol that provides the basic ins and outs to communicate with any kind of input device. So any new device type implements this protocol and makes it possible for the system to interact with the device. So any class like &lt;code&gt;Gamepad&lt;/code&gt;, &lt;code&gt;Mouse&lt;/code&gt; or &lt;code&gt;Touch&lt;/code&gt; adapts to this protocol and this is where the unique code is to translate between the device and the input system.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;InputBinding&lt;/code&gt;: Is a protocol that holds a reference to the &lt;code&gt;InputAction&lt;/code&gt; it belongs to and is adapted by Input devices to provide the unique elements. This is the bridge to how the input device passes along an event to an &lt;code&gt;InputAction&lt;/code&gt; so the event can be triggered for the game to use. We have things like &lt;code&gt;GamepadBinding&lt;/code&gt; and &lt;code&gt;KeyInputBinding&lt;/code&gt; that provide their own unique implementation to bridge between the device and the action.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;InputAction&lt;/code&gt;: This is the working class hero. This is where all device events end up; the values are processed and also transformed when necessary. For instance, there can be processing of input smoothing or calculation of analog values on digital-only devices based on time since triggered. This is where the game can query for current values and check the state of actions at any time.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;InputGroup&lt;/code&gt;: This value type organizes and toggles the actions associated with the group.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These four are the core functionality of the system. On top of them is the &lt;code&gt;Input&lt;/code&gt; singleton that makes it easy to interact with the package, and that's pretty much it.&lt;/p&gt;

&lt;p&gt;Then there are quite a lot of additional code to handle special cases like laying out the virtual touch input controller and everything related to that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Making the gameplay logic and algorithms is the easy part of game development. Making input systems is hard, but it pays off and is well worth the time to get it done right.&lt;/p&gt;

&lt;p&gt;Then there's always the management of UI states... But that's a story for another day.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Transform Component in GameplayKit</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Sat, 21 May 2022 17:47:34 +0000</pubDate>
      <link>https://forem.com/johansteen/transform-component-in-gameplaykit-h9i</link>
      <guid>https://forem.com/johansteen/transform-component-in-gameplaykit-h9i</guid>
      <description>&lt;p&gt;In every new game project I have a few components which are part of my reusable core functionality that I always include. To have a set of GameplayKit based components that provide common functionality most games require can save a great deal of time once implemented.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-- Shared
  +-- Entities
  +-- Components
    +-- Core
          InputComponent.swift
          PhysicsComponent.swift
          RemoveComponent.swift
          SpriteComponent.swift
          TransformComponent.swift
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Last time we looked at implementing a &lt;a href="https://blog.bitbebop.com/gameplaykit-remove-component/"&gt;GameplayKit Remove Component&lt;/a&gt; and now the time has come to see how we can implement a transform component.&lt;/p&gt;

&lt;p&gt;Almost every entity I create needs transformations in one way or another, so to have a rock-solid and robust transform component that is easily accessible everywhere where it makes sense, has turned out to be incredible helpful.&lt;/p&gt;

&lt;p&gt;The purpose of the transform component is to give ourselves a clean and logical API that wraps around useful transform related functions similar to how the major game engines do it.&lt;/p&gt;

&lt;p&gt;This will provide us with a system where the transform interaction is fully decoupled from the visual representation of the game entity. Clean, single responsible components, help us to get better structured and more maintainable code.&lt;/p&gt;

&lt;p&gt;Apart from handling the obvious properties position, rotation and scale, we also get a location in the game code where we can put anything related to overall transformation handling that is useful for more than one entity.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Transform Component
&lt;/h2&gt;

&lt;p&gt;To start off the transform component we will have an empty node that will serve as a container that holds the transform properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Handles transformations for an `Entity`.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;TransformComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;/// Reference to the node that holds the transformations.&lt;/span&gt;
    &lt;span class="c1"&gt;///&lt;/span&gt;
    &lt;span class="c1"&gt;/// We assign an empty node by default so an entity can have transformations&lt;/span&gt;
    &lt;span class="c1"&gt;/// without having a sprite node assigned to it.&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;lazy&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To ensure that our transform component can always hold transformations, we instantiate an empty SpriteKit &lt;code&gt;SKNode&lt;/code&gt; by default. We do it lazily as we only want to create the empty node if we actually need it.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;node&lt;/code&gt; property can be used differently, depending on the game and the entities needs. Many times I let my &lt;code&gt;SpriteComponent&lt;/code&gt; set itself as the node in the transform component, which is the reason why we want it to be lazy.&lt;/p&gt;

&lt;p&gt;Other times I might keep the empty &lt;code&gt;SKNode&lt;/code&gt; and use it as a parent for the sprites it transforms. So it's a case-by-case scenario.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transform Properties
&lt;/h3&gt;

&lt;p&gt;Let's move on to the basic properties, where we wrap the transform component around the properties of &lt;code&gt;SKNode&lt;/code&gt; with some added sugar on top.&lt;/p&gt;

&lt;p&gt;First, we have the position.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// The position of the entity's node in its parent's coordinate system.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGPoint&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Computed world position from parent's coordinate system.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;worldPosition&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGPoint&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/*
      Use parent's coord system.
      Convert this node's local position to the world node's coord system.
      */&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;world&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;newValue&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The position property is simply a wrapper around the position property in &lt;code&gt;SKNode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;More interesting is the world position. I use the &lt;code&gt;worldPosition&lt;/code&gt; property all the time and I find it very useful to have a wrapper around reading and setting the position in world space.&lt;/p&gt;

&lt;p&gt;So by having both a &lt;code&gt;position&lt;/code&gt; and a &lt;code&gt;worldPosition&lt;/code&gt; property as part of the transform component, it becomes dead simple to work with the position of entities in both local and world space.&lt;/p&gt;

&lt;p&gt;Next, moving on to rotation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// The Euler rotation about the z axis (in radians).&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;rotation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zRotation&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zRotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not much to say here; the rotation property simply wraps around the &lt;code&gt;zRotation&lt;/code&gt; property in &lt;code&gt;SKNode&lt;/code&gt;. I haven't yet had any reason to add any other options here.&lt;/p&gt;

&lt;p&gt;If you prefer working with degrees instead of radians, you could add a conversion for doing that here.&lt;/p&gt;

&lt;p&gt;And finally, we have the scale.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// A scaling factor that multiplies the size of an entity.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGSize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xScale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yScale&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;set&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
    &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newValue&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Get accumulated size of the entity.&lt;/span&gt;
&lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGSize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculateAccumulatedFrame&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I prefer to work with scale by having it contained in one &lt;code&gt;CGSize&lt;/code&gt; value instead of working with each axis separately. So the scale property wraps a &lt;code&gt;CGSize&lt;/code&gt; value around &lt;code&gt;xScale&lt;/code&gt; and &lt;code&gt;yScale&lt;/code&gt; in &lt;code&gt;SKNode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then the additional &lt;code&gt;size&lt;/code&gt; attribute calculates the total size of everything added to the hierarchy of the node. One use for this is to get the size in Physics Component when setting up the physics properties.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transform Methods
&lt;/h3&gt;

&lt;p&gt;With the transform properties setup, we can start adding useful methods to interact with the component.&lt;/p&gt;

&lt;p&gt;I've a &lt;code&gt;set(node:)&lt;/code&gt; method that I use for updating which node that the transform component uses for holding its properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Set the node that holds the transformation values.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Transfer attributes from the previous referenced node to the new.&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zRotation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;zRotation&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;xScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;width&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scale&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;height&lt;/span&gt;

  &lt;span class="c1"&gt;// Set self.node to reference the new node.&lt;/span&gt;
  &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transform component might already have values assigned to its properties, so when setting a new node I transfer the properties from the node that previously was responsible for holding the properties to the new node.&lt;/p&gt;

&lt;p&gt;This is a design consideration that I've been juggling a bit back and forth with. And I'm still not 100% sure if this is the way I'm going to keep it or if I might revise it in the future.&lt;/p&gt;

&lt;p&gt;I've been considering using another approach where the transform class has its own properties for position, rotation and scale instead of using a node to hold those properties. But so far I've found it more useful to have it in the node, and also simpler to work with. So for now, I'll stick to this approach.&lt;/p&gt;

&lt;p&gt;And then finally, we can start decorating the component with useful methods to simplify making transforms on our game entities.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Moves the transform in the direction and distance of translation.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGVector&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;/// Run an animation SKAction on the node.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the structure for the transform component in place, there is no limit to different methods that are useful for transformations in game development that we can keep adding to this class.&lt;/p&gt;

&lt;p&gt;I'll get the ball rolling with two example methods.&lt;/p&gt;

&lt;p&gt;In any component that handles movement logic for our game entities, we can use the translate method to quickly execute the movement on screen. If the component has a direction and speed, we can simply pass in the formula to the transform component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;translate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is something I use all the time. To be able to simple get the delta time anywhere in your game code as in my example above, you can check out my article on writing a class for &lt;a href="https://blog.bitbebop.com/deltatime-spritekit-swift/"&gt;Game Time in Swift&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another method that I find useful is to have a &lt;code&gt;run()&lt;/code&gt; method where I can execute &lt;code&gt;SKActions&lt;/code&gt; on the entity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;actionA&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;actionB&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use this for animations, but I also use it quite often to quickly be able to run time-based logic on a game entity. For instance, on an explosion entity I would start a run action with a completion action that adds a remove component when the explosion is done.&lt;/p&gt;

&lt;h2&gt;
  
  
  Accessing the Transform Component
&lt;/h2&gt;

&lt;p&gt;With the transform component done and ready to be used in our game entities, we need to make sure we can easily get hold of a reference to it.&lt;/p&gt;

&lt;p&gt;The transform component is something I use all the time. Not only for moving the objects on the screen, but I also need to read the transformation data for all kinds of different logic. It could be anything from a behavior system to handling trigger-based events.&lt;/p&gt;

&lt;p&gt;More or less every game entity will require the transform component, so I've made it a part of my base class for entities. Which ensures that the rest of the game systems can count on that there will always be a transform component available.&lt;/p&gt;

&lt;p&gt;I create my own base class for that all game entities inherit from, which is on top of &lt;code&gt;GKEntity&lt;/code&gt; in GameplayKit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKEntity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// Transform Component.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;transform&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;TransformComponent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;// Every entity has a transform component.&lt;/span&gt;
    &lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As every entity in the game inherits this &lt;code&gt;Entity&lt;/code&gt; class instead of using &lt;code&gt;GKEntity&lt;/code&gt; directly, they all automatically get the transform component added.&lt;/p&gt;

&lt;p&gt;We also want to make sure that every game component has quick and easy access to its entity's transforms. So just as we did our own &lt;code&gt;Entity&lt;/code&gt; class instead of using &lt;code&gt;GKEntity&lt;/code&gt;, we will use our own &lt;code&gt;Component&lt;/code&gt; class instead of using &lt;code&gt;GKComponent&lt;/code&gt;&lt;br&gt;
in GameplayKit directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// Hold a reference to the entity's TransformComponent.&lt;/span&gt;
  &lt;span class="kd"&gt;lazy&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;transform&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TransformComponent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt;
      &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;fatalError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The component must be added to an Entity."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;transform&lt;/span&gt;
  &lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want it to be dead simple to get hold of the transform component everywhere where it makes sense, and that is in other game components.&lt;/p&gt;

&lt;p&gt;By having a lazy property we get the reference to the transform component first time it's used, and then the reference is kept for in the property, which is good for performance.&lt;/p&gt;

&lt;p&gt;Now every component in an entity has direct access to its transform, and we can write code like this anywhere without having to first find the transform component or having to worry about which SpriteKit node to interact with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;transform&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;newPosition&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Powerful and convenient at the same time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Next
&lt;/h2&gt;

&lt;p&gt;With the basic structure for the transform component in place, we can continue decorating it with methods to keep increasing its usefulness. We've just scratched the surface of what methods to include.&lt;/p&gt;

&lt;p&gt;I'll put some ideas on the table that I believe would be useful. What first comes to mind would be to add a property and related methods to simplify the handling of the parent-child relationship between game entities.&lt;/p&gt;

&lt;p&gt;I can also see that including methods for both local and world space operations for rotations and scale would be of use. It would probably also be convenient to add methods that rotate towards a direction and/or move towards a specific position. And the list could go on.&lt;/p&gt;

&lt;p&gt;Enjoy leveling up your gamedev with a powerful transform component.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>gamedev</category>
      <category>gameplaykit</category>
      <category>spritekit</category>
    </item>
    <item>
      <title>Batch Remove System for GameplayKit Entities</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Sat, 14 May 2022 13:27:59 +0000</pubDate>
      <link>https://forem.com/johansteen/batch-remove-system-for-gameplaykit-entities-22hc</link>
      <guid>https://forem.com/johansteen/batch-remove-system-for-gameplaykit-entities-22hc</guid>
      <description>&lt;p&gt;In most games, objects are being added and removed from the game world as the game progresses. This is an operation that affects memory usage and also triggers possible garbage collection.&lt;/p&gt;

&lt;p&gt;I was looking for a solution to be able to remove objects in batches instead of having custom code that handles removal of objects scattered throughout my games.&lt;/p&gt;

&lt;p&gt;I came up with a solution based on using a component together with a component system in GameplayKit.&lt;/p&gt;

&lt;p&gt;By removing objects in batches I get control of exactly then during the game's update loop removal of objects are happening and also get the code better structured and performant to do these operations that affects memory in one go instead of being fragmented during the frame cycle.&lt;/p&gt;

&lt;p&gt;It has also allowed me to get cleaner and more consolidated code with a single location that handles the removal of objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Remove Component
&lt;/h2&gt;

&lt;p&gt;The remove component is super simple; all it does is add itself to a component system, so it can be processed later.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;import&lt;/span&gt; &lt;span class="kt"&gt;GameplayKit&lt;/span&gt;

&lt;span class="c1"&gt;/// Flags an entity to be removed from the game.&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;RemoveComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// MARK: Component Life Cycle&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didAddToEntity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didAddToEntity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;// Register with the removeComponentSystem.&lt;/span&gt;
        &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;removeComponentSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use &lt;code&gt;didAddToEntity()&lt;/code&gt; to run our code automatically as soon as we add the component to an entity.&lt;/p&gt;

&lt;p&gt;The component system the remove component adds itself to is defined in the scene class where the game runs. As almost all my entities and their added components needs to reference the scene file, I'm letting all my entities have a reference to the scene, and then I don't use &lt;code&gt;GKComponent&lt;/code&gt; directly but an extended version with a helper property so I always can reference the scene from components.&lt;/p&gt;

&lt;p&gt;It looks something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// MARK: Convenience Properties&lt;/span&gt;

    &lt;span class="c1"&gt;/// The scene the owning entity is added to.&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;scene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GameScene&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;)?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;RemoveComponent&lt;/code&gt; is a child of my &lt;code&gt;Component&lt;/code&gt; and not &lt;code&gt;GKComponent&lt;/code&gt; so I can use the &lt;code&gt;scene&lt;/code&gt; property in &lt;code&gt;didAddToEntity()&lt;/code&gt; method.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Component System
&lt;/h2&gt;

&lt;p&gt;In my game scenes where I define my different component systems, I've setup a dedicated &lt;code&gt;GKComponentSystem&lt;/code&gt; which only has the purpose of handling removals of entities from the game.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;GameScene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKScene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// MARK: Component Systems&lt;/span&gt;

  &lt;span class="c1"&gt;/// Component System to remove entities from the game.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;removeComponentSystem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;GKComponentSystem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;componentClass&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;RemoveComponent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the life cycle of &lt;code&gt;SKScene&lt;/code&gt; &lt;sup id="fnref1"&gt;1&lt;/sup&gt; &lt;code&gt;didFinishUpdate()&lt;/code&gt; is the last method called just before the wait for the next frame begins. That method should be a great choice for us to use for the removal of our objects from the game.&lt;/p&gt;

&lt;p&gt;At this time everything in the game is done executing during this update loop, so we end this cycle by batch removing all objects flagged for removal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didFinishUpdate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;didFinishUpdate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// Remove entities flagged for removal.&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;removeComponentSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Remove the entity and it's resources.&lt;/span&gt;
      &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When iteration through the remove component system to get a reference for each entity that has the &lt;code&gt;RemoveCompenent&lt;/code&gt; added, we call a remove method that has the actual logic to remove each entity from the game world.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;remove()&lt;/code&gt; method would most likely be unique for each game project. For me, I usually end up with something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Removes an entity from the game world.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Remove sprite component as that removes the nodes from the scene.&lt;/span&gt;
  &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SpriteComponent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Remove the reference from the entities set.&lt;/span&gt;
  &lt;span class="n"&gt;entities&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I use a &lt;code&gt;GKComponent&lt;/code&gt; that handles the sprite and it knows how to visually remove itself from the game world in the &lt;code&gt;willRemoveFromEntity()&lt;/code&gt; method that is automatically called when a component is removed.&lt;/p&gt;

&lt;p&gt;I keep a set with references to all entities currently in the game world, which I remove the entity from.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using the Remove Component
&lt;/h2&gt;

&lt;p&gt;That's basically it; the only thing that remains is to actually start using the &lt;code&gt;RemoveComponent&lt;/code&gt; when we need to flag an object for removal.&lt;/p&gt;

&lt;p&gt;All we have to do to remove an object from the game is to add the &lt;code&gt;RemoveComponent&lt;/code&gt; to the entity.&lt;/p&gt;

&lt;p&gt;Let's say that we have a bullet in the scene and we want to remove it when it hits its target. Then we simply can add the &lt;code&gt;RemoveComponent&lt;/code&gt; in the &lt;code&gt;contactDidBegin&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;contactDidBegin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="nv"&gt;other&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKEntity&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKPhysicsContact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Flag the bullet for removal.&lt;/span&gt;
  &lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;RemoveComponent&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or we might have a particle emitter with a lifetime of 1.5 seconds that we want to remove when done playing. Then we could add the &lt;code&gt;RemoveComponent&lt;/code&gt; by using an &lt;code&gt;SKAction&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;// remove emitter when done&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;wait&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;forDuration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;remove&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
    &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addComponent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;RemoveComponent&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use the run &lt;code&gt;SKAction&lt;/code&gt; and a sequence to add the &lt;code&gt;RemoveComponent&lt;/code&gt; after the specified time has elapsed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to Next
&lt;/h2&gt;

&lt;p&gt;With this structure in place where we have a separate system that tracks objects for removal, it would be interesting to keep building on this concept to separate some of this logic away from the game loop.&lt;/p&gt;

&lt;p&gt;For instance, we could potentially see if it was possible to use a background thread to iterate through the component system to get more time left on the main thread used by the game for a performance increase.&lt;/p&gt;

&lt;p&gt;But that's a project for another day.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/spritekit/skscene/responding_to_frame-cycle_events"&gt;SKScene Life Cycle&lt;/a&gt;. Responding to Frame-Cycle Events. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>swift</category>
      <category>gamedev</category>
      <category>spritekit</category>
      <category>gameplaykit</category>
    </item>
    <item>
      <title>Better Time Management in SpriteKit</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Sun, 08 May 2022 11:01:06 +0000</pubDate>
      <link>https://forem.com/johansteen/better-time-management-in-spritekit-474n</link>
      <guid>https://forem.com/johansteen/better-time-management-in-spritekit-474n</guid>
      <description>&lt;p&gt;Time management and the usage of delta time is one of the most important and fundamental parts for most game projects as it ensures consistency of any on-screen transforms no matter what the device's frame rate is that the game runs on.&lt;/p&gt;

&lt;p&gt;More or less any form of movement, rotation or time-related calculation should take delta time into account to ensure it's not dependent on the frame rate.&lt;/p&gt;

&lt;p&gt;Without using delta time, a bullet in a game, as an example, would move at a different speed on a 120 fps device compared to a 60 fps device.&lt;/p&gt;

&lt;h2&gt;
  
  
  Delta Time in SpriteKit
&lt;/h2&gt;

&lt;p&gt;SpriteKit does not give us a delta time value out of the box, which is unfortunate considering how useful it is.&lt;/p&gt;

&lt;p&gt;It's not that the game framework engineers at Apple are not aware of delta time, as the &lt;code&gt;GKComponent&lt;/code&gt; in GameplayKit requires delta time in its &lt;code&gt;update(deltaTime:)&lt;/code&gt; method. But you have to calculate the value yourself.&lt;/p&gt;

&lt;p&gt;At the same time as it's unfortunate that SpriteKit does not provide delta time out of the box, it's also understandable that the GameplayKit engineers deemed &lt;code&gt;deltaTime&lt;/code&gt; as a requirement when calling the update method, as a component will most likely need to use delta time in one way or another.&lt;/p&gt;

&lt;p&gt;And of course, if not using GameplayKit but only plain SpriteKit, you are going to need to use a delta time for your on-screen calculations to ensure consistency no matter what frame rate the device runs on.&lt;/p&gt;

&lt;p&gt;SKScene provides the current time value, so most likely you are using or have seen solutions similar to this to get the delta time value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;GameplayScene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKScene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// Keeps track of how much time has passed since last game loop update.&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;lastUpdateTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Get delta time since last time `update` was called.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;deltaTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateDeltaTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;/// Calculates time passed from current time since last update time.&lt;/span&gt;
  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;calculateDeltaTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// When the level is started or after the game has been paused, the last update time is reset to the current time.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;lastUpdateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isZero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;lastUpdateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Calculate delta time since `update` was last called.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;deltaTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;lastUpdateTime&lt;/span&gt;

    &lt;span class="c1"&gt;// Use current time as the last update time on next game loop update.&lt;/span&gt;
    &lt;span class="n"&gt;lastUpdateTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;deltaTime&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the life cycle of this &lt;code&gt;SKScene&lt;/code&gt; we get the current time provided in the update method. By storing the current time value in the class property &lt;code&gt;lastUpdateTime&lt;/code&gt;, we are able to keep track of how much time that has elapsed since the last time the update method was called, and by that we have our delta time value.&lt;/p&gt;

&lt;p&gt;We can then take this value and keep passing it along to other methods or systems that need to use delta time for their calculations.&lt;/p&gt;

&lt;p&gt;Which could look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;deltaTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateDeltaTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Update the bullet system that handle movement of all bullets on screen.&lt;/span&gt;
  &lt;span class="n"&gt;bulletSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Update each GameplayKit component system.&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;componentSystem&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;componentSystems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;componentSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each system, component or object that uses delta time will then have to accept the value in its method signature, and then pass it along further down the chain to its own methods that relies on delta time. You most likely will not want to keep all your logic in the update method, as it could grow massive, but structure the logic in dedicated methods.&lt;/p&gt;

&lt;p&gt;We then end up with components like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;MoveComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... Initialization and references to other components of the entity here ...&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt; &lt;span class="nv"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;funct&lt;/span&gt; &lt;span class="nf"&gt;move&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt; &lt;span class="nv"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we have a move method in the component that moves the entity's position at a speed and direction that is not dependent on the device frame rate as we multiply the resulting velocity with our delta time value. As delta time is passed as a &lt;code&gt;TimeInterval&lt;/code&gt; we have to cast it to an appropriate format, like &lt;code&gt;CGFloat&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Most games will of course not only use the update method in SKScene, but will need to use the other methods in the life cycle, such as &lt;code&gt;didSimulatePhysics&lt;/code&gt; or &lt;code&gt;didFinishUpdate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Those methods do not get the current time injected, so we are going to have to promote the &lt;code&gt;deltaTime&lt;/code&gt; property to a class property to be able to access and use delta time in those scenarios.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;GameplayScene&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKScene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;deltaTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculateDeltaTime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;from&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didSimulatePhysics&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Update camera movemement.&lt;/span&gt;
    &lt;span class="n"&gt;camera&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Update each 'after physics' component system.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;componentSystem&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;afterPhysicsComponentSystems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;componentSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this is an approach that does the job, and SpriteKit provides us with the necessary data to deal with delta time, it's quite convoluted.&lt;/p&gt;

&lt;p&gt;We are mixing the time logic with the scene logic. And as every calculation that affects what happens on the screen, which is a lot in most games, relies on delta time, we are going to have to keep passing the value around between systems, classes and methods.&lt;/p&gt;

&lt;p&gt;We might also have multiple scenes, even running at the same time, which happens when transitioning between scenes, which would create multiple delta time calculations at the same time.&lt;/p&gt;

&lt;p&gt;The more complex a game becomes, with more systems and classes, the more this approach will feel to start falling apart. Let's find a better way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Game Engines
&lt;/h2&gt;

&lt;p&gt;Looking at modern game engines such as Unity and Unreal, they calculate delta time as a core functionality and the value is made available to use where you need it. It makes sense that any framework that targets game development makes this available.&lt;/p&gt;

&lt;p&gt;If we for instance take a closer peek at Unity, it provides a Time class&lt;sup id="fnref1"&gt;1&lt;/sup&gt; that has static properties containing time-related data.&lt;/p&gt;

&lt;p&gt;By that, you never have to pass any time information around in your game code. Instead, you can at any time do a calculation like this, by just statically accessing the &lt;code&gt;deltaTime&lt;/code&gt; property of &lt;code&gt;Time&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;direction&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="n"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's apparent that they decided that something so crucial and that is used so often in game development should be calculated under the hood and be easily available at any time, which making it static solves.&lt;/p&gt;

&lt;p&gt;The time class in Unity does not only provide &lt;code&gt;deltaTime&lt;/code&gt; as a static property but has a ton of different useful time-related information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Swift Class for Static Time
&lt;/h2&gt;

&lt;p&gt;We have now examined the ordinary approach to dealing with delta time in SpriteKit as well as taken a peek at how modern game engines handle it. So let's aim for a similar approach in SpriteKit for a better way to easily get access to time information via static properties.&lt;/p&gt;

&lt;p&gt;We'll take inspiration from Unity and see how we can have a &lt;code&gt;Time&lt;/code&gt; class available in SpriteKit with static properties that are not tied to the current scene's update loop.&lt;/p&gt;

&lt;p&gt;The static class will need to hold relevant properties together with an &lt;code&gt;update()&lt;/code&gt; method to keep the values current.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Tracks the game's time-related information.&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;Time&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// The time given at the beginning of this frame.&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;/// The interval in seconds from the last frame to the current one.&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;deltaTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;/// Called on the device's frame update to track time properties.&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="nv"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;//  If `time` is 0.0 the game has just started, so set it to `currentTime`.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isZero&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Calculate delta time since `update(at:)` was last called.&lt;/span&gt;
    &lt;span class="n"&gt;deltaTime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

    &lt;span class="c1"&gt;// Set `time` to `currentTime for next game loop update.&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;currentTime&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gives us the &lt;code&gt;Time&lt;/code&gt; class with the static properties and a method to keep them up to date. Now we just need a place to call the &lt;code&gt;update()&lt;/code&gt; method. The first thought might be to call it from &lt;code&gt;update()&lt;/code&gt; in &lt;code&gt;SKScene&lt;/code&gt;. Which would work most of the time.&lt;/p&gt;

&lt;p&gt;We do get one problem if we do it from &lt;code&gt;SKScene&lt;/code&gt;, at some times we might have more than one scene running, for instance when transitioning between two scenes. That would cause a race condition when then they would both update &lt;code&gt;Time&lt;/code&gt;, which will give us an incorrect &lt;code&gt;deltaTime&lt;/code&gt; for one of the scenes.&lt;/p&gt;

&lt;p&gt;We also want to keep our code clean and not have to remember to call &lt;code&gt;Time.update()&lt;/code&gt; in every scene class we create, as well as we want to avoid polluting the scene class with code that doesn't have to be there.&lt;/p&gt;

&lt;p&gt;Luckily &lt;code&gt;SKView&lt;/code&gt; has a delegate property that we can use for this. The delegate property takes an &lt;code&gt;SKViewDelegate&lt;/code&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt; object, which gives us the hook we need to have a place to calculate time values outside the scene class.&lt;/p&gt;

&lt;p&gt;Let's create our own &lt;code&gt;Ticker&lt;/code&gt; class, which is an &lt;code&gt;SKViewDelegate&lt;/code&gt; so we can update our &lt;code&gt;Time&lt;/code&gt; class. The &lt;code&gt;view()&lt;/code&gt; method in &lt;code&gt;SKViewDelegate&lt;/code&gt; is called just before the &lt;code&gt;update()&lt;/code&gt; method in &lt;code&gt;SKScene&lt;/code&gt;, so it's a perfect place for us to use to update time properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="c1"&gt;/// Assign to the `SKView` to update game time properties for each frame.&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;Ticker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NSObject&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;SKViewDelegate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shouldRenderAtTime&lt;/span&gt; &lt;span class="nv"&gt;time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;Bool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Update time properties.&lt;/span&gt;
    &lt;span class="kt"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// By returning true the game runs at the full frame rate specified with preferredFramesPerSecond.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, we need to assign the delegate to the SKView, during the game's initialization process.&lt;/p&gt;

&lt;p&gt;I prefer to have a &lt;code&gt;GameManager&lt;/code&gt; class where I do all my early initialization. I instantiate my &lt;code&gt;GameManager&lt;/code&gt; immediately from my &lt;code&gt;ViewController&lt;/code&gt; where I pass in the &lt;code&gt;SKView&lt;/code&gt; that will present my different game scenes.&lt;/p&gt;

&lt;p&gt;That is the perfect spot to assign the custom delegate that will ensure that the time properties stay up to date without having to manage that on a per-scene basis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;GameManager&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// Ticker that updates game time properties.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;ticker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;Ticker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Assign the game time ticker to the view.&lt;/span&gt;
    &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;delegate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ticker&lt;/span&gt;

    &lt;span class="c1"&gt;// ... Other game setup code would go here...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And there we have it, a rock-solid reusable solution that gives us easy access to time properties like delta time from anywhere in our game code.&lt;/p&gt;

&lt;p&gt;Whenever we need to do a delta time based calculation, we can now at any time use &lt;code&gt;Time.deltaTime&lt;/code&gt; as part of the calculation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Improvements
&lt;/h2&gt;

&lt;p&gt;With a central location for our time properties, it doesn't have to end with delta time. There are plenty of time-related properties that are useful for game development. If we look at Unity's &lt;code&gt;Time&lt;/code&gt; class as a reference, we could replicate more of the properties there and keep decorating our own &lt;code&gt;Time&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;Let's say we also want to have access to the frame count in our game code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;enum&lt;/span&gt; &lt;span class="kt"&gt;Time&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// The total number of frames since the start of the game.&lt;/span&gt;
  &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;private(set)&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;frameCount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;at&lt;/span&gt; &lt;span class="nv"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... previous code in the update method here ...&lt;/span&gt;

    &lt;span class="c1"&gt;// Increase frame count since game started.&lt;/span&gt;
    &lt;span class="n"&gt;frameCount&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now at any time access &lt;code&gt;Time.frameCount&lt;/code&gt; if we need to read this value.&lt;/p&gt;

&lt;p&gt;The final tweak, let's extend our value types operators to handle &lt;code&gt;TimeInterval&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Previously in this post we multiplied speed with delta time and had to cast the time value to CGFloat, &lt;code&gt;CGFloat(seconds)&lt;/code&gt;. As we are going to use the delta time value in many places, it would be convenient if we didn't have to cast it every time. Instead, we can extend types we are going to use with delta time, such as &lt;code&gt;CGFloat&lt;/code&gt; and &lt;code&gt;CGVector&lt;/code&gt; to use &lt;code&gt;TimeInterval&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here's an example of extending &lt;code&gt;CGFloat&lt;/code&gt; so we can multiply a &lt;code&gt;CGFloat&lt;/code&gt; value directly with a &lt;code&gt;TimeInterval&lt;/code&gt; without having to cast it every time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;lhs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;lhs&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;CGFloat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rhs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By that, we are now able to write clean game code like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="n"&gt;movement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="kt"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What a beauty!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://docs.unity3d.com/ScriptReference/Time.html"&gt;Unity API: Time&lt;/a&gt;. Static properties that provides time information in Unity. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://developer.apple.com/documentation/spritekit/skviewdelegate"&gt;SKViewDelegate&lt;/a&gt;. Take custom control over the view's render rate. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>gamedev</category>
      <category>swift</category>
      <category>spritekit</category>
    </item>
    <item>
      <title>Trail VFX with SpriteKit</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Sat, 30 Apr 2022 01:31:21 +0000</pubDate>
      <link>https://forem.com/johansteen/trail-vfx-with-spritekit-3dia</link>
      <guid>https://forem.com/johansteen/trail-vfx-with-spritekit-3dia</guid>
      <description>&lt;p&gt;Visual Effects are an important part of making pleasing effects in games. Commonly, VFX is used for things like bullets, projectile trails, magic, portals, and countless other things.&lt;/p&gt;

&lt;p&gt;I was doing research some time ago on how to be able to replicate some common VFX techniques in SpriteKit. More specifically, I wanted to be able to make trailing effects to spice up the look of bullets as the player upgraded them while progressing through the game.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2omg2s8rycslskbdsbp.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa2omg2s8rycslskbdsbp.gif" alt="SpriteKit Trailing VFX Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the kind of effect I ended up with, using only the functionality provided by SpriteKit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trailing VFX Breakdown
&lt;/h2&gt;

&lt;p&gt;Let's start by breaking down how an effect like this is usually constructed, and then we continue on how to implement those techniques using SpriteKit.&lt;/p&gt;

&lt;p&gt;The effect is based on having a seamless trail texture. This can be created in Photoshop quite easily with some random strokes and then matching up the edges with the offset filter to make it seamless. But that's out of the scope of this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Moving the Trail Independently
&lt;/h3&gt;

&lt;p&gt;We are going to apply this texture on a plane, which is the VFX object that we will add to and move around in our game world. To make the texture feel dynamic instead of static, we are going to tweak the UV coordinates, which controls how the texture maps to the plane.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb77ek6ja4dnhvit1fp6p.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb77ek6ja4dnhvit1fp6p.jpg" alt="Game Trail VFX UV Setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When we compress the V position of the coordinates on one edge of the UV, we effectively squeeze the texture located on the opposite edge, so we get a tapered effect on the texture from one edge to the other.&lt;/p&gt;

&lt;p&gt;And here comes the beauty, if we move this plane over the scene, and at the same time we also move the U position of the texture, at a different speed than the plane is using, the texture "comes alive" and we get a sense that the texture constantly evolves and animates during its lifetime instead of just statically move over the scene.&lt;/p&gt;

&lt;p&gt;Working with a UV like this, the possible effects can be taken much further. We could alter the UV using a curved shape instead of a linear falloff, or segment it up and randomly adjust each segment's size slightly to break up the movement and move it even further away from a static texture.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fading Out the Trail Edge
&lt;/h2&gt;

&lt;p&gt;Next, we are going to need to fade out the edge of the trail so it doesn't cut off abruptly. We will do that with the help of a gradient map.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fct50v09bz28uwzcrwr6y.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fct50v09bz28uwzcrwr6y.jpg" alt="Game Trail VFX Gradient Multiply"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The gradient map is the top layer of the stack which we are using to control the opacity of the effect. This layer will remain in place and not move over the UV like the trail texture does. By doing a multiply blend of the top gradient layer with the layers below, we end up with a nice fade out at the edge of the trail.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Tweaks
&lt;/h3&gt;

&lt;p&gt;To give the trails a bit more flare and depth, we are going to duplicate the trail texture two or three times and stack them on top of each other. Each copy will have the texture slightly offset and move over the UV at a slightly different speed.&lt;/p&gt;

&lt;p&gt;This gives us tons of dynamic variation as the effect moves over the game scene. In the video of my SpriteKit effect above, I've layered the trail texture two times and each layer moves with different speed values and is then blended together.&lt;/p&gt;

&lt;p&gt;And for the final touch to make it glow, top it off with a bit of bloom.&lt;/p&gt;

&lt;h2&gt;
  
  
  SpriteKit Implementation
&lt;/h2&gt;

&lt;p&gt;That was it for the theory and how one would achieve this kind of effect in most graphics and game systems. So let's see how we can approach this using SpriteKit and get into the nitty gritty details with some code.&lt;/p&gt;

&lt;p&gt;The biggest challenge is that we don't have access to manipulate UV coordinates when we map textures to nodes in SpriteKit. With SceneKit it would have been a different story, but oh well. As game VFX is often heavily based on manipulating UVs, we have to come up with some workarounds to achieve similar outcomes.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Trail Setup
&lt;/h3&gt;

&lt;p&gt;The trail layer would usually rely heavily on manipulating UVs. As we don't have access to UVs in SpriteKit, let's see what we would need the UVs to do, and then find SpriteKit solutions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With UVs textures can easily be repeated, so when the texture leaves the surface on one edge, it wraps around, and comes in on the opposite edge.&lt;/li&gt;
&lt;li&gt;UVs allow us to compress and resize parts of the texture independently of how the displayed surface is sized.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As &lt;code&gt;SKSpriteNode&lt;/code&gt; does not have functionality to move and wrap a texture applied to it, we'll solve it by repeating the texture ourselves, parent the repeated setup to a container node, and then crop out the visible area.&lt;/p&gt;

&lt;p&gt;We'll have to handle the wrapping ourselves.&lt;/p&gt;

&lt;p&gt;We will need three repetitions of the texture, which is enough no matter at what position we are observing it, to have enough repeating texture on each side to always be covered.&lt;/p&gt;

&lt;p&gt;This setup will allow us to move the projectile texture independently of the parent node.&lt;/p&gt;

&lt;p&gt;So let's begin with setting up the trail. I put this into it's own method so we can potentially create multiple layers of the same trail and stack for variation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;makeTrail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trailC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKSpriteNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;imageNamed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"trailTexture"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trailL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKSpriteNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;imageNamed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"trailTexture"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trailR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKSpriteNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;imageNamed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"trailTexture"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;trailL&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;
  &lt;span class="n"&gt;trailR&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;trails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trailC&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;trails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trailL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;trails&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trailR&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;trails&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We simply create the three instances we need of the texture. We have one centered, and then we move one to the left of it and one to the right of it.&lt;/p&gt;

&lt;p&gt;In the example above, the texture is 512 points wide, so I've hard-coded the values &lt;code&gt;512&lt;/code&gt; and &lt;code&gt;-512&lt;/code&gt; to move each segment to the left and right. We could have got this value from the texture itself, to make it more reusable.&lt;/p&gt;

&lt;p&gt;We then parent all the segments to an &lt;code&gt;SKNode&lt;/code&gt; and return this hierarchy. This trail object is basically what we need to be able to move and wrap the trail texture independently.&lt;/p&gt;

&lt;p&gt;Now we can call &lt;code&gt;makeTrail()&lt;/code&gt; whenever we need a new trail to build and layer up an effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Get 2 wrapable trails.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trail1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeTrail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;trail2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;makeTrail&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;// Make the second trail slightly taller and change the blend mode to `add`.&lt;/span&gt;
  &lt;span class="n"&gt;trail2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;trail2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;yScale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;1.25&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;trail2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;children&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;child&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;SKSpriteNode&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;child&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blendMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ... Setup continues ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example we create two trail objects, so we can layer them on top of each other for more variation that will help sell the effect as a non-static texture.&lt;/p&gt;

&lt;p&gt;The second trail object is made slightly larger by scaling it to &lt;code&gt;1.25&lt;/code&gt; on the y-axis. The second trail is placed on top of the first, so each child of the second trail has its blendMode changed to &lt;code&gt;add&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Move and Wrap the Texture
&lt;/h3&gt;

&lt;p&gt;Time to get the texture moving. We will use the &lt;code&gt;SKCropNode&lt;/code&gt; to get a window that we can observe our trail object through, and then give the trail object that holds the texture its own movement loop.&lt;/p&gt;

&lt;p&gt;The crop node can then move around on the screen while the trail texture moves and wraps independently beneath it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... Setup continued ...&lt;/span&gt;

  &lt;span class="c1"&gt;// Create a huge hidden background.&lt;/span&gt;
  &lt;span class="c1"&gt;// This is explained further in the taper part. We need this for the warpGeometryGrid.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKSpriteNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="n"&gt;bg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
  &lt;span class="n"&gt;bg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isHidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

  &lt;span class="c1"&gt;// Mask with the crop node.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKSpriteNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;crop&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKCropNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;crop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;maskNode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;
  &lt;span class="n"&gt;crop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;crop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trail1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;crop&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trail2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// ... Setup continues ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;huge&lt;/em&gt; background we create here is a story by itself that is related to SpriteKit's geometry warping behavior. So it will be explained further once we get to the taper section. We add it here as it needs to be a child to the crop node.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;SKCropNode&lt;/code&gt; needs a mask that defines our cropping area. The mask is basically our window where we can see what's inside the crop node, and the size of the mask becomes the size of our effect. So the mask is of the same height as the trail texture so we can fully see it, but much less wide, as we will keep moving the trail texture and only want to see a part of it horizontally.&lt;/p&gt;

&lt;p&gt;So after setting the mask, we just keep adding children (the trails and the background) that we want to see through the crop node.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... Setup continued ...&lt;/span&gt;

  &lt;span class="c1"&gt;// Keep moving the trails through the crop node.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;move1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;moveTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;move2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;moveTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;trail1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeatForever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;move1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;move2&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;move3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;moveTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;move4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;moveTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;512&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;trail2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;repeatForever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sequence&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;move3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;move4&lt;/span&gt;&lt;span class="p"&gt;])))&lt;/span&gt;

  &lt;span class="c1"&gt;// ... Setup continues ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We then need to move the trail texture. We use &lt;code&gt;SKAction.moveTo(x:duration:)&lt;/code&gt; to add the texture movement. Each trail needs two move actions. The first action has a duration of &lt;code&gt;0&lt;/code&gt; as it moves the texture back to its starting position. This is basically the wrap around.&lt;/p&gt;

&lt;p&gt;And the second move action animates the texture to move to the other side of the visible area. The duration value here sets the speed. We put both move actions into a sequence that we repeat forever.&lt;/p&gt;

&lt;p&gt;In this example we use two trails stacked on top of each other, so we move the second trail with a different duration to get a different speed so it adds visual variation.&lt;/p&gt;

&lt;p&gt;Potentially, we could also offset the move x value for one of the trails for even more variation.&lt;/p&gt;

&lt;p&gt;And there we have it, a parent node (the crop node) that can be moved in the game scene while a texture moves independently inside it that wraps around. This setup gives us the same behavior as the first of the two UV bullet points.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fade the Edge
&lt;/h3&gt;

&lt;p&gt;To fade out the edge of the effect, we will do pretty much exactly as theorized above. We'll take a gradient map image and multiply it on top of the effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... Setup continued ...&lt;/span&gt;

  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;opacity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKSpriteNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;imageNamed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"trailTexture-gradient"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;opacity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;blendMode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;multiplyAlpha&lt;/span&gt;
  &lt;span class="n"&gt;opacity&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;

  &lt;span class="c1"&gt;// ... Setup continues ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We prepare an object with the gradient texture and set its &lt;code&gt;blendMode&lt;/code&gt; appropriately so we can fade out the edge of the effect. We will add the node to the effect hierarchy together&lt;br&gt;
with the taper effect in the next step.&lt;/p&gt;

&lt;p&gt;Another approach I've been considering is to use an &lt;code&gt;SKShader&lt;/code&gt; that should be able to do the same thing, but which would be cleaner and more efficient.&lt;/p&gt;
&lt;h3&gt;
  
  
  Taper the Texture
&lt;/h3&gt;

&lt;p&gt;It's time to deal with the tapering of the trail effect by using a SpriteKit implementation for the second bullet point from the list with UV behaviors we are trying to replicate.&lt;/p&gt;

&lt;p&gt;The closest I've got is to use an &lt;code&gt;SKEffectNode&lt;/code&gt; with warpGeometry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... Setup continued ...&lt;/span&gt;

  &lt;span class="c1"&gt;// The effect node to warp.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;effect&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKEffectNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Create the tapered coordinates.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;destinationPositions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;   &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.9&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nf"&gt;vector_float2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;3.5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;warpGeometryGrid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKWarpGeometryGrid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// Apply the tapered effect.&lt;/span&gt;
  &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;warpGeometry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;warpGeometryGrid&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;replacingByDestinationPositions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;positions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;destinationPositions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// Control the quality of the distortion effect.&lt;/span&gt;
  &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;subdivisionLevels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;

  &lt;span class="c1"&gt;// ... Setup continues ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We distort the trail by using &lt;code&gt;SKWarpGeometryGrid&lt;/code&gt;. Basically, we just create a grid of coordinates where we can squeeze the right side of the node together, so when the trail moves over the effect node, it gets compressed on the right side while&lt;br&gt;
it spreads out and widens on the left side.&lt;/p&gt;

&lt;p&gt;This approach works fine if used isolated, but as with many SpriteKit things, it gets a tad more complicated when combining parts together.&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;subdivisionLevels&lt;/code&gt; property of the effect node to get rid of distortion blockiness and get a much smoother and crisper look. Higher values do affect performance.&lt;/p&gt;

&lt;p&gt;Do you remember this from before, when we created the huge background?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKSpriteNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;black&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;size&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;95&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;bg&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isHidden&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now is the time to talk about it. The huge, hidden, background is there to ensure that the warpGeometryGrid coordinates stay in put.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The warp does not respect the cropped area.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By having a larger than we need background, the warp will not move around. Otherwise, as the trails move over the node, it instead calculates the unit coordinates based on how&lt;br&gt;
large it sees all nodes added together for each frame. The large background counters that behavior and helps it keep consistent.&lt;/p&gt;

&lt;p&gt;It's not a pretty solution, but that's how far I've been able to take it with SpriteKit alone. Using a CIFilter might be worth exploring as an alternative option, a transform there might behave more consistent than using warpGeometry.&lt;/p&gt;

&lt;p&gt;Talking about CIFilter, as we have an effect node created already, why not keep using it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... Setup continued ...&lt;/span&gt;

  &lt;span class="c1"&gt;// Add an additional bloom on top of the effect.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;bloomFilter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;CIFilter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"CIBloom"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;
  &lt;span class="n"&gt;bloomFilter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"inputRadius"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;bloomFilter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;forKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"inputIntensity"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;filter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bloomFilter&lt;/span&gt;

  &lt;span class="c1"&gt;// ... Setup continues ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The effect node can take a CIFilter among its properties, so let's go ahead and use it to add a bloom filter to enhance the effect further.&lt;/p&gt;

&lt;h3&gt;
  
  
  Move the Full Trail Effect
&lt;/h3&gt;

&lt;p&gt;With the entire effect layered up and organized in a hierarchy under the effect node, we can now simply move the trail wherever we need it to be my moving the effect node around.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... Setup continued ...&lt;/span&gt;

  &lt;span class="c1"&gt;// Move the entire projectile over the screen.&lt;/span&gt;
  &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;SKAction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;moveTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;700&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;duration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

  &lt;span class="n"&gt;effect&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;crop&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's all there is to it. We start an animation where we want the projectile to go and then add it to the scene.&lt;/p&gt;

&lt;p&gt;In this article I've out of convenience, just added the setup inside the &lt;code&gt;didMove(to:)&lt;/code&gt; method. It would make more sense to have this functionality in a &lt;code&gt;trailEffect()-&amp;gt;SKNode&lt;/code&gt; method that would setup the trail and return its node to have it instantiated on demand.&lt;/p&gt;

&lt;p&gt;The returned node can then get the appropriate movement action assigned and then added to the scene.&lt;/p&gt;

&lt;p&gt;Performance wise using SKEffectNode and SKCropNode can be heavy. Keeping the dimensions down on the effect should have a positive effect on performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Even though the fact that this solution can not compete with what you can do with the modern game engines out there, and also that the solution uncovers a few flaws (aka bugs) with SpriteKit, it can still provide a lot of power and usefulness for SpriteKit projects.&lt;/p&gt;

&lt;p&gt;A dynamic trail VFX can be the building block and foundation of many different effects. Continuing building on the trails in this example, I'll add a head to the trails using something like an animated flare. On top of that, a small particle emitter could be added as the final layer, emitted some sparkling texture to help bring the effect to life.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>spritekit</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Visual Debugging of GameplayKit GKComponent</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Tue, 12 Apr 2022 14:33:35 +0000</pubDate>
      <link>https://forem.com/johansteen/visual-debugging-of-gameplaykit-gkcomponent-2iao</link>
      <guid>https://forem.com/johansteen/visual-debugging-of-gameplaykit-gkcomponent-2iao</guid>
      <description>&lt;p&gt;When coding games, it can be useful to be able to visualize values in real-time to monitor that algorithms behave as expected and that data is generated correctly. You don't want to feel that you are working against a black hole, hoping for the best that every part of the game works as intended.&lt;/p&gt;

&lt;p&gt;Writing a test suite can help somewhat with this, or even sometimes just printing data to the console will do the trick. As games most of the time are a visual experience, getting visual feedback of behaviors during play testing can be extremely useful and time saving and to help feel confident that the implementations are solid.&lt;/p&gt;

&lt;p&gt;If you use a game engine like Unreal or Unity, you get some stuff like this "for free" but when we code our own games with Swift in Xcode, we have to implement our own systems to handle the visualizing of crucial values in our games to check that all the parts work as intended.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Cases
&lt;/h2&gt;

&lt;p&gt;As this is only intended to be used during development and testing, and will never be shipped to the players in release builds, there is no need to make something pretty.&lt;/p&gt;

&lt;p&gt;The point of these visualizations is to simply show the data in an easy to understand manner so it can be analyzed that it works as intended.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GJcvMG0Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2d8mrryg32jz1zgfednt.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GJcvMG0Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2d8mrryg32jz1zgfednt.jpg" alt="GKComponent Visual Debugging Examples" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I've been building systems for this to keep track of values like enemy healthpoints, simulated input pressure, generated movement paths and many more things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Example
&lt;/h2&gt;

&lt;p&gt;Let's study a concrete example, how this can be implemented using the Swift programming language. I'm basing this on using GameplayKit and SpriteKit, but it can easily be adopted to other frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Visual Debug Protocol
&lt;/h3&gt;

&lt;p&gt;I rely heavily on the Entity Component System provided with GameplayKit, so most of my logic is contained within GKComponents. I'm using a custom protocol with GKComponent that I can implement for components that contain values that I need to analyze visually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
&lt;span class="c1"&gt;/// Protocol to enable/disable visualization of debug info in `GKComponent` objects.&lt;/span&gt;
&lt;span class="kd"&gt;protocol&lt;/span&gt; &lt;span class="kt"&gt;GKComponentDebuggable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// Enable display of debug info.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;enableDebugInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;/// Disable display of debug info.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;disableDebugInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="c1"&gt;/// Update loop to run debug specic logic.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;debugUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt; &lt;span class="nv"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With these three methods in my &lt;code&gt;GKComponentDebuggable&lt;/code&gt; protocol I've been able to handle all my visualization needs I've had so far. &lt;code&gt;enableDebugInfo()&lt;/code&gt; allows me to do&lt;br&gt;
any initialization, in &lt;code&gt;disableDebugInfo()&lt;/code&gt; I do the cleanup and in &lt;code&gt;debugUpdate()&lt;/code&gt; I can handle any changes needed on a frame by frame basis.&lt;/p&gt;
&lt;h3&gt;
  
  
  Debug Core Setup
&lt;/h3&gt;

&lt;p&gt;I handle the setup to enable, disable, and update the components that implement the &lt;code&gt;GKComponentDebuggable&lt;/code&gt; in my main &lt;code&gt;GameplayScene&lt;/code&gt; class. That is the class that takes care of all the core management of my game systems.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="kt"&gt;GameplayScene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
  &lt;span class="c1"&gt;/// Tracks the state if debug info shall be displayed.&lt;/span&gt;
  &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="nv"&gt;debugInfoEnabled&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;didSet&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;debugInfoEnabledDidChange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;/// Root layer of nodes to display movement graphs for debugging.&lt;/span&gt;
  &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;debugGraphLayer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKNode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="cp"&gt;#endif&lt;/span&gt;

  &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;didMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;view&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;SKView&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other initialization code would be here ...&lt;/span&gt;

    &lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
    &lt;span class="c1"&gt;// Add layers to display debug info to the scene.&lt;/span&gt;
    &lt;span class="n"&gt;debugGraphLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;zPosition&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;LevelLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rawValue&lt;/span&gt;
    &lt;span class="n"&gt;worldNode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;debugGraphLayer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Call didChange once so it can start with debug mode on if enabled.&lt;/span&gt;
    &lt;span class="nf"&gt;debugInfoEnabledDidChange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="cp"&gt;#endif&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// ... And here continues the rest of my GameplayScene class ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm using two properties. &lt;code&gt;debugInfoEnabled&lt;/code&gt; allows me to define if I should start the game with debug info in an enabled state. When the value is changed, I call a dedicated &lt;code&gt;debugInfoEnabledDidChange()&lt;/code&gt; method that handles all states when it comes to visual debug info. This is not limited to the things I show with &lt;code&gt;GKComponentDebuggable&lt;/code&gt; as I also have other debug info I enable that are not related to specific components.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;debugGraphLayer&lt;/code&gt; is a sub-root node that is available in the &lt;code&gt;GameplayScene&lt;/code&gt; when making a Debug build, that all &lt;code&gt;GKComponentDebuggable&lt;/code&gt; implementations can use to add their visuals to. This is set to a Z depth above everything else in the scene.&lt;/p&gt;

&lt;p&gt;During the scene's life cycle, I initialize the &lt;code&gt;debugGraphLayer&lt;/code&gt; node at the end of &lt;code&gt;didMove(to:)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Okay, let's move on to interacting with the protocol.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
&lt;span class="c1"&gt;// Extend GameplayScene to add methods to display debug info.&lt;/span&gt;
&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;GameplayScene&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;/// Toggle display of debug overlay metrics.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;debugInfoEnabledDidChange&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... other debug info handling....&lt;/span&gt;

    &lt;span class="c1"&gt;// Toggle debug info in components.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;componentSystem&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;componentSystems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;toggleDebugInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;for&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;componentSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;/// Toggles debug info for provided array of components.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;toggleDebugInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;GKComponent&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;component&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;GKComponentDebuggable&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;debugInfoEnabled&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enableDebugInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disableDebugInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;/// Update loop to run debug specic logic.&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;debugUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt; &lt;span class="nv"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Exit right away if we don't display debug info.&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;debugInfoEnabled&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Update component systems.&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;componentSystem&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;componentSystems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;component&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kt"&gt;GKComponentDebuggable&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;componentSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debugUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep it neat and tidy, I've added the debug handling code in an extension to the &lt;code&gt;GameplayScene&lt;/code&gt; class that is only included in debug builds. I've three methods in this extension that manage the debug visualization.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;debugInfoEnabledDidChange()&lt;/code&gt; is the method we call when we change the &lt;code&gt;debugInfoEnabled&lt;/code&gt; property in the &lt;code&gt;GameplayScene&lt;/code&gt; above, that handles toggling all different debug visualizations on and off.&lt;/p&gt;

&lt;p&gt;In the method, I loop through the &lt;code&gt;componentSystems&lt;/code&gt; property. Which is an array of &lt;code&gt;[GKComponentSystem]&lt;/code&gt; that holds references to all currently active component systems in the game. That is the standard behavior of ECS in GameplayKit and a bit out of scope for me to go deeper into in this article.&lt;/p&gt;

&lt;p&gt;This is the same array I loop through in my standard gameplay update loop, to update all components on each frame iteration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;componentSystem&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;componentSystems&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;componentSystem&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we have &lt;code&gt;toggleDebugInfo()&lt;/code&gt; which takes an array of GKComponents. This is the method we call from &lt;code&gt;debugInfoEnabledDidChange&lt;/code&gt; where we pass in the components from each component system. But I also call this method manually when a new entity is added to the game during gameplay in debug mode, to enable visualization if required.&lt;/p&gt;

&lt;p&gt;This method simply loops through the components and then calls the &lt;code&gt;enableDebugInfo()&lt;/code&gt; or &lt;code&gt;disableDebugInfo()&lt;/code&gt; on each component that has implemented the &lt;code&gt;GKComponentDebuggable&lt;/code&gt; protocol.&lt;/p&gt;

&lt;p&gt;And finally we have the &lt;code&gt;debugUpdate(deltaTime:)&lt;/code&gt; method. Just like previous methods, this method loops through all components in each component system to see which ones implement &lt;code&gt;GKComponentDebuggable&lt;/code&gt;, and for those that does, the &lt;code&gt;debugUpdate(deltaTime:)&lt;/code&gt; method is called in the component.&lt;/p&gt;

&lt;p&gt;This method is called last in the regular gameplay update loop when building a debug build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt; &lt;span class="nv"&gt;currentTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
  &lt;span class="c1"&gt;// Run update loop for debug info and overlay.&lt;/span&gt;
  &lt;span class="nf"&gt;debugUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;Time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;So with all this in place, let's see an example, of an actual implementation in a component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight swift"&gt;&lt;code&gt;&lt;span class="cp"&gt;#if DEBUG&lt;/span&gt;
&lt;span class="c1"&gt;// MARK: - Debug&lt;/span&gt;

&lt;span class="kd"&gt;extension&lt;/span&gt; &lt;span class="kt"&gt;EnemyAIComponent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;GKComponentDebuggable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;enableDebugInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderComponent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;GameplayScene&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Configure path display&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;shape&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;SKShapeNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;lineWidth&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;
    &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;strokeColor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;red&lt;/span&gt;
    &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kt"&gt;NodeName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;componentDebug&lt;/span&gt;
    &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;startPos&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;

    &lt;span class="c1"&gt;// Store a reference to the entity in the path so we can find it later as it is displayed directly in the scene and not as a child of anything relating to the entity.&lt;/span&gt;
    &lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userData&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"entity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debugGraphLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;disableDebugInfo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;scene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderComponent&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scene&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;GameplayScene&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Find and remove the path in the graph layer.&lt;/span&gt;
    &lt;span class="n"&gt;scene&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;debugGraphLayer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enumerateChildNodes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;withName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;NodeName&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;componentDebug&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;weak&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt;
      &lt;span class="k"&gt;guard&lt;/span&gt; &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="nv"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;userData&lt;/span&gt;&lt;span class="p"&gt;?[&lt;/span&gt;&lt;span class="s"&gt;"entity"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;as?&lt;/span&gt; &lt;span class="kt"&gt;GKEntity&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;entity&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;removeFromParent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;func&lt;/span&gt; &lt;span class="nf"&gt;debugUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deltaTime&lt;/span&gt; &lt;span class="nv"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;TimeInterval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Not needed in this component.&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, I extend &lt;code&gt;EnemyAIComponent&lt;/code&gt; to visualize the path on screen that an enemy gets assigned when spawned. So during the &lt;code&gt;enableDebugInfo()&lt;/code&gt; phase, I take the path property already available in the component and draw the path to screen with a &lt;code&gt;SKShapeNode&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I use &lt;code&gt;disableDebugInfo()&lt;/code&gt; to remove the path when the entity is removed.&lt;/p&gt;

&lt;p&gt;In this case the path does not change during the component's life cycle, so I don't need to call &lt;code&gt;debugUpdate(deltaTime:)&lt;/code&gt;. Otherwise, I'd have used this method to update the drawn path during the life span of the component.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;There are of course many ways to skin a cat, but for me, I've found that this protocol-based approach together with the ECS system of GameplayKit has worked out great while keeping the code clean and easy to navigate.&lt;/p&gt;

&lt;p&gt;While I just scratched the surface here of what one can do, I can imagine taking the concept further to a full-blown in-game console to be able to interact with the protocol and even other game data live during gameplay for even faster iterations.&lt;/p&gt;

&lt;p&gt;And other times, a simple print statement to the Xcode console might be enough. I'd put my solution above somewhere in between, which fulfills the purpose fast and efficiently in many day to day scenarios to analyze game data.&lt;/p&gt;

</description>
      <category>swift</category>
      <category>spritekit</category>
      <category>gameplaykit</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Hypastorm Asset Workflow</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Mon, 11 Apr 2022 14:52:52 +0000</pubDate>
      <link>https://forem.com/johansteen/hypastorm-asset-workflow-37a1</link>
      <guid>https://forem.com/johansteen/hypastorm-asset-workflow-37a1</guid>
      <description>&lt;p&gt;I've already covered different coding workflows in multiple previous posts as well as my &lt;a href="https://blog.bitbebop.com/gamedev-file-structure/"&gt;game development file structure&lt;/a&gt;, so let's dig into my pipeline to create all the art related assets and my overall workflow to complete a game production.&lt;/p&gt;

&lt;p&gt;All in all, the bulk of making &lt;a href="https://bitbebop.com/games/hypastorm/"&gt;Hypastorm&lt;/a&gt; took about one month for our tiny two person team, so I had to come up with some efficient workflows and time saving approaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Art
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Blender&lt;/em&gt; and &lt;em&gt;Photoshop&lt;/em&gt; was my main tools to get the graphics done for this game. The actual choice of applications is not very important, in the end it all basically end up as PNG files to be used as sprites in &lt;em&gt;SpriteKit&lt;/em&gt;. I wanted to use graphics generated in code for some parts, but it turned out to grow the scope too much, so I canceled that for Hypastorm and added that on my list for things to make for a future game instead. So it is all just bitmap graphics in the asset catalog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Game Objects
&lt;/h3&gt;

&lt;p&gt;Almost every object in the game is initially created as a 3D model in Blender and then rendered out as a Sprite, or a Sprite Atlas if it needed animation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JSRof-Z4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yfnbgopkn9o7o1qoqrw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JSRof-Z4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yfnbgopkn9o7o1qoqrw3.png" alt="Spawner Setup in Blender" width="880" height="495"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The other half of my team, Phimrost Sitthikun, did the initial modeling and setup of each game object that required Blender and then I continued working on it to prepare it so it was "game-ready" before rendering.&lt;/p&gt;

&lt;p&gt;From the start I designed a full pipeline around Blender where we could store things in a "library" and use a lot of referencing between scenes and files. I wanted to be able to reuse lighting and other things, so I for instance could adjust the lighting in one place and then batch re-render every object in the game in one go with the adjusted lighting.&lt;/p&gt;

&lt;p&gt;That is a workflow that I'm used to and comfortable with in other 3D applications I have used in the past. I eventually got this to work in Blender, as it theoretically has every feature required to achieve this.&lt;/p&gt;

&lt;p&gt;Unfortunately, Blender was &lt;strong&gt;not&lt;/strong&gt; very stable.&lt;/p&gt;

&lt;p&gt;One of my goals with the project was to get more into the world of Blender, so I really wanted Blender to work out and gave it more chances than I normally would give an application with issues. But it is simply not there yet. It is not production ready and extremely unreliable in certain scenarios.&lt;/p&gt;

&lt;p&gt;So while the above mentioned setup worked in theory, in reality it turned Blender into a crash fest. Parts of scenes got corrupted. Reopening a Blender file relying heavily of linking between files was a lottery if it would work again or not, changing a view could be enough for a repeatable crash. More times than I can count the file eventually became corrupted and I had to manually repair it by extracting assets one by one from the &lt;code&gt;.blend&lt;/code&gt; file or revert to an older version and redo a lot of work.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;That quickly got boring and tedious after a few times.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Never in my career have I encountered a DCC tool that unreliable in some key areas. So while Blender impresses me in some scenarios, I can't rely on it in others.&lt;/p&gt;

&lt;p&gt;So in the end I patched the assets enough via salvaged files to get the artwork I needed out of Blender. I've adjusted my 3D pipeline for the next game, and I have invested in &lt;em&gt;Houdini&lt;/em&gt; as the core of the 3D workflow. Houdini has been a joy to work with so far. I felt right back at home after a few days with Houdini after weeks of &lt;strong&gt;rage quits&lt;/strong&gt; with Blender.&lt;/p&gt;

&lt;p&gt;Houdini is stable. I've never appreciated stability in an application as much as I did after a few weeks with Blender.&lt;/p&gt;

&lt;p&gt;Anyway, when it comes to modeling, I find Blender &lt;em&gt;very stable&lt;/em&gt; and have never run into any issues there. Perfectly fine workflow wise and stable wise. So Blender is the modeling tool in the pipeline for now. And &lt;strong&gt;maybe&lt;/strong&gt; a render tool.&lt;/p&gt;

&lt;p&gt;The short version, I wasted too much precious time recovering and repairing Blender files, when I used features that obviously are not yet stable enough to rely on in a production. Lesson learned and my pipeline is adjusted accordingly.&lt;/p&gt;

&lt;h3&gt;
  
  
  UI
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xgR3u-3E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8862qqb31hmeg8fb9z9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xgR3u-3E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m8862qqb31hmeg8fb9z9.jpg" alt="UI elements in Adobe Illustrator" width="880" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created every main UI element in &lt;em&gt;Adobe Illustrator&lt;/em&gt;. The &lt;strong&gt;Asset Export&lt;/strong&gt; panel in Illustrator was a huge help for an efficient workflow to streamline getting the art out of Illustrator and into the game.&lt;/p&gt;

&lt;p&gt;By piping the output from the Asset Export via my &lt;a href="https://github.com/artstorm/xcode-asset-catalog-generator"&gt;Xcode Asset Catalog Generator&lt;/a&gt; tool I got every change I did in Illustrator to immediately update the Xcode Asset Catalog with the new version.&lt;/p&gt;

&lt;p&gt;The same holds true for the game object assets that I got out of Blender, but I usually made some hand painted tweaks in Photoshop there before passing the asset on to the generator.&lt;/p&gt;

&lt;p&gt;As &lt;em&gt;Xcode 12&lt;/em&gt; now supports &lt;strong&gt;SVG&lt;/strong&gt; files in the asset catalog, I'm able to simplify this even further by just sending SVG files directly into the asset catalog as long as I have UI elements that are suitable as vector graphics. Which is what I am doing for the next game I'm working on.&lt;/p&gt;

&lt;h4&gt;
  
  
  UI Flow
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7lx-6_-D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qkwc65u0k9jdbv9vnb4k.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7lx-6_-D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qkwc65u0k9jdbv9vnb4k.jpg" alt="UI Flow in Adobe XD" width="880" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With my Creative Cloud subscription, I have access to so many apps, many that I've never used or bothered to install. But now was the time to give &lt;em&gt;Adobe XD&lt;/em&gt; a spin.&lt;/p&gt;

&lt;p&gt;While I was not amazed with it, it got the job done. As the number of overlays and panels in the game grew, I needed an easy way to visualize the different screens and how to put it together. As I don't use any visual editor to make my games but do all these things in code, it was very helpful to have an overview in XD that I easily could edit and try new layouts with before translating it into code logic.&lt;/p&gt;

&lt;p&gt;I did this quite late in the development of this game, but as I got quite some mileage out of XD, this is part of my workflow from the beginning on my new game.&lt;/p&gt;

&lt;h3&gt;
  
  
  Achievements
&lt;/h3&gt;

&lt;p&gt;The achievement badges for &lt;em&gt;Game Center&lt;/em&gt; was another interesting challenge where I ended up with a workflow, based on ideas from a post in Adobe Substance's blog, where I rely heavily on &lt;em&gt;Substance Designer&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T8yUilOu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4z5v3urzz2d8xq2uaqs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T8yUilOu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t4z5v3urzz2d8xq2uaqs.jpg" alt="Hypastorm Achievements" width="880" height="341"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A workflow that has the potential to handle tons of more illustrations in a streamlined way to not get overwhelming or take ages to make adjustments to existing badges or when adding new badges, that should fit in with the chosen style.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h9pIh6AQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3cwtoab6tnq21dytnxr.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h9pIh6AQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o3cwtoab6tnq21dytnxr.jpg" alt="Blender Heightmap" width="880" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every badge starts in Blender as a very simple object. The object is only used to be able to get a height map out of Blender. Then the height map will be the source for the rest of the process towards a final badge.&lt;/p&gt;

&lt;p&gt;I used Blender's compositor with a File Output node to get normalized height maps out of Blender suitable for this purpose.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--E-h-LN_H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3cs4l6rr7n5fevw1xgpq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--E-h-LN_H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3cs4l6rr7n5fevw1xgpq.jpg" alt="Substance 3D Nodes" width="880" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In Substance Designer I import all the height maps from Blender. They are linked to Blender's output files, so a change in Blender will automatically update in Substance Designer as well.&lt;/p&gt;

&lt;p&gt;By passing in the height maps into a node network that applies materials and other styling, every badge will get the same look and design and look great together when presented in the Game Center Achievements section for the player.&lt;/p&gt;

&lt;p&gt;The final node in the Substance network is the PBR render node. That node could easily be replaced with a more stylistic arty output in a color scale for a completely different look, which I'm considering for my next game.&lt;/p&gt;

&lt;p&gt;Anyway, I did this at the end of the development cycle and the setup was a breeze and worked more or less as intended right away. I was very happy with the setup and I can easily add more achievements by just making a simple model and add the new additional height map to the Substance node network.&lt;/p&gt;

&lt;h2&gt;
  
  
  Audio
&lt;/h2&gt;

&lt;p&gt;Initially I started using &lt;em&gt;Adobe Audition&lt;/em&gt; for sound effects as I have access to it via my &lt;em&gt;Adobe Creative Cloud&lt;/em&gt; subscription. I quickly dropped going down that road and Instead I ended up using Apple's &lt;em&gt;Logic Pro X&lt;/em&gt; for everything. It was my first time with Logic Pro X, or actually my first time using any kind of modern DAW for audio creation.&lt;/p&gt;

&lt;p&gt;Last time I was doing something down these lines my applications of choice were &lt;em&gt;ProTracker&lt;/em&gt; and &lt;em&gt;AudioMaster&lt;/em&gt; on the Amiga. Time flies. The evolution from old Amiga software to all the possibilities a modern DAW offers combined with all the incredible instruments you can get these days are amazing. Me, who hasn't followed the progress over the years, was stunned.&lt;/p&gt;

&lt;h3&gt;
  
  
  Music
&lt;/h3&gt;

&lt;p&gt;As mentioned, Logic Pro X was the core of my audio production and I equipped it with some extra synthesizers that I purchased from Arturia.&lt;/p&gt;

&lt;p&gt;I created all instruments with &lt;em&gt;Arturia's SEM V&lt;/em&gt; for both the title song and the in game song. SEM V is quite an amazing reproduction of Oberheim's legendary SEM synthesizer.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_FYIzU5p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qabxld4cqbsiyra36ai5.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_FYIzU5p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qabxld4cqbsiyra36ai5.jpg" alt="Arturia" width="880" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I simply just love this synthesizer, the sound characteristics and the analog GUI replication of the real original SEM. That's eye candy that I get hooked on.&lt;/p&gt;

&lt;p&gt;I began creating the music and sound effects very late into the production and I would have liked to have used more time for it. I felt that I rushed it slightly, as I spent a major part of my audio time learning how to use Logic Pro X and SEM. Still, I think the audio turned out good enough to do the job.&lt;/p&gt;

&lt;p&gt;For my next game I will keep making the audio in parallel with the rest of the production, so I don't have a huge amount of sounds to create towards the end. And also, now I know my way around a DAW, so I will not have to use time to learn the actual applications.&lt;/p&gt;

&lt;p&gt;I might take the opportunity to explore a different instrument next time, I'm currently eying &lt;em&gt;Analog Dreams&lt;/em&gt; from Native Instruments, to get the lovely 80's movie synthesizer sound as the foundation for my next game's soundtrack. Either that or &lt;em&gt;Roland's JUPITER-80&lt;/em&gt; synthesizer, which is virtualized by Arturia.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sound Effects
&lt;/h3&gt;

&lt;p&gt;For sound effects I ended up sampling a few sounds myself and the rest I created digitally with &lt;em&gt;Alchemy&lt;/em&gt;. Alchemy is included with Logic Pro X and is a powerful synthesizer that I haven't spent enough time with, I was too eager to play with the synthesizers I got from Arturia.&lt;/p&gt;

&lt;p&gt;Anyway, Alchemy turned out to be a good companion to get sound effects created. I should dig a bit deeper into it next time.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LVITvTMC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzwzn95wlwt7pr014h0i.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LVITvTMC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lzwzn95wlwt7pr014h0i.jpg" alt="Logic Pro X Alchemy" width="880" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The sounds I recorded myself, I captured with my old trusty &lt;em&gt;Zoom H4N&lt;/em&gt; portable recorder, which I imported into the new sampler that comes with the Logic Pro X 10.5 update.&lt;/p&gt;

&lt;p&gt;For my next game I will definitely spend more time with the sampler and do more of my own recordings. I like the feeling to start with my own analog sounds as the source for the effects. On top of that, I'm also tempted to try &lt;em&gt;Massive&lt;/em&gt; from Native Instruments as an alternative to Alchemy.&lt;/p&gt;

&lt;p&gt;The options of cool software instruments available these days are endless and they are all too fun to play around with.&lt;/p&gt;

&lt;h3&gt;
  
  
  Audio Formats
&lt;/h3&gt;

&lt;p&gt;Once the sounds are ready to go into the game, I've made a batch processing tool that converts the audio to optimized formats for Apple's devices.&lt;/p&gt;

&lt;p&gt;The music I keep as Stereo 48kHz, AAC. The music is actually responsible for most of the game's download size. Probably over 50% of the game size is the audio, on the top of my head.&lt;/p&gt;

&lt;p&gt;The sound effects I convert to uncompressed Core Audio Format, little endian in 16 bit, Mono, 24kHz. I couldn't really hear any difference between 24kHz and 48kHz for the sound I've made for the game, so I opted to save some space and processing power to go with 24kHz.&lt;/p&gt;

&lt;h2&gt;
  
  
  Progress Tracking
&lt;/h2&gt;

&lt;p&gt;There are so many productivity systems out there these days, all fighting for your attention and promising to be the magic bullet to succeed with your projects. Hypastorm is not the only game I've been working on, so I've had quite some time to give many of the usual productivity suspects a fair run during my game development endeavors so far. But as I've progressed with the games, I've simplified, and then simplified more, how I manage my tasks. Right now I'm finding it to be more efficient with a few simple lists of tasks in &lt;em&gt;Things&lt;/em&gt; combined with spreadsheets.&lt;/p&gt;

&lt;p&gt;I actually do like kanban boards and related workflows, which is why I've tried to apply it on my game projects. I've used &lt;em&gt;Jira&lt;/em&gt;, &lt;em&gt;Trello&lt;/em&gt; and other similar systems for years when I've been developing apps with larger teams. In such cases, those systems are excellent! But I found out when I'm basically just a solo developer with an "assistant" that work on different things than me, it felt overkill for things I could organize and overview easier in plain old lists.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b2In_60A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulas97w5jzlwnpkeg4ly.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b2In_60A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ulas97w5jzlwnpkeg4ly.jpg" alt="Game Dev with Things" width="880" height="251"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So instead I make an &lt;em&gt;area&lt;/em&gt; in Things for each game and then add a project for every hat I have to wear during the development the game. Naturally that is &lt;strong&gt;Code, Art and Audio&lt;/strong&gt; but also things like &lt;strong&gt;Ideas, Marketing and QA&lt;/strong&gt; gets their own projects.&lt;/p&gt;

&lt;p&gt;In each project I organize tasks under headings. So for instance in code I make a heading for each planned build / milestone, so I can track what to code and fix next, and then I can simply archive the heading when done.&lt;/p&gt;

&lt;p&gt;It just works out to be very fast and reliable. I have my tasks available on all my devices in a native app, so I can sort and organize my tasks whenever I have some spare time. While I was happy enough with Things instead of a kanban board to manage my tasks, one thing I really missed is attachment support. I sort of patched that with using &lt;em&gt;Bear&lt;/em&gt; as an attachment "add-on" for Things. That's not perfect, not even close.&lt;/p&gt;

&lt;p&gt;Other useful applications I use are &lt;em&gt;Apple Numbers&lt;/em&gt; where I track all the art and audio assets I need to create, in spreadsheets. I actually rely on Numbers quite a bit, everything from time tracking, balancing enemies and weapons to planning achievements and their difficulty versus rewards.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;MindNode&lt;/em&gt; I use for diagramming. It's not really a diagramming app, but I found it to work out quite well for that purpose, and I like it way better than the different web based diagramming apps I've tried. I visualize my workflows in MindNode and I also design things like decision trees for game AI.&lt;/p&gt;

&lt;p&gt;And finally I use a dedicated game development journal in &lt;em&gt;Day One&lt;/em&gt; to note down my personal thoughts after each day of game work, so I get obstacles, solutions, victories and defeats on record for me to &lt;em&gt;maybe&lt;/em&gt; evaluate later. I like to record a short video for each entry if it makes sense as I enjoy seeing the game's evolution by browsing the videos when looking back.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Hopefully this overview of my asset workflow has been helpful and given you some ideas for your projects that you can take with you and use.&lt;/p&gt;

&lt;p&gt;For me, there were many lessons learned during the production of this game and I now have a much better and more effective foundation when I'm working on my next game. I'm sure I'll run into many new things to solve in that production too, and keep refining and improving my pipeline further.&lt;/p&gt;

&lt;p&gt;Finally, the game is available in the &lt;a href="https://apps.apple.com/app/hypastorm/id1515684370"&gt;App Store&lt;/a&gt; for iPhone, iPad, Apple TV and Mac, if you'd like to give it a spin.&lt;/p&gt;

</description>
      <category>gamedev</category>
      <category>workflow</category>
    </item>
    <item>
      <title>Gamedev File Structure</title>
      <dc:creator>Johan Steen</dc:creator>
      <pubDate>Sun, 10 Apr 2022 08:08:55 +0000</pubDate>
      <link>https://forem.com/johansteen/gamedev-file-structure-3d52</link>
      <guid>https://forem.com/johansteen/gamedev-file-structure-3d52</guid>
      <description>&lt;p&gt;File structures for game development. Not as sexy as adding a new effect to the game's visuals. Nonetheless, it needs to be dealt with.&lt;/p&gt;

&lt;p&gt;When I was starting my first game last year I was looking for this type of information for ideas and inspiration how to organize my projects, but I couldn't find any good resources. That rings extra true when you narrow it down to game development with Swift using Xcode.&lt;/p&gt;

&lt;p&gt;This is a breakdown of how I organized my latest game project in Xcode, version control and storage.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ever-evolving
&lt;/h2&gt;

&lt;p&gt;I recently finished my second game, &lt;a href="https://bitbebop.com/games/hypastorm/"&gt;Hypastorm&lt;/a&gt;, after having put my first game on hold for a while. Which kinda makes my second game the first, but more on that in another post to come.&lt;/p&gt;

&lt;p&gt;I started the second game as I felt I had learned so much since I began working on the first game. I wanted to try a new structure of my approach to game development on a new fresh canvas. I will now go back and reapply this structure to my first game.&lt;/p&gt;

&lt;p&gt;So, my game project structure did evolve a lot between the two games. And it is ever-changing and as I've now started pre-production on my third game, where I'm fine-tuning, streamlining and revising it even more.&lt;/p&gt;

&lt;p&gt;But for now, let's focus on how the second game ended up being handled.&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;I use git to version control the main code base and I keep the repository origin on GitHub.&lt;/p&gt;

&lt;p&gt;This has worked out fine, as the games I've been working on are not that heavy on art and sound. The repository sizes has a small footprint.&lt;/p&gt;

&lt;p&gt;The day I start a game that relies on more large assets I'll consider using Git LFS as the next step up.&lt;/p&gt;

&lt;p&gt;In Xcode I organized my last game like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Game Repository
+-- Shared
    +-- Entities
    +-- Components
    +-- Scenes
    +-- UI
    +-- Audio
    +-- Log
    +-- Utilities
    +-- Preload
    +-- Assets
    +-- Level.swift
    +-- ECS.swift
    +-- GameData.swift
    +-- GameConfig.swift
    +-- GameManager.swift
    +-- SceneManager.swift
+-- iOS
+-- tvOS
+-- macOS
+-- Nexus
+-- GameMath
+-- Tools
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A quick breakdown what goes in each folder/file above.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entities / Components&lt;/strong&gt;: The ECS, unique game mechanics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scenes&lt;/strong&gt;: Different game scenes with all possible game states, including the main finite game state machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UI&lt;/strong&gt;: The HUD, all-in game overlays and UI elements like buttons and labels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio&lt;/strong&gt;: My audio players and mixer. In my next game these are moved to the engine framework.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Log&lt;/strong&gt;: Debug logging and plenty of signposts for measuring performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Utilities&lt;/strong&gt;: Convenience methods and different extensions of Apple's frameworks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preload&lt;/strong&gt;: Handles preloading from disk and the decoding of assets into memory and onto the GPU. This is now mature enough to have been graduated into my engine framework for the next game.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Assets&lt;/strong&gt;: Graphics, sound effects, music, level data, json... You name it, it's here.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Level.swift&lt;/strong&gt;: Constructs a playable level from data on disk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ECS.swift&lt;/strong&gt;: Game specific extensions of my ECS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GameData.swift&lt;/strong&gt;: Data persistent between levels.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GameConfig.swift&lt;/strong&gt;: A central place to tweak game config and stats for entities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GameManager.swift&lt;/strong&gt;: Where it all begins...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SceneManager.swift&lt;/strong&gt;: Fade in / fade out. Handles adaptation to different screen sizes. Yada yada yada...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;iOS / tvOS / macOS&lt;/strong&gt;: The unique code for each platform target.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Nexus&lt;/strong&gt;: My lightweight game engine framework. Reduces common boilerplate code between games.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GameMath&lt;/strong&gt; My math library. Fills in the blanks of all necessary math operations not covered by Apple's frameworks. Did I hear trigonometry?&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;: Game specific tools. Mainly command line. Converters, generators, like my &lt;a href="https://github.com/artstorm/xc-assetcat-gen"&gt;Xcode Asset Catalog Generator&lt;/a&gt;,  and automation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have an old Mac mini with Xcode server that runs a small test suite for each platform when I make a new commit to the repository as an extra safety net to reduce the risk of breaking things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Assets
&lt;/h2&gt;

&lt;p&gt;The assets that are in the code repository above are the final, small, optimized exported versions. But then you need a location to work on the original source assets and store them, with versioning.&lt;/p&gt;

&lt;p&gt;I've chosen Git LFS for that and I keep the origin repository on Azure DevOps as they have a generous free tier that works for me.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Assets Repository
+-- Art
    +-- Entities
    +-- FX
    +-- Output
    +-- UI
+-- Audio
    +-- Title Music
    +-- In Game Music
    +-- Sound Effects
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A short breakdown of what might be noteworthy of the above structure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Art&lt;/strong&gt;: Here goes the Photoshop, Blender, Illustrator and other art files. The &lt;code&gt;Output&lt;/code&gt; directory is where I send exported/rendered versions of assets. I then have my conversion script in &lt;code&gt;Tools&lt;/code&gt; in the code repository that builds the Xcode asset catalog from here with optimized versions for different devices and screens.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audio&lt;/strong&gt;: Not much to say about this, I store all audio related work here. I make music and sound effects in Logic Pro X and I found saving the work using &lt;code&gt;Organize as folder&lt;/code&gt; instead of &lt;code&gt;as package&lt;/code&gt;, when saving the project, a bit more friendly when working with version control.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Rest
&lt;/h2&gt;

&lt;p&gt;Apart from the files that makes up what will become the game, there's a bunch of other types of files being generated during the game's development cycle.&lt;/p&gt;

&lt;p&gt;I've chosen to keep them on an ordinary cloud based sync service. I'm using iCloud Drive as I had a huge amount of unused storage available there. Otherwise I'd considered Dropbox.&lt;/p&gt;

&lt;p&gt;This could go in version control instead, but I felt that using a cloud drive for this made more sense. I can access the files everywhere, if I get any ideas when I'm out and about I can open the documents on my iPad and edit them on the go. Or use my Apple Pencil to illustrate ideas or flows.&lt;/p&gt;

&lt;p&gt;On top of that, it makes it easier to share this folder with non-coding people that I might give access to, for additional input or help with these parts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iCloud Drive
+-- Concept Art
+-- Documentation
+-- Marketing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the breakdown.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Concept Art&lt;/strong&gt;: My early initial drawings and collections of inspirational art and mood boards. PureRef is a great tool to organize inspirational art.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation&lt;/strong&gt;: Game Design Documents, my time log and asset tracking spreadsheets.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Marketing&lt;/strong&gt;: Videos and screenshots for Apple Store. Videos to share on social media. I actually haven't really had time to do any marketing, at all. Additional content will likely appear here later on. For now I've put my focus mainly on getting games done and build personal gamedev habits and workflows that works for me.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I hope you found the breakdowns of how I organized my last game project helpful. You might have got some useful ideas from how I organize my game projects that you can use or tweak.&lt;/p&gt;

&lt;p&gt;As I mentioned earlier, it is ever-evolving, and I've made multiple adjustments for the next game that I've started working on. I might revisit this article and make an updated version in a year from now.&lt;/p&gt;

&lt;p&gt;Keep coding!&lt;/p&gt;

</description>
      <category>swift</category>
      <category>gamedev</category>
      <category>xcode</category>
    </item>
  </channel>
</rss>
