{"id":341,"date":"2021-04-24T14:14:03","date_gmt":"2021-04-24T14:14:03","guid":{"rendered":"https:\/\/bronsonzgeb.com\/?p=341"},"modified":"2021-05-04T18:25:30","modified_gmt":"2021-05-04T18:25:30","slug":"unity-architecture-pattern-the-main-loop","status":"publish","type":"post","link":"https:\/\/bronsonzgeb.com\/index.php\/2021\/04\/24\/unity-architecture-pattern-the-main-loop\/","title":{"rendered":"Unity Architecture Pattern: the Main loop"},"content":{"rendered":"\n<p>This article will show the benefits of using a main loop as a foundational structure for your Unity games. The main loop is a powerful pattern that makes projects easier to debug and maintain and scales very well for projects of any size. It even has performance benefits.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What is a main loop?<\/h2>\n\n\n\n<p>Let me start by saying this isn&#8217;t a new concept. If you were making a game outside of Unity, you&#8217;d have a loop at the core of your game. By the way, Unity has one too, but you can&#8217;t see it. In that context, a main loop is nothing but a loop that runs at 60 frames per second, collects input, updates your game objects, and renders the game. The main loop pattern in this article is similar to that.<\/p>\n\n\n\n<p>I&#8217;m suggesting a main MonoBehaviour (let&#8217;s call it <code>GameManager.cs<\/code>, <code>GameMain.cs<\/code> or even just <code>Game.cs<\/code>) responsible for updating all the other game objects in your scene. In other words, there&#8217;s only a single <code>Update()<\/code> function. This might sound tedious, but in fact, it makes your code simpler. Additionally, the benefits are well worth any extra effort, in my opinion. Before exploring the advantages, let&#8217;s first look at the structure of a typical Unity scene.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">A typical Unity scene<\/h2>\n\n\n\n<p>A typical scene consists of a loose collection of MonoBehaviours that are supposed to initialize and update independently. The goal is to have modular components that drop into a scene and &#8220;just work.&#8221; In reality, this adds complexity, reduces debuggability, increases maintenance costs, and frankly makes life more complicated than it has to be. With only a little bit of structure, you can avoid these issues. In my experience, it rarely works out how I imagined it would.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/bronsonzgeb.com\/wp-content\/uploads\/2021\/04\/No-MainLoop.png\" alt=\"\" class=\"wp-image-345\" width=\"500\" height=\"377\"\/><figcaption>A Typical Unity Scene<\/figcaption><\/figure><\/div>\n\n\n\n<p>There&#8217;s no clear entry point into the initialization of a scene like the one described above. What I mean is, to understand how a given scene initializes, you&#8217;d have to find every script referenced in the scene and piece together all the <code>Awake()<\/code> and <code>Start()<\/code> functions. What&#8217;s more, the order of execution is either hidden in the Order of Execution settings or implicitly defined. This might be manageable (albeit annoying) for a handful of objects, but it scales poorly as your scene grows. Furthermore, because the initialization order isn&#8217;t defined, you end up with null checks all over the place. Some objects may even wait until the first <code>Update()<\/code> frame to initialize fully. If any of this is familiar, then the good news is I have a solution for you.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Initialization single entry point<\/h2>\n\n\n\n<p>Having a single <code>MonoBehaviour<\/code> that&#8217;s in charge of initializing your scene solves these problems. Rather than relying on a vague group of <code>Awake()<\/code> and <code>Start()<\/code> methods, you can take complete control of your initialization by defining a single <code>Start()<\/code> method on your <code>GameManager<\/code>. The <code>GameManager<\/code> initializes all other managers in the scene, which initializes all the objects in your scene. As a result, you&#8217;ll know for certain that this single <code>Start()<\/code> method initializes everything in your scene. <\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-large is-resized\"><img decoding=\"async\" src=\"https:\/\/bronsonzgeb.com\/wp-content\/uploads\/2021\/04\/MainLoop.png\" alt=\"\" class=\"wp-image-346\" width=\"500\" srcset=\"https:\/\/bronsonzgeb.com\/wp-content\/uploads\/2021\/04\/MainLoop.png 960w, https:\/\/bronsonzgeb.com\/wp-content\/uploads\/2021\/04\/MainLoop-300x225.png 300w, https:\/\/bronsonzgeb.com\/wp-content\/uploads\/2021\/04\/MainLoop-768x576.png 768w\" sizes=\"(max-width: 960px) 100vw, 960px\" \/><figcaption>A Unity scene with a main loop<\/figcaption><\/figure><\/div>\n\n\n\n<p>What&#8217;s more, you can remove any null reference checks because you control the order of initialization. Your code will be so straightforward to read that even a junior developer who has never used Unity could understand it. Why is that? There are two reasons. First of all, you&#8217;re not relying on any behind-the-scenes magic except for a single <code>Start()<\/code> function call. Second, if you open any <code>MonoBehaviour<\/code> in your IDE, you&#8217;ll be able to track its initialization back to a single entry point. That is, you no longer have to hunt down everything <code>Start()<\/code> method in the project. You follow your initialization method (I usually call it <code>OnCreated()<\/code> or <code>OnStart()<\/code>) back up the chain until you reach the point where it&#8217;s called. This approach is also great for onboarding new developers to the project. If this sounds appealing to you, then the good news is it gets better. You can take everything I said here and apply it to your <code>Update()<\/code> function as well. That gives you a single entry point into your frame.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Update single entry point<\/h2>\n\n\n\n<p>Having a single entry point into your game&#8217;s update loop has all the same advantages as initialization. The update loop is simple to follow and understand. The order of execution is explicitly defined. It&#8217;s also easier to debug a frame by dropping a breakpoint in <code>Update()<\/code> and stepping through. There are more advantages too, such as controlling which objects are updated. That is to say, pausing object execution becomes trivial. For example, if you open a menu, you may want to pause everything that&#8217;s running behind it. Some developers pause their game by setting the <code>timescale<\/code> to 0, but you can&#8217;t animate your menus if you do this. You could collect all the objects in your scene that aren&#8217;t part of the menu and disable them, but I find this approach unreliable. With the main loop approach, you simply don&#8217;t call <code>Update()<\/code> on any gameplay objects if a menu is open.<\/p>\n\n\n\n<p>Another side effect of using this pattern is that you must keep runtime lists of your objects. As it turns out, this is useful in many cases. For example, if you need to save all the dynamic props in your game&#8217;s positions, you already have a list of them to iterate over. Or maybe you need to clear out all the projectiles before a cutscene starts. When it&#8217;s time to optimize your game you could decide to update a slice of the list on each frame, granting an instant performance boost. I&#8217;ve personally benefited from having runtime lists of my objects countless times. On that note, let&#8217;s get into performance.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Performance<\/h2>\n\n\n\n<p>Aside from all these architectural benefits, there are also performance benefits for using this pattern. As it turns out, there&#8217;s a hidden cost to calling <code>Update()<\/code> and <code>FixedUpdate()<\/code> in Unity. And so, another happy side effect of the main loop pattern is you sidestep this problem entirely and automatically have improved performance. The increased performance is especially beneficial on mobile platforms where there&#8217;s a fixed thermal headroom. I mean that mobile devices can output a certain amount of energy per frame before the hardware throttles performance. On other hardware, optimizing anything other than bottlenecks won&#8217;t result in improved performance. However, all optimizations matter on mobile devices because any optimization can lower energy usage and free up energy for other systems.<\/p>\n\n\n\n<p>I hope you find this pattern beneficial when structuring your projects. In my experience, using a main loop leads to simple, maintainable code that scales from small jam projects to large productions.<\/p>\n\n\n\n<p><strong>Check out the example project on GitHub <a href=\"https:\/\/github.com\/bzgeb\/UnityMainLoopExample\">here<\/a>. If you liked this article,\u00a0<\/strong><a rel=\"noreferrer noopener\" target=\"_blank\" href=\"https:\/\/bronsonzgeb.com\/index.php\/join-my-mailing-list\/\"><strong>join my mailing list<\/strong><\/a><strong>\u00a0to be notified whenever a new post comes out. Mailing list subscribers also have the opportunity to ask me to cover specific topics. So if you didn&#8217;t like this article,\u00a0<\/strong><a rel=\"noreferrer noopener\" target=\"_blank\" href=\"https:\/\/bronsonzgeb.com\/index.php\/join-my-mailing-list\/\"><strong>join my mailing list<\/strong><\/a><strong>\u00a0anyway and ask me to cover something else.<\/strong><\/p>\n","protected":false},"excerpt":{"rendered":"<p>This article will show the benefits of using a main loop as a foundational structure for your Unity games. The main loop is a powerful pattern that makes projects easier to debug and maintain and scales very well for projects of any size. It even has performance benefits. What is a main loop? Let me [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":346,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[28,1],"tags":[30,5],"class_list":["post-341","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-architecture","category-unity-programming","tag-architecture","tag-unity"],"_links":{"self":[{"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/posts\/341","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/comments?post=341"}],"version-history":[{"count":6,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/posts\/341\/revisions"}],"predecessor-version":[{"id":353,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/posts\/341\/revisions\/353"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/media\/346"}],"wp:attachment":[{"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/media?parent=341"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/categories?post=341"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bronsonzgeb.com\/index.php\/wp-json\/wp\/v2\/tags?post=341"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}