InGame Tilemap Editing - PART 4: Automating the UI - 2D Level Builder - Unity Tutorial

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
In addition to the automation of the tilemaps we've done last episode, let's now automate the UI panels. Currently they are manually created but whenever we would add new buildables we also need to update the UI, which is quite annoying. But good thing is, it's not that hard to code and UI coding stuff is always good to know. So let's start. According to our current UI scheme, we want to have UI Categories and they contain the button tiles to draw. Theoretically we could reuse the category scriptable object from the previous episode, but UI handling for the user and tilemap code handling can be completely different. So it's more practical to separate this and create new "UI Categories" in form of a scriptable object. Change MonoBehaviour to ScriptableObject and also add the line to add this item to our context menu. Now I'm going to add two variables with their getters. The first one is the siblingIndex and is just an integer. This number represents the order of our categories from top to bottom. The second is of type Color and will change the background color of the category labels. Currently they are all white and this feature is basically just for show and acts as an example how you can change various things. We now have two options. Every UI Category could have a list of "Buildables" which then will be shown. Or we reverse this by assigning the UI Category to the object itself, like we've done it with the other category. I'll use the second approach because I think it's better to store information that belongs to an object there. It also makes sure that an object is only shown once and can't be assigned to several categories. So let's add the according field and getter to the BuildingObjectBase. If you named your new scriptable object differently just make sure to also change the Type. Now let's create some UI categories and then assign our buildables to them. The Sibling Index starts by 0 and represents the entry on top of an hierarchy and therefore at the top of our list. Then just count upwards. When choosing a color make sure to increase the alpha. It always starts with a default of 0 and that makes It invisible. Then just fill in the new field we created for all the buildables. I decided to not create an "Item" UI Category, so that we can see some differences. Like we initialize the tilemaps on game start via a script we now need to do this for our UI. I create a new script called BuildingHUD, because it only represents the UI elements that are responsible for building. Make it a Singleton and also import the UnityEnginge.UI package. Now taking a look at our current structure we have the following: The wrapper which contains the different UI Categories, here called "Categories". In there the category element which itself contains the category label, here badly named "Background" which represents the background and the title of the category and also the list of buildables which are the buttons we created in episode 1. To spawn objects with this structure we are going to work with prefabs. To create those I will change and rename one of the existing categories. This will act as an universal start point for all the elements we will spawn later. Make sure to remove the content of the "Items" because they will be spawn into this separately for every entry. The Text of the title will be changed as well, so there is just the placeholder "ABC" for now. When done create a new folder called "Prefabs" and drag and drop the object in there. Now this is our category prefab. To spawn the button we need another one as well. I'll adjust an example entry like earlier and remove the specific values like the image and the Building reference, so that it's just a "blank" building button. Now drag and drop it into your prefabs folder as well. I move both entries to an "UI" folder, so that it gets obvious where the prefabs belong to. Now that we have what we need, let's create the according serialized fields for this, so we can set up the UI creation. Of course we want a list of UICategory to select the categories we want to display. This is done manually but could also be done via code, so that you can show different field groups for different needs. Then we need the parent element where all our categories go into. If you want to set a parent for a game object always use type "Transform" for the parent. This will automatically get the "Transform" component of the game object you will drag into the slot. And of course our two prefabs. So the upcoming part might be a bit difficult, so let's do it step by step. I create a method which will build the UI and will be called on Start. I create a "foreach" loop to iterate through every category inside the categories list. So let's instantiate a new object based on the universal category prefab. We then set the wrapperElement as parent. So basically that spawned our category object. Let's change the hierarchy name to the current category name, so that we can check if it works correctly. Back in Unity add the script to your manager object. Add the wrapper element and the two prefabs. Now add all the UI Categories you want to show. I also hide the prefab and remove the manually created entries, so that they don't disturb the new creation. When starting play mode the three entries get created. Taking a look in the hierarchy, you can see they were named like the category and contain the structure like we want. So the basic setup works. Since we want to add the buttons to those instantiated elements here, it makes sense to save the instantiated objects referenced to the category they belong to. This can be done with a Dictionary. As key we use the UICategory and the value will be the game object we created. So after initialization you can add the key-value pair to the dictionary like this. In some use cases for changes during runtime there might already exist this element, so let's check if the current key - the category - exists in the dictionary. If it does not exist, we create the entry and add it. Else we assume it was created earlier, but based on how the code currently works, this will never be the case. Just be aware of this handy approach if you add live update later on. Now, whether the if-statement was executed or not, we have a value for the active category. We then can replace the call of the "inst" variable with the GameObject which is saved in the dictionary, because basically they are the same. Now we can change the other attributes, like the text which represents the name of the category. For this we will find the first and only Text component for the game object. Make sure to use "GetComponent" not "GetComponentS" "…InChildren". Changing the index is quite simple and will make sure that the one with an index of zero will be on top of the hierarchy. Changing the background color is similar to the text but we will get another component, of course. If you have several text components for example, you might need to get the correct ones based on their direct parent or their position. An example for the latter one can be found in my tutorial about the UI for the Highscore List. On testing all three elements have now a background color and the according title. But of course the items are still missing, so let's fix this. Since we reverted the reference between category and item, we don't have a simple list of objects we want to show now, unfortunately. One approach now could be to have a serialized field were we add all the scripted objects we created and then we can loop through tem. But who would want to do this? It would be much cooler to just use all the scripted objects that are located somewhere inside the according folder, right? Right! The good news: Unity can do this. The bad news: This only works in a folder called "Resources". Let's just take it as it is and create the folder. We then can move our complete "Scriptables" folder in there. I think all bad news should be so easy to fix. So back in the BuildingHUD script, let's create a method which will return all Buildables. The return type will be an array of the BuildingObjectBase or whatever type your buildables are. Then just return Resources.LoadAll and add your type as type reference. As parameter you then can specify the path where they are located. Be aware that the "Resources" folder is used by default, so this must not be added to the path. We can then call this method right after the loop where we created the categories. Then we can iterate through all buildables. When creating a button we need to assign its parent correctly, which is the "Items" object inside the category prefab, which is empty for now. Every parent might be used several times, so it's better to only search it once and then save it into a variable. I'll do this by saving it into a Dictionary with the according Game Object as key. The value is of type "Transform" because this is the type we need for setting a parent. Right after I instantiated an object and fill the first dictionary, I also set the key and value for the new one, the elementItemSlot. With the "Find" method I can find objects by name. So, we can now find the according value with the key, which is the game object. To get the game object, we need to look up in our first dictionary with the "UICategory" key. You can nest it like this. This will return the "Items" object for the current UICategory. But spawning an item which is not assigned to any category would be bad. So let's make sure an UI Category was selected. If this is not the case we will skip the rest of this code and continue with the next element in our loop. Now we can instantiate a new object like we did earlier with the categoryPrefab, but now we use the one for the item. Then we can set the parent to the parent element we retrieved two lines above. Then you can change titles, names and sprites. There is only one problem with the image. We want to get the sprites that are assigned to the Tiles we created in episode 1. But we don't have an object of type "Tile" but rather "TileBase" and the latter one does not expose a "Sprite" property. But a "Tile" inherits from "TileBase", so that's the reason why we can use the tiles here as tileBases. To get access to the sprite property from the "Tile", we just create a temporary variable of type Tile. For this import the UnityEnginge.Tilemaps package. With an explicit conversion we can convert the "TileBase" variable, that comes from the current buildable, to a "Tile". Now we can access the sprite property and assign it. And we also need to assign the buildable itself to the BuildingButtonHandler script. Make sure to add a setter for "item" in this script. Now you can assign the item via code. So now for every existing buildable inside the given path, we will check if it belongs to an UICategory. If it does, the object will be spawned and it gets added to the according category. That's it. When starting play mode everything should look like earlier, but with a little more color. You can see the items exist, they have the correct sprite and they also reference the correct BuildingObject. So currently the UI only gets created once during start and not updated. But we laid a good foundation for an updatable UI. If you need this I recommend to take a look into my Highscore List video, which contains some useful code parts. In the next episode we'll take a look into some improvements and useful features for the current code. Thank you for watching and also thank you to everyone supporting me and the channel. Special thanks to my supporters on Patreon: Pat Rick & nuxvomo. Thank you all. And as usual: If you enjoyed the content consider liking and subscribing and I'll see you next time.
Info
Channel: Velvary
Views: 364
Rating: undefined out of 5
Keywords:
Id: dCrkOIylNSw
Channel Id: undefined
Length: 14min 23sec (863 seconds)
Published: Sat Sep 04 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.