New Design Pattern: UI Pattern to help disable/control UI in Unity
When working on games, there’s a ton of things that need to be managed by an underlying system, to allow for certain things to happen, following major events. Things like, a player dying, and ultimately a new menu popping up, showing the player’s progress/information/respawn ability. If you’re a game developer, you know that there’s a lot of work that goes into UI design, and a ton of things that need to happen, to ensure it responds well, menus are called when they need to, and ultimately, things are easy to get to.
A pattern that is common use in Unity game development, is a Singleton pattern. A Singleton is an instantiated single instance of a class, that is easily accessible by other code within a game. This pattern is incredibly useful for keeping track of Gameobject’s, performing higher level tasks, and handling individual event related items throughout a game’s lifecycle. I typically use a couple different Singleton’s in my games, to reference different things. Controllers usually setup in my games include: Game, Scene, and sound controllers, that can be called to perform different actions throughout the game. Some of these, even survive between scene loads, to ensure that certain data is kept through scene load.
Previously when setting up menu systems, I would create a reference search for that said menu within the start method of a controller class and fill that attribute with the appropriate reference type. While this is effective, and nothing too wrong with it, I’ve come up with a little bit better of an approach, to resolve some code and dependency issues that come with the former implementation process.
The new pattern:
I’ll nickname this the ICPU – standing for the Independent Control Pattern for UI. This pattern takes a couple things into mind:
- You need a centralized location for activating UI elements
- Many of the UI elements you want to work with, need to hide on startup
- You want to reduce the size of your Controllers, and leverage the individual UI scripts for more heavy lifting and reference purposes
In this pattern approach, I take away the need of the Scene controller to search for items in the UI and disabling them itself. Instead, the task of registering and disabling the object is performed by a secondary object, that all UI objects inherit. The great thing about this format, you can build out methods the UI elements can share, other than registration, to allow for better sharing between the same elements. Example: Want all these UI elements to have a glow on hover? Want these items to shake when being clicked? There’s a lot of things you can use this for, but for now, we’ll just use it to initialize some UI elements, register them to our scene controller, and disable them until they are needed.
First, I start with a method on a Singleton controller that can be called from anywhere in the scene.
Next, I add references to two classes I’ve created, that will handle specific logic for individual menus:
There is one method within the Scene controller, that will need to be updated, as we add UI elements, to provide the initialization routine. This does the local mapping to the Scene controller.
Final Scene controller:
Now we create a class that perform the initialization routine on Start(), and disable the Gameobject. This allows a UI menu to be created, be able to be referenced, and then hide on game start, so the user does not see the menu when starting. This class can be extended to add additional features shared between these UI menu’s.
The UI menu’s that we want to use this base class, will inherit from this class created above. These classes don’t need to have any implementation at the moment, but additional code can be added for localized functionality of the UI menu in question. We don’t need anything for this, but we want to reference the UIStartup class, so that the start method will be called on these.
That’s it! Any additional UI classes/objects, can be added to the InitializeUI method, and a local reference in the Scene controller. Later, when these menu’s are needed, they can be called with .SetActive(true), to enable their views! Although it doesn’t seem like much, once you have a bunch of UI menu’s in your scene, this can do great things to keep your SceneController clean, and an be used to add functionality across a lot of your UI!
~ Sean Haddy Founder, Haddicus Games