Screenshot from Unity 4.6, new UI system reveal

UI Manager (A better one)

About eight years ago, we shipped our very first game: Fabric. Back then, we were young, naive, and didn’t know how to code. Well, at least I didn’t. So my solutions were… not the best. But the things I did with the UI system were ugly, even by my standards.

After the release, I decided to think about what I’d done. And potentially come up with a better system. And I did! It was great! Or so I thought at the time. Sure, it was a superior solution to what I did for Fabric, which is not a high bar to clear. It was also a simple one. It can be enough for a small game with a few screens. But after working at About Fun primarily as a UI developer, I know better!

Separation Issues

My primary objective was to separate visualization and functionality. One class would be responsible for processing and organizing the data, while another would be concerned with fancy animations and presentation. The visualization class would only be communicating with the data processing one. No one else has to know about its existence.

The next objective is to get the data processor class. Someone has to activate the relevant screen, after all. The system we were using at About Fun was similar to what I did in the end (at least I think it’s similar, It’s been a while…).

Visualization and functionality

Separating the visualization from the functionality is easy when you think about it. Just have two classes (DUH!). And that was what I did: I created a Base and a UIBase class. The Base would take care of the functionality, while the UIBase would do the visualization. Of course, no one outside the Base should know or care about the UIBase. So no public methods or members for the UIBase class!

Access

While easy on paper, getting access to a base is a bit more tricky. My first UI Manager was using enums associated with each window. While easy to implement, this approach has lots of downsides. Like keeping track of all enums in a few different places. And why introduce another identifier when we already have one: the type?

Assuming each screen would have its unique type and would inherit from the base class, we can have a Dictionary<Type, Base>. So, the very first version of our UI Manager would look like this:

private Dictionary<Type, Base> _screens;

public T Get<T>() where T : Base
{
	if (!_isInitialized)
	{
		Initialize();
	}

	_screens.TryGetValue(typeof(T), out Base val);

	if (!val)
	{
		return null;
	}

	return val.GetComponent<T>();
}

We can fill up the dictionary in the Awake() method. At runtime, the application would ask the UI Manager for a screen, and initialize it whenever required.

Activating screens

The next step is to show and hide screens. Of course, the UI manager should keep track of active screens. So, the obvious solution is to pass the required screen to the UI manager and let it take care of the rest. And it is what I ultimately did. But instead of the application calling _uiManager.Show(myScreen), I decided to delegate the responsibility to the screen itself. The application would only call myScreen.Show(). Adding a _activeSceen field to the UI manager, a _uiManager field, and a Show()method to the base class worked out pretty well.

Fine details

Thus far, I described the general logic of the package and my thought process. The final version contains a few more classes for better control over the UI. I’ll skip the fine details to keep this blog short. If you are interested, you can check out the GitHub repository. For an example, check out this one. Let me know if you have any suggestions or general thoughts about this package.

Leave a Reply

Your email address will not be published. Required fields are marked *