Are you having problems organizing UI? Great news, the struggle is over! I will tell you all about the pattern I’m using in most of my projects.
In the majority of cases, we need to see a single UI window at a time, like the main menu, pause menu, or in-game window. We might want to bring up a window from many different places in our code. And we want to disable other windows. So we need a method which would disable all windows and enable the one we want and we want to be able to access it from anywhere in the code. Let’s create a new class, call it UIManager, and make it a Singleton, using this base class (use Singletons with caution though!).
To switch between different windows more easily, I will make use of enums. Let’s assume we will have three windows: the main menu, in-game, and pause. Also, we might want to have none. So here is how the UIManager looks:
public enum Window { None, MainMenu, InGame, Pause } public class UIManager : Singleton<UIManager> { public void SetWindow(Window window) { //switch windows here } }
Now, let’s think about the windows. Each window will have different buttons and will behave slightly differently than others. So it is a good idea to make a script for each of them.
using UnityEngine; public class MainMenu : MonoBehaviour { }
using UnityEngine; public class InGame : MonoBehaviour { }
using UnityEngine; public class Pause : MonoBehaviour { }
Now let’s declare them in the UIManager like so:
[SerializeField] private MainMenu mainMenu; [SerializeField] private InGame inGame; [SerializeField] private Pause pause;
We don’t want other scripts to know about these windows so I made them private. But we still want to assign them through the inspector and that is what the [SerializeField] attribute does: it exposes the field in the inspector.
Activate/deactivate them in the SetWindow(Window window) method and we are done with scripting!
using UnityEngine; public enum Window { None, MainMenu, InGame, Pause } public class UIManager : Singleton<UIManager> { [SerializeField] private MainMenu mainMenu; [SerializeField] private InGame inGame; [SerializeField] private Pause pause; public void SetWindow(Window window) { mainMenu.gameObject.SetActive(window == Window.MainMenu); inGame.gameObject.SetActive(window == Window.InGame); pause.gameObject.SetActive(window == Window.Pause); } }
In the Unity editor, create the UI elements, add the scripts, assign the variables and you are good to go!
Now anytime you need a specific window, you can open it up by simply writing:
UIManager.Instance.SetWindow(Window.MainMenu);
And that’s pretty much it. Know a different pattern or a better way? Anything to improve or fix? Any other suggestions? Perhaps a tip or a request for the next blog post? Let me know in the comments and I will make that happen! You can download the code from GitHub and check out the rest of the Extra Tools project!
Nice!
How does the code ensure that the UIManager can be accessed from anywhere in the code? thnka