{"id":304,"date":"2022-09-17T15:11:34","date_gmt":"2022-09-17T15:11:34","guid":{"rendered":"https:\/\/docs.sisus.co\/init-args\/?p=304"},"modified":"2026-09-17T10:41:54","modified_gmt":"2026-09-17T10:41:54","slug":"creating-a-component","status":"publish","type":"post","link":"https:\/\/docs.sisus.co\/init-args\/getting-started\/creating-a-component\/","title":{"rendered":"2. Creating Your First Component"},"content":{"rendered":"<h1>What Is Dependency Injection<\/h1>\n<p>Creating new components using the base classes in Init(args) is very similar to how it would work normally in Unity. The key difference is how the component obtains references to other objects that it depends on (its dependencies).<\/p>\n<p>Instead of components manually retrieving their dependencies using various methods like GameObject.Find, FindObjectOfType, GetComponent, and Singleton accessors, they just receive all their dependencies through their Init function without having to do anything for it. This design pattern is called <a href=\"https:\/\/en.wikipedia.org\/wiki\/Dependency_injection\">Dependency Injection<\/a>. With the component no longer being responsible for figuring out how all it dependencies should be resolved, it can become more focused on its main responsibility and much more flexible.<\/p>\n<h1>Tightly-Coupled Components<\/h1>\n<p>Let&#8217;s say you wanted to create a Player component. You want the GameObject to which the Player component is attached to move when movement input is given, relative to the facing of the camera.<\/p>\n<pre>using UnityEngine;\r\n\r\npublic class Player : MonoBehaviour\r\n{\r\n    void Update()\r\n    {\r\n        Vector2 moveInput = inputManager.MoveInput;\r\n\r\n        if(moveInput != Vector2.zero)\r\n        {\r\n            const float speed = 0.2f;\r\n            float time = Time.deltaTime;\r\n            float distance = time * speed;\r\n\r\n            Vector3 moveDirection = camera.transform.rotation * moveInput;\r\n\r\n            transform.Translate(moveDirection * distance);\r\n        }\r\n    }\r\n}<\/pre>\n<p>In order for this Player class to function, it requires instances of the InputManager and Camera classes.<\/p>\n<p>Now one common and straight-forward strategy for resolving a dependency is by having a static property that holds a shared instance of a class, which the dependent class can use to retrieve the instance. This is often implemented using the <a href=\"https:\/\/en.wikipedia.org\/wiki\/Singleton_pattern\">singleton pattern<\/a>.<\/p>\n<pre>using UnityEngine;\r\n\r\npublic class Player : MonoBehaviour\r\n{\r\n    void Update()\r\n    {\r\n        \/\/ Gets the singleton instance via the static property.\r\n        Vector2 moveInput = InputManager.Instance.MoveInput;\r\n\r\n        if(moveInput != Vector2.zero)\r\n        {\r\n            const float speed = 0.2f;\r\n            float time = Time.deltaTime;\r\n            float distance = time * speed;\r\n\r\n            \/\/ Gets the first active Camera with the tag \"MainCamera\" from the loaded scenes.\r\n            Vector3 moveDirection = Camera.main.transform.rotation * moveInput;\r\n\r\n            transform.Translate(moveDirection * distance);\r\n        }\r\n    }\r\n}<\/pre>\n<p>This approach has some issues though. One of them is that the dependencies of the component are hidden, scattered across the body of the class. This means you need to read through the whole script to understand what other objects you need to add to your scene for this component to work.<\/p>\n<p>Another issue is that it&#8217;s very rigid: the class only works with a specific InputManager singleton object, and only with a specific Camera in the scene that has been assigned the &#8220;MainCamera&#8221; tag.<\/p>\n<p>You could also take a different approach, and use <a href=\"https:\/\/docs.unity3d.com\/ScriptReference\/SerializeField.html\">serialized fields<\/a> instead.<\/p>\n<pre>using UnityEngine;\r\n\r\npublic class Player : MonoBehaviour\r\n{\r\n    [SerializeField]\r\n    InputManager inputManager;\r\n\r\n    [SerializeField]\r\n    Camera camera;\r\n\r\n    void Update()\r\n    {\r\n        Vector2 moveInput = inputManager.MoveInput;\r\n\r\n        if(moveInput != Vector2.zero)\r\n        {\r\n            const float speed = 0.2f;\r\n            float time = Time.deltaTime;\r\n            float distance = time * speed;\r\n\r\n            Vector3 moveDirection = camera.transform.rotation * moveInput;\r\n\r\n            transform.Translate(moveDirection * distance);\r\n        }\r\n    }\r\n}<\/pre>\n<p>This solves some of the issues when it comes to flexibility. Now it&#8217;s possible to drag-and-drop any Camera or InputManager object in and the Player class will use them! This is in fact a form of dependency injection.<\/p>\n<p>But this approach isn&#8217;t without its problems either. If you need to change your InputManager to a different instance a couple months later, you will need to go change references in all components across the whole project by hand to point to the new instance. Also when working with prefabs, multiple scenes, or objects that are only created at runtime, it could be impossible to drag-and-drop references in. Not to mention creating unit tests for this component would be very difficult.<\/p>\n<p>So how can we get rid of all these limitations and downsides, and create loosely coupled components that are as flexible as possible, as well as easily unit testable by default?<\/p>\n<h1>MonoBehaviour&lt;T&#8230;&gt;<\/h1>\n<p>The first thing we need to change is explicitly define all the other types that the Player class depends on, as generic arguments of the MonoBehaviour base class.<\/p>\n<pre>public class Player : MonoBehaviour&lt;InputManager, Camera&gt;<\/pre>\n<p>To make this component as flexible as possible, let&#8217;s also change the dependency from the concrete InputManager class, into a dependency to an IInputManager interface instead. This way it&#8217;s possible to very easily swap the component to use a different implementation at any point. This can be especially useful when writing unit tests.<\/p>\n<pre>public class Player : MonoBehaviour&lt;IInputManager, Camera&gt;<\/pre>\n<p>Normally using interfaces in Unity is problematic, firstly because Unity&#8217;s serializer doesn&#8217;t support Object references in interface type fields, and secondly because there&#8217;s no Inspector support for interfaces that would allow any other type of data into these fields either. With Init(args) these are no longer an issue, so we can use interfaces as much as we want.<\/p>\n<p>After this you&#8217;ll need to do two things to get the code to compile:<\/p>\n<ol>\n<li>Import types from the <code>Sisus.Init<\/code> namespace with a using directive.<\/li>\n<li>Implement the <code>Init<\/code> method to receive the IInputManager and Camera references and assign them into fields.<\/li>\n<\/ol>\n<p>You can automatically do both by selecting the <code>Generate Init method<\/code> context action in your IDE.<\/p>\n<p><img loading=\"lazy\" class=\"alignnone size-full wp-image-1146\" src=\"https:\/\/docs.sisus.co\/init-args\/wp-content\/uploads\/sites\/6\/2022\/09\/2026-09-17-12_58_06-Init-args-\u2013-Player.cs_.png\" alt=\"Generate Init method\" width=\"641\" height=\"146\" srcset=\"https:\/\/docs.sisus.co\/init-args\/wp-content\/uploads\/sites\/6\/2022\/09\/2026-09-17-12_58_06-Init-args-\u2013-Player.cs_.png 641w, https:\/\/docs.sisus.co\/init-args\/wp-content\/uploads\/sites\/6\/2022\/09\/2026-09-17-12_58_06-Init-args-\u2013-Player.cs_-300x68.png 300w\" sizes=\"(max-width: 641px) 100vw, 641px\" \/><\/p>\n<p>If your IDE cannot resolve the <code>Sisus<\/code> namespace, you might need first add <em>InitArgs<\/em> to the <em>Assembly Definition References<\/em> list in your <a href=\"https:\/\/docs.unity3d.com\/Manual\/assembly-definitions-creating.html\"><em>Assembly Definition Asset<\/em><\/a>.<\/p>\n<p><img loading=\"lazy\" class=\"alignnone size-full wp-image-311\" src=\"https:\/\/docs.sisus.co\/init-args\/wp-content\/uploads\/sites\/6\/2022\/09\/2022-09-17-17_04_21-Greenshot.png\" alt=\"\" width=\"325\" height=\"462\" srcset=\"https:\/\/docs.sisus.co\/init-args\/wp-content\/uploads\/sites\/6\/2022\/09\/2022-09-17-17_04_21-Greenshot.png 325w, https:\/\/docs.sisus.co\/init-args\/wp-content\/uploads\/sites\/6\/2022\/09\/2022-09-17-17_04_21-Greenshot-211x300.png 211w, https:\/\/docs.sisus.co\/init-args\/wp-content\/uploads\/sites\/6\/2022\/09\/2022-09-17-17_04_21-Greenshot-300x426.png 300w\" sizes=\"(max-width: 325px) 100vw, 325px\" \/><\/p>\n<p>After this you can get rid of the <code>[SerializeField]<\/code> attributes above our fields &#8211; the dependencies will now be getting provided through the <code>Init<\/code> method at runtime, not stored in these fields.<\/p>\n<pre>using Sisus.Init;\r\nusing UnityEngine;\r\n\r\npublic class Player : MonoBehaviour&lt;IInputManager, Camera&gt;\r\n{\r\n\u00a0 \u00a0 IInputManager inputManager;\r\n\u00a0 \u00a0 Camera camera;\r\n\r\n\u00a0 \u00a0 protected override void Init(IInputManager inputManager, Camera camera) \u00a0 \u00a0\r\n\u00a0 \u00a0 {\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.inputManager = inputManager;\r\n\u00a0 \u00a0 \u00a0 \u00a0 this.camera = camera;\r\n\u00a0 \u00a0 }\r\n\r\n\u00a0 \u00a0 void Update()\r\n\u00a0 \u00a0 {\r\n\u00a0 \u00a0 \u00a0 \u00a0 Vector2 moveInput = inputManager.MoveInput;\r\n\u00a0 \u00a0 \u00a0 \u00a0 if(moveInput != Vector2.zero)\r\n\u00a0 \u00a0 \u00a0 \u00a0 {\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const float speed = 0.2f;\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 float time = Time.deltaTime;\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 float distance = time * speed;\r\n  \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Vector3 moveDirection = camera.transform.rotation * moveInput;\r\n  \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 transform.Translate(moveDirection * distance);\r\n\u00a0 \u00a0 \u00a0 \u00a0 }\r\n\u00a0 \u00a0 }\r\n}<\/pre>\n<p>And that&#8217;s it, we are now all done creating our extra flexible Player component that receives all its dependencies via dependency injection.<\/p>\n<p>If both IInputManager and Camera are turned into <a href=\"https:\/\/docs.sisus.co\/init-args\/reference\/global-services\/\">services<\/a>, then the component will receive them automatically.<\/p>\n<p>If you want to configure them using the Inspector with <a href=\"https:\/\/docs.sisus.co\/init-args\/initializers\/cross-scene-references\/\">cross-scene reference<\/a> support, that&#8217;s also possible using an <a href=\"https:\/\/docs.sisus.co\/init-args\/initializers\/initializer\/\">Initializer<\/a>.<\/p>\n<p>And if you want to <a href=\"https:\/\/docs.sisus.co\/init-args\/getting-started\/initializing-components-in-code\/\">pass the arguments in code<\/a>, e.g. during a unit test, that can be done using GameObject.AddComponent&lt;TComponent, T&#8230;&gt; and prefab.Instantiate&lt;T&#8230;&gt; as well.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>What Is Dependency Injection Creating new components using the base classes in Init(args) is very similar to how it would work normally in Unity. The key difference is how the component obtains references to other objects that it depends on (its dependencies). Instead of components manually retrieving their dependencies using various methods like GameObject.Find, FindObjectOfType, ..<\/p>\n<div class=\"clear-fix\"><\/div>\n<p><a href=\"https:\/\/docs.sisus.co\/init-args\/getting-started\/creating-a-component\/\" title=\"read more\">Read more<\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[8],"tags":[],"_links":{"self":[{"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/posts\/304"}],"collection":[{"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/comments?post=304"}],"version-history":[{"count":36,"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/posts\/304\/revisions"}],"predecessor-version":[{"id":1153,"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/posts\/304\/revisions\/1153"}],"wp:attachment":[{"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/media?parent=304"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/categories?post=304"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/docs.sisus.co\/init-args\/wp-json\/wp\/v2\/tags?post=304"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}