I'm currently working on a new little prototype game. Typical for any game, you start growing your UI prefabs library. Creating UI becomes somewhat tedious because every time you build something, you need to locate it via the Project tab. Wouldn't it be better to have it integrated into the Hierarchy right-click menu, the so-called GameObject menu? Show The picture above shows the menu for the little prototype game with our own UI library. Creating UIs this way feels more native and faster. Let's explore how to do that! The first thing we need to do is to integrate into the menu. For that, we need an editor script, let's call it
This
little template will create one menu entry. It's important that the menu entry name starts with If you now click it, you'll see Locate prefabsSo far, so good! The next step is to locate the prefabs that we want to instantiate. There are different ways, in the next paragraphs, I'll explain them and their pros and cons. AssetDatabase.LoadAssetAtPathWith AssetDatabase.LoadAssetAtPath we can load any asset to work with at editor time. We could use it to load any prefab and create an instance. However, since the API wants to have a path to load an asset it's absolutely not refactoring safe. If you move/reorganize your prefabs, you have to change all the paths as well. That's why I personally do not like this API. Resources folderThe Resources folder along with its API is a special folder in Unity. It allows to load any resource at
editor and run time and is not preloaded by Unity. However, it suffers from the same issue as Also, Unity recommends not to use it anymore: AddressablesA perfect replacement for the old Resources folder is Addressables. Ok, almost perfect, because Addressables do not work well in editor time, yet. It can be used with some hacks and if you're happy with it, go for it! For me, I'd like to wait a bit more until it's fully supported. Using a ScriptableObject to locate prefabsNow we've had three ways that won't work, are outdated, or are not really safe to use. What we actually can use is a ScriptableObject whose sole purpose is to gather all prefabs. Then, we only need to locate one ScriptableObject to have access to all the prefabs. The location of the ScriptableObjects can be done with It's important that you create the ScriptableObject outside of an editor folder. It must be a runtime script:
In this script, we use the The second class is a custom editor with a little help box to remember where we may need to change a path if we move the SO. Now, let's create an instance of Fill your instance with all the prefabs you need. In my case, it looks like this: Locate the PrefabManagerBack in your
First, we define the const Second, we define a method that uses
Instantiate a prefabFinally, we're now able to create an instance of a prefab!
First, we define the method Within the method, we use If the instance was loaded successfully, we call the Careful here: You could also use GameObject.Instantiate but then it won't be a linked prefab anymore! For a better editor integration, we then use Undo.RegisterCreatedObjectUndo tso we can easily use Edit -> Undo to undo the object creation. Lastly, we use Selection.activeObject to select the newly created instance. Additional validation functionSince we're instantiating UI prefabs, we want to make sure, that we only can instantiate them, when we have a canvas in any parent object. We can use a validation function to check that:
This is a very simple menu validator function. If it returns You could also go the other way round and create a canvas before if there's non. That's up to you. :) Cheers! |