{"id":1095,"date":"2023-12-04T14:26:15","date_gmt":"2023-12-04T03:26:15","guid":{"rendered":"https:\/\/noblesteedgames.com\/blog\/?p=1095"},"modified":"2023-12-04T14:43:24","modified_gmt":"2023-12-04T03:43:24","slug":"developing-games-with-porting-in-mind-plus-sample-code","status":"publish","type":"post","link":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/","title":{"rendered":"Developing Games with Porting in Mind &#8211; Plus sample code!"},"content":{"rendered":"\n<p>During a workshop on developing games with porting in mind, Reuben shared common programming pitfalls and approaches that make porting easy down the line. The following is an edited transcription of the workshop\u2019s contents, which we hope will be useful reading to fellow developers! For the full workshop recording, check out the YouTube upload <a href=\"https:\/\/youtu.be\/NVhktUHjbsc?si=VR61YgoyXHewZpv8\">here!<\/a><\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<div class=\"nv-iframe-embed\"><iframe loading=\"lazy\" title=\"Developing Games with Porting in Mind\" width=\"1200\" height=\"675\" src=\"https:\/\/www.youtube.com\/embed\/NVhktUHjbsc?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" allowfullscreen><\/iframe><\/div>\n<\/div><\/figure>\n\n\n\n<p>You can also find the sample project Reuben has made to illustrate the following topics <a href=\"https:\/\/gitlab.com\/no-moss-studios-public\/porting-sample\">here<\/a>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><a href=\"https:\/\/gitlab.com\/no-moss-studios-public\/porting-sample\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"502\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/5-1024x502.jpg\" alt=\"Screenshot of Porto's Adventure in Unity.\" class=\"wp-image-1114\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/5-1024x502.jpg 1024w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/5-600x294.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/5-300x147.jpg 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/5-768x376.jpg 768w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/5-1536x752.jpg 1536w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/5.jpg 1915w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure><\/div>\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p>We\u2019ve worked with several indie devs who have made a game on Steam that they want to port to Switch, Xbox, PlayStation or more. From this, we wanted to share some of the common pitfalls we have seen, especially from indie teams that are sometimes relatively new to making a game or going from hobby projects to commercial ventures. Here are my tips for developing your game in a way that makes porting easy down the line!<\/p>\n\n\n\n<p>Firstly, the suggestions in this blog are Unity-focused! Unity makes porting things pretty easy. Having done some porting work that was in Unreal Engine, my first tip, if you want to make a game that&#8217;s getting ported: use Unity.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"498\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/10-1024x498.jpg\" alt=\"Screenshot of Porto's Adventure in Unity Editor. We're on the first level, which is mostly yellow blocks with a yellow character hopping around.\" class=\"wp-image-1132\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/10-1024x498.jpg 1024w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/10-600x292.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/10-300x146.jpg 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/10-768x373.jpg 768w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/10-1536x747.jpg 1536w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/10.jpg 1917w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Here&#8217;s Porto&#8217;s Adventure in Unity: Not very pretty, but it&#8217;ll help us out with illustrating all the concepts we&#8217;re covering!<\/figcaption><\/figure><\/div>\n\n\n<p>Regardless, the things we&#8217;ll be talking about here will likely apply to other engines. This is because we aren\u2019t covering the specific aspects of the SDKs involved for these console platforms. We have NDAs that prevent us from showing anything, anyway!&nbsp;<\/p>\n\n\n\n<p>Instead, what we&#8217;ll be focusing on is how to structure your project to make it easy to port your game, regardless of what that platform is. This is relevant whether you ever even do port to a platform or not! (As is commonplace amongst indie teams.) These tips will also be more useful, as the actual things that you&#8217;d be implementing for your game are often different depending on your title.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cleaner code = games that are more painless to port<\/h2>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/media.giphy.com\/media\/l0HlKcmahAXyS7hJK\/giphy.gif\" alt=\"An animation of a cube walking and then hopping into a square shaped hole. It falls into it slowly and is a perfect fit.\"\/><figcaption class=\"wp-element-caption\">Setting up your project nicely segmented, modular, and clean, makes your game easier to port!<\/figcaption><\/figure><\/div>\n\n\n<p>The undercurrent theme throughout this blog is that: projects are easier to port the cleaner they are. If your project is laid out cleanly, nicely segmented and modular, that makes your project easier to port. We\u2019ll be talking about structures and techniques you can use to make your game cleaner in general, specifically in a way that helps with porting. Here are the specific concepts we\u2019ll be covering:<\/p>\n\n\n\n<ul>\n<li><a href=\"#services-models\">Services Model<\/a><\/li>\n\n\n\n<li><a href=\"#input\">Input<\/a><\/li>\n\n\n\n<li><a href=\"#saves\">Saves<\/a><\/li>\n\n\n\n<li><a href=\"#loading\">Loading<\/a><\/li>\n\n\n\n<li><a href=\"#platform-systems\">Platform systems<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"services-models\">Services Models<\/h2>\n\n\n\n<p>Services models are models that allow us to easily manage different components and, in the context of porting your games, allow us to switch them out based on platforms. This is not a porting-specific thing, but a general setup that is helpful to ensure that you&#8217;re setting your project up in a modular way.&nbsp;<\/p>\n\n\n\n<p>What a lot of indie teams start with is setting up a boot scene: a scene that initializes things for you. This is very helpful to have when you&#8217;re making a game that can be cross-platform because a lot of the platforms have things that need to happen at instantiation.&nbsp;<\/p>\n\n\n\n<p>But\u2026 something that we&#8217;ve seen with a few of our clients is that they will have things that exist inside this boot scene that are required for their game to run.<\/p>\n\n\n\n<p>The issue compounds itself as we attempt to initialise other scenes. For example, when we want to start from a specific level. We\u2019ve had clients say they resolve things by going \u201cI&#8217;ll just go to this level, drop this prefab, and make sure everything&#8217;s in there.\u201d That&#8217;s not a great system. You want a game that is set up in a clean and organised way that initializes itself no matter where you start.<\/p>\n\n\n\n<p>In our sample project, Porto&#8217;s Adventure, we share a general model for how we&#8217;ve done a few different things. It has a self-initializing core and an application plug-in. When your scenes boot up, they go to this application, the plug-in initializes and then the scene begins.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"348\" height=\"260\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/4-2.jpg\" alt=\"Screenshot of the application plug-in in the Unity Editor.\" class=\"wp-image-1113\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/4-2.jpg 348w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/4-2-300x224.jpg 300w\" sizes=\"(max-width: 348px) 100vw, 348px\" \/><figcaption class=\"wp-element-caption\">The application plug-in in action!<\/figcaption><\/figure><\/div>\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"772\" height=\"491\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/0.5.jpg\" alt=\"Screenshot of the application plug-in's source code.\" class=\"wp-image-1101\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/0.5.jpg 772w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/0.5-600x382.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/0.5-300x191.jpg 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/0.5-768x488.jpg 768w\" sizes=\"(max-width: 772px) 100vw, 772px\" \/><figcaption class=\"wp-element-caption\">A screenshot of our sample project&#8217;s application plugin.<\/figcaption><\/figure><\/div>\n\n\n<p>To illustrate, when attempting to load Porto\u2019s Adventure\u2019s menu scene, we have this <code>MenuController<\/code>, which is a subclass of a <code>SceneController<\/code>, which does the following:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"623\" height=\"497\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/2.jpg\" alt=\"A screenshot of our SceneController. \" class=\"wp-image-1104\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/2.jpg 623w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/2-600x479.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/2-300x239.jpg 300w\" sizes=\"(max-width: 623px) 100vw, 623px\" \/><figcaption class=\"wp-element-caption\">A screenshot of our <code>SceneController<\/code>. <\/figcaption><\/figure><\/div>\n\n\n<ol>\n<li>It Starts.<\/li>\n\n\n\n<li>Call this <code>InitializeScene<\/code> routine which initializes the app if it&#8217;s not initialized\u00a0<\/li>\n\n\n\n<li>Then calls this abstract function <code>OnSceneStart<\/code><\/li>\n\n\n\n<li>Then, on <code>OnSceneStart<\/code>, the menu controller selects the play button as the first piece of UI to load.<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"884\" height=\"495\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/1-2.jpg\" alt=\"A screenshot of our MenuController.\" class=\"wp-image-1103\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/1-2.jpg 884w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/1-2-600x336.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/1-2-300x168.jpg 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/1-2-768x430.jpg 768w\" sizes=\"(max-width: 884px) 100vw, 884px\" \/><figcaption class=\"wp-element-caption\">A screenshot of our <code>MenuController<\/code>.<\/figcaption><\/figure><\/div>\n\n\n<p>This is a simple setup, but important to understand conceptually especially if you&#8217;re porting your game from a PC build to consoles. It\u2019s common to overlook the concept that, on console, things take more time to initialize than you might expect.<\/p>\n\n\n\n<p>For example, on startup, say we&#8217;re loading up our menu and want to populate the volume settings to have that volume set based on <code>SaveData<\/code>, which might be 50%. On a console, loading that data is quite a process: you have to first make sure you&#8217;re signed in as a user, then get the data for that user. Potentially, you might have to do other things like mount the file system and those take <em>time<\/em>\u2014 they&#8217;re not going to happen in a cycle. So, something that we will typically do is enforce a system like this that has, as part of its initialization, asynchronous functions that wait for things to load.<\/p>\n\n\n\n<p>In addition, we don&#8217;t have to place a game controller in the scene. Our services model lets us wait for the application to tell us when things are finished initializing before things kick off.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"input\">Input<\/h2>\n\n\n\n<p>The first step for porting a game to consoles is making sure that it works with gamepad. If your game works with controllers on PC, it will be much easier to get it working with controllers on other consoles.<\/p>\n\n\n\n<p>If you&#8217;re developing a game in Unity and you want to get it to consoles: use the new Unity input system! It lets you bind actions and have all different kinds of control profiles for different controllers and buttons.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"258\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/6-1024x258.jpg\" alt=\"Screenshots of the Input Manager and New Unity Input System.\" class=\"wp-image-1115\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/6-1024x258.jpg 1024w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/6-600x151.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/6-300x76.jpg 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/6-768x194.jpg 768w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/6-1536x387.jpg 1536w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/6.jpg 2000w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">The Input Manager vs the new Unity Input System.<\/figcaption><\/figure><\/div>\n\n\n<p>This also works nicely with the Unity UI system, where it automatically detects key presses and navigates selectable components like buttons or dropdowns. You can get controller support for things like UI easily this way as a result.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"saves\">Saves<\/h2>\n\n\n\n<p>Centralise your <code>SaveData<\/code> as much as possible! The services model is great for this. In our example, you can see <code>SaveService<\/code> has very simple functions for waiting for save and load, which can be done asynchronously before continuing in our game when we&#8217;re loading from a different scene.<\/p>\n\n\n\n<p>When most folks start developing with Unity, they will likely use <code>PlayerPrefs<\/code>, which doesn&#8217;t work on consoles, so you don&#8217;t want to be using that! But even as a starting point, I think <code>PlayerPrefs <\/code>gets you into this terrible mindset of: \u201cI can access this static data from anywhere.\u201d If a client were using <code>PlayerPrefs<\/code>, we would have to replace them, but even then we might be accessing and adjusting data from a lot of different places making things disorganised.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/3-1.jpg\" alt=\"Screenshot of the SaveService.\" class=\"wp-image-1109\" width=\"819\" height=\"546\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/3-1.jpg 858w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/3-1-600x401.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/3-1-300x200.jpg 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/3-1-768x513.jpg 768w\" sizes=\"(max-width: 819px) 100vw, 819px\" \/><figcaption class=\"wp-element-caption\">Screenshot of the <code>SaveService<\/code>.<\/figcaption><\/figure><\/div>\n\n\n<p>That\u2019s why we use <code>SaveService<\/code>, which has one reference to <code>SaveData<\/code>. The only way to access and load <code>SaveData<\/code> is through this service centralising it all. Though saves can get complex, most projects will find it fine to do what I&#8217;m doing here, which is just serializing it as JSON and then converting that to saving.<\/p>\n\n\n\n<p>You can encrypt this and get crazier as you want to but the point of this is to set up your system in a way that things are centralised. Then, if you want to encrypt <code>SavedData<\/code>, change the data to binary, or do any other transformations, because it&#8217;s all centralised, these become easy to do.<\/p>\n\n\n\n<p>Yet another example of that is the <code>SaveWriter <\/code>class. <code>SaveService<\/code> accesses <code>SaveWriter<\/code>, which is another service, but SaveWriter is abstract with a basic <code>FileSaveWriter<\/code>. This has some overrides: a <code>PlayStationFileSaveWriter<\/code>, a <code>SwitchFileSaveWriter<\/code> and an <code>XboxFileSaveWriter<\/code>. In Porto\u2019s Adventure, these are all blank, but in essence, for porting we\u2019ll need separate save logic for each platform we\u2019re porting to.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"257\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/image-1-1-1024x257.png\" alt=\"Screenshot showcasing the overrides for FileSaveWriter\" class=\"wp-image-1116\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/image-1-1-1024x257.png 1024w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/image-1-1-600x151.png 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/image-1-1-300x75.png 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/image-1-1-768x193.png 768w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/image-1-1.png 1090w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Screenshot showcasing the overrides for <code>FileSaveWriter<\/code><\/figcaption><\/figure><\/div>\n\n\n<p>For most of them you\u2019ll need to have a logged-in user to <code>SaveData<\/code> and you&#8217;ll need to mount to that user file system and confirm that you can save data as that user. With a system like this, you can have an abstract version of a service. Your <code>SaveService<\/code> doesn&#8217;t care what <code>SaveData<\/code> it has, it just cares that it has one that&#8217;s initialized. You can plug that in later with a different platform service,<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"loading\">Loading<\/h2>\n\n\n\n<p>Loading is yet another aspect of your game that is better as a service. Similar to what we talked about for the <code>SaveService<\/code>, it\u2019s good to be centralised. This <code>LoadScene<\/code> async function calls the <code>SceneManager<\/code> to load scene.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"690\" height=\"353\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/7-1.jpg\" alt=\"Screenshot of SceneService and how it loads scenes.\" class=\"wp-image-1118\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/7-1.jpg 690w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/7-1-600x307.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/7-1-300x153.jpg 300w\" sizes=\"(max-width: 690px) 100vw, 690px\" \/><figcaption class=\"wp-element-caption\">Screenshot of <code>SceneService<\/code> and how it loads scenes.<\/figcaption><\/figure><\/div>\n\n\n<p>It&#8217;s doing nothing at all in this scene service but that&#8217;s okay because it&#8217;s centralised.<\/p>\n\n\n\n<p>Down the line, we might want to do things depending on the platform or something else, like turning this into asynchronous loading, loading asset bundles, transitioning to a loading scene or doing a fade in and out. By centralising our efforts, making them consistent across loads and simple at the start of our project, we make things easier for any added complexity in the future.<\/p>\n\n\n\n<p>Things change throughout development. You might want to have things less centralised things into services later, but starting off this way means you can go crazy with them down the line without having to worry about needing to change a bunch of different load calls. For console porting, there are a lot of upgrades that you might need to do to your loading scene. For example, depending on the platform, you might want to implement addressables to cut down patch sizes or cut down the size of your executable and all that jazz.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"platform-systems\">Platform Systems<\/h2>\n\n\n\n<p>This is going to be another example of when our services model becomes very helpful. To illustrate, when we boot up Porto\u2019s Adventure, we&#8217;ll initialize all of our services, including our <code>PlatformService<\/code>. It has <code>PlatformFactoryService<\/code> which initializes all of our other services depending on what platform we&#8217;re on.\u00a0<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"457\" height=\"491\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/8.jpg\" alt=\"Screenshot of PlatformService in the Unity Editor.\" class=\"wp-image-1119\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/8.jpg 457w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/8-279x300.jpg 279w\" sizes=\"(max-width: 457px) 100vw, 457px\" \/><figcaption class=\"wp-element-caption\"><code>PlatformService<\/code> in action! <\/figcaption><\/figure><\/div>\n\n\n<p>So, if we&#8217;re on editor, we create an initial <code>EditorPlatformService<\/code>, Standalone, Switch, PS5 and so forth. Those platform services have their own initialize that does things like add a file, <code>SaveWriter<\/code> and so forth.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"518\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/9-1-1024x518.jpg\" alt=\"Screenshot showing the various platform services initialised by Platform Factory Service.\" class=\"wp-image-1121\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/9-1-1024x518.jpg 1024w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/9-1-600x304.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/9-1-300x152.jpg 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/9-1-768x389.jpg 768w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/9-1.jpg 1110w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><figcaption class=\"wp-element-caption\">Services for each platform!<\/figcaption><\/figure><\/div>\n\n\n<p>Like the save system, you want to switch out different versions of a service without necessarily any of the rest of the logic. For a practical example, achievements: All platforms use different achievements. So if we&#8217;re deploying on Steam we would have Steam achievements, PlayStation would have trophies, Xbox has achievements, Switch doesn&#8217;t have achievements and other cases. We might want to have a system for Switch, where we have a <code>SwitchAchievementService<\/code> which effectively does nothing except logging to a file.<\/p>\n\n\n\n<p>It doesn&#8217;t matter to the code what that achievement service is, whether it&#8217;s the <code>PlayStationAchievementService<\/code>, the <code>SteamAchievementService<\/code>, or the kind of no-achievement service that we might implement for Switch, this code just calls whatever <code>AchievementService<\/code> is available, and it\u2019s up to the service to handle its own implementation of these achievements, without any need for a big \u201cAchievement Manager\u201d.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/achievements-5.jpg\" alt=\"A screenshot of the achievements in Every Hue of You on Steam.\" class=\"wp-image-1128\" width=\"819\" height=\"381\" srcset=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/achievements-5.jpg 1005w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/achievements-5-600x279.jpg 600w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/achievements-5-300x140.jpg 300w, https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/achievements-5-768x358.jpg 768w\" sizes=\"(max-width: 819px) 100vw, 819px\" \/><figcaption class=\"wp-element-caption\">The Steam achievements for <a href=\"\/projects\/project.php?p=everyhueofyou\">Every Hue of You<\/a><\/figcaption><\/figure><\/div>\n\n\n<p>This system can become complex if, for example, the console we\u2019re developing for can have multiple different users logged in and multiple different users should be able to progress their own achievements while they&#8217;re logged in. Even when things get incredibly complex due to platform specifics, a services model like this that allows you to swap things in and out makes development much easier.<\/p>\n\n\n\n<p>We can easily set this up, and all these services would handle themselves completely independently and modularly. The only place where we would need to use any custom defines is in that factory that has added those different services.&nbsp;<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">To conclude<\/h2>\n\n\n\n<p>We hope this helped you rethink how you structure your projects to make them easier for porting! We\u2019ve skipped out on the QnA covered in the workshop, so if you\u2019d like to have a listen, the video\u2019s<a href=\"https:\/\/youtu.be\/NVhktUHjbsc?si=kt71LumfEl6X4nbQ\"> here.<\/a> As for the sample project,<a href=\"https:\/\/gitlab.com\/no-moss-studios-public\/porting-sample\"> Porto\u2019s Adventure,<\/a> take a look and steal those plugins!<\/p>\n\n\n\n<p>We hope you enjoyed reading this! Have a question or want to chat more about game development?&nbsp;<a href=\"mailto:hello@noblesteed.games\" data-type=\"mailto\" data-id=\"mailto:hello@noblesteed.games\"><strong>Reach out to us!<\/strong><\/a><\/p>\n\n\n\n<p>Other places you can find us:<\/p>\n\n\n\n<ul>\n<li>Our other&nbsp;<a href=\"https:\/\/noblesteedgames.com\/blog\/category\/gamedev-resources\/\">game development resources<\/a><\/li>\n\n\n\n<li>Join our<a href=\"https:\/\/discord.com\/invite\/Ka8suskKcs\">&nbsp;Discord serve<\/a>r<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Some tips on avoiding common programming pitfalls and approaches that make porting games to consoles easier!<\/p>\n","protected":false},"author":1,"featured_media":1131,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[48,40],"tags":[28,31,79,6],"ppma_author":[65,66],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v23.1 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Developing Games with Porting in Mind - Plus sample code! | Dev Blog<\/title>\n<meta name=\"description\" content=\"Some tips on avoiding common programming pitfalls and approaches that make porting games to consoles easier!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Developing Games with Porting in Mind - Plus sample code! | Dev Blog\" \/>\n<meta property=\"og:description\" content=\"Some tips on avoiding common programming pitfalls and approaches that make porting games to consoles easier!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/\" \/>\n<meta property=\"og:site_name\" content=\"Noble Steed Games\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/NobleSteedAU\" \/>\n<meta property=\"article:published_time\" content=\"2023-12-04T03:26:15+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2023-12-04T03:43:24+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"900\" \/>\n\t<meta property=\"og:image:height\" content=\"378\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Reuben, Ann Li\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@NobleSteedAU\" \/>\n<meta name=\"twitter:site\" content=\"@NobleSteedAU\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Reuben\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"12 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/\"},\"author\":{\"name\":\"Reuben\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#\/schema\/person\/72236c3fe545f797cc0ce4635c1ca1a9\"},\"headline\":\"Developing Games with Porting in Mind &#8211; Plus sample code!\",\"datePublished\":\"2023-12-04T03:26:15+00:00\",\"dateModified\":\"2023-12-04T03:43:24+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/\"},\"wordCount\":2074,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg\",\"keywords\":[\"game development\",\"indie dev\",\"porting\",\"Unity\"],\"articleSection\":[\"E-Books &amp; Downloadable Resources\",\"Gamedev Resources\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/\",\"url\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/\",\"name\":\"Developing Games with Porting in Mind - Plus sample code! | Dev Blog\",\"isPartOf\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg\",\"datePublished\":\"2023-12-04T03:26:15+00:00\",\"dateModified\":\"2023-12-04T03:43:24+00:00\",\"description\":\"Some tips on avoiding common programming pitfalls and approaches that make porting games to consoles easier!\",\"breadcrumb\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#primaryimage\",\"url\":\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg\",\"contentUrl\":\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg\",\"width\":900,\"height\":378,\"caption\":\"Photos of our games ported to Switch, PS5 and feature phones.\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/noblesteedgames.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Developing Games with Porting in Mind &#8211; Plus sample code!\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#website\",\"url\":\"https:\/\/noblesteedgames.com\/blog\/\",\"name\":\"Noble Steed Games\",\"description\":\"Stories from Development\",\"publisher\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/noblesteedgames.com\/blog\/?s={search_term_string}\"},\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#organization\",\"name\":\"Noble Steed Games\",\"url\":\"https:\/\/noblesteedgames.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/PFP.jpg\",\"contentUrl\":\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/PFP.jpg\",\"width\":1374,\"height\":1374,\"caption\":\"Noble Steed Games\"},\"image\":{\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#\/schema\/logo\/image\/\"},\"sameAs\":[\"https:\/\/www.facebook.com\/NobleSteedAU\",\"https:\/\/x.com\/NobleSteedAU\",\"https:\/\/www.instagram.com\/noblesteedau\/\",\"https:\/\/www.linkedin.com\/company\/18263569\/\",\"https:\/\/www.youtube.com\/channel\/UC-CE2Op8dEH0LET0t9Zw79g\",\"https:\/\/twitter.com\/NobleSteedAU\"]},{\"@type\":\"Person\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#\/schema\/person\/72236c3fe545f797cc0ce4635c1ca1a9\",\"name\":\"Reuben\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/noblesteedgames.com\/blog\/#\/schema\/person\/image\/b281395bed28c3024dda9576a32f5794\",\"url\":\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/IMG_20231006_131634.jpg\",\"contentUrl\":\"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/IMG_20231006_131634.jpg\",\"caption\":\"Reuben\"},\"sameAs\":[\"https:\/\/noblesteedgames.com\/blog\/\"],\"url\":\"https:\/\/noblesteedgames.com\/blog\/author\/studios-admin\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Developing Games with Porting in Mind - Plus sample code! | Dev Blog","description":"Some tips on avoiding common programming pitfalls and approaches that make porting games to consoles easier!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/","og_locale":"en_US","og_type":"article","og_title":"Developing Games with Porting in Mind - Plus sample code! | Dev Blog","og_description":"Some tips on avoiding common programming pitfalls and approaches that make porting games to consoles easier!","og_url":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/","og_site_name":"Noble Steed Games","article_publisher":"https:\/\/www.facebook.com\/NobleSteedAU","article_published_time":"2023-12-04T03:26:15+00:00","article_modified_time":"2023-12-04T03:43:24+00:00","og_image":[{"width":900,"height":378,"url":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg","type":"image\/jpeg"}],"author":"Reuben, Ann Li","twitter_card":"summary_large_image","twitter_creator":"@NobleSteedAU","twitter_site":"@NobleSteedAU","twitter_misc":{"Written by":"Reuben","Est. reading time":"12 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#article","isPartOf":{"@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/"},"author":{"name":"Reuben","@id":"https:\/\/noblesteedgames.com\/blog\/#\/schema\/person\/72236c3fe545f797cc0ce4635c1ca1a9"},"headline":"Developing Games with Porting in Mind &#8211; Plus sample code!","datePublished":"2023-12-04T03:26:15+00:00","dateModified":"2023-12-04T03:43:24+00:00","mainEntityOfPage":{"@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/"},"wordCount":2074,"commentCount":0,"publisher":{"@id":"https:\/\/noblesteedgames.com\/blog\/#organization"},"image":{"@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#primaryimage"},"thumbnailUrl":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg","keywords":["game development","indie dev","porting","Unity"],"articleSection":["E-Books &amp; Downloadable Resources","Gamedev Resources"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/","url":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/","name":"Developing Games with Porting in Mind - Plus sample code! | Dev Blog","isPartOf":{"@id":"https:\/\/noblesteedgames.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#primaryimage"},"image":{"@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#primaryimage"},"thumbnailUrl":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg","datePublished":"2023-12-04T03:26:15+00:00","dateModified":"2023-12-04T03:43:24+00:00","description":"Some tips on avoiding common programming pitfalls and approaches that make porting games to consoles easier!","breadcrumb":{"@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#primaryimage","url":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg","contentUrl":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/porting.jpg","width":900,"height":378,"caption":"Photos of our games ported to Switch, PS5 and feature phones."},{"@type":"BreadcrumbList","@id":"https:\/\/noblesteedgames.com\/blog\/developing-games-with-porting-in-mind-plus-sample-code\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/noblesteedgames.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Developing Games with Porting in Mind &#8211; Plus sample code!"}]},{"@type":"WebSite","@id":"https:\/\/noblesteedgames.com\/blog\/#website","url":"https:\/\/noblesteedgames.com\/blog\/","name":"Noble Steed Games","description":"Stories from Development","publisher":{"@id":"https:\/\/noblesteedgames.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/noblesteedgames.com\/blog\/?s={search_term_string}"},"query-input":"required name=search_term_string"}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/noblesteedgames.com\/blog\/#organization","name":"Noble Steed Games","url":"https:\/\/noblesteedgames.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/noblesteedgames.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/PFP.jpg","contentUrl":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/PFP.jpg","width":1374,"height":1374,"caption":"Noble Steed Games"},"image":{"@id":"https:\/\/noblesteedgames.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/NobleSteedAU","https:\/\/x.com\/NobleSteedAU","https:\/\/www.instagram.com\/noblesteedau\/","https:\/\/www.linkedin.com\/company\/18263569\/","https:\/\/www.youtube.com\/channel\/UC-CE2Op8dEH0LET0t9Zw79g","https:\/\/twitter.com\/NobleSteedAU"]},{"@type":"Person","@id":"https:\/\/noblesteedgames.com\/blog\/#\/schema\/person\/72236c3fe545f797cc0ce4635c1ca1a9","name":"Reuben","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/noblesteedgames.com\/blog\/#\/schema\/person\/image\/b281395bed28c3024dda9576a32f5794","url":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/IMG_20231006_131634.jpg","contentUrl":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/IMG_20231006_131634.jpg","caption":"Reuben"},"sameAs":["https:\/\/noblesteedgames.com\/blog\/"],"url":"https:\/\/noblesteedgames.com\/blog\/author\/studios-admin\/"}]}},"authors":[{"term_id":65,"user_id":1,"is_guest":0,"slug":"studios-admin","display_name":"Reuben","avatar_url":{"url":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/IMG_20231006_131634.jpg","url2x":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/IMG_20231006_131634.jpg"},"user_url":"https:\/\/noblesteedgames.com\/blog\/","last_name":"Moorhouse","first_name":"Reuben","job_title":"","description":""},{"term_id":66,"user_id":2,"is_guest":0,"slug":"annnomoss-co","display_name":"Ann Li","avatar_url":{"url":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/T04BCCRJU9M-U04D8Q5K2R0-8125c3e23c8c-512.jpg","url2x":"https:\/\/noblesteedgames.com\/blog\/wp-content\/uploads\/2023\/12\/T04BCCRJU9M-U04D8Q5K2R0-8125c3e23c8c-512.jpg"},"user_url":"","last_name":"Khaw","first_name":"Ann Li","job_title":"","description":""}],"_links":{"self":[{"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/posts\/1095"}],"collection":[{"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/comments?post=1095"}],"version-history":[{"count":13,"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/posts\/1095\/revisions"}],"predecessor-version":[{"id":1139,"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/posts\/1095\/revisions\/1139"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/media\/1131"}],"wp:attachment":[{"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/media?parent=1095"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/categories?post=1095"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/tags?post=1095"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/noblesteedgames.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=1095"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}