Unity UI: Controllers or No Controllers
One of the cornerstones of the development world is the idea of “best practice”. Since coding is as much about style and flexibility as it is about solving concrete problems and modeling desired outcomes there’s really no one single way to approach a solution…nor should there be! What we have instead is a kind of trend towards certain efficiencies such as least amount of code to get the job done, making it reusable, making sure it doesn’t trip up or over other code, etc. Best practice can be abused when people insist that their way is the only way because anything less is just going to cause your app to sputter and die a wheezing death. But best practices are really the distillation of a whole lot of people’s trial and error, hopefully with a dash of advice from those who created the language.
Finding the “best practice” is often difficult for a few reasons, first and foremost being that as a rule, there is no best practice. Everyone swears by what works best for them. Some people like cars, some like motorcycles, but both will get you to where you need to be so who really cares? The second is that often times developers can be real cagey with their knowledge. There’s some undercurrent that believes divulging experience in development is like a magician telling people how the trick is done, not because it ruins the illusion, but because it suddenly makes the original magician a lot less valuable if everyone can do the same trick.
That’s why I’m throwing this out there in the hopes that someone can at least share some insight into their own experience since it seems like more of what we call a pattern than a practice. A pattern is more of a mindset than an actual flow. It’s how things are arranged so you can get yourself into a practice. In this case, I’m looking for advice on structuring and controlling a user interface in Unity.
And before I get to the question at hand, just a bit of a preamble. The way I’ve been working with Unity UI, I see two methods of wiring up the interaction. The first is to have the UI itself handle interaction with the code that puts and pulls data to and from the game’s data store. The second is to centralize the code that interfaces with the data store, and then have another script on the UI that deals with the UI itself. Then, these scripts communicate among themselves to pass data along.
Option 1: Direct Script Interface
The first option is probably the most direct and easiest to conceptualize. The Unity UI system allows us to draw a box, say, which contains fields for text input (in our example). In order to get this data into the game data store so we can apply it elsewhere, we need to recognize that the textboxes exist.
After we draw our UI, we attach a script to it. This script has properties that are intended to hold references to the UI elements like the textbox (and the button used to submit the data to the data store). When the script receives the command to read the data from the form, it refers to those properties so it can read the contents. It would then take the data from the textboxes and “do something” with it — send it to another part of the game, or put it into the database or something.
The benefit to this is that the UI is completely sorta self-contained. We could copy this and paste it elsewhere and it should work exactly the same, which is one of Unity’s greatest strengths. It’s also easier to manage because we just need to go to the source — the UI elements — and we have access to the visuals and the code.
The downside to this is that we end up with a whole lot of repeated code. Anytime we want similar but slightly different behavior we would need to modify the underlying code and then add a reference to other UI. It also means that we can’t easily take advantage of global patterns such as singletons which allow for persistence of data without having to go “back to the well” of a back-end system. Finally, if we had one script to handle several UI elements, we’d have a whole lot of properties tied to UI elements to deal with, which might make management a nightmare.
Option 2: MVC-esque Interface
This option is more complex, so please bear with me as I try and explain the diagram.
First, MVC is a pattern called “model-view-controller” which puts the display in a “view”, the logic in a “controller” and uses a “model” to represent the data passed between the two. Here, the UI has a controller. This is a game object which centralizes a whole lot of behavior for the express purpose of bundling it together for easy access. Here, a UI controller would be the base of either this or all scene UI elements. We’d have scripts for managing windows in the scene, but also for handling the UI elements (textboxes, buttons, etc).
The difference here is that this script would need to communicate with another script on a more global scene controller. The scene controller is like the MCP from the original TRON: it’s got access to everything you might need, just hanging out in space, easily accessed from whatever and where ever you need it.
The benefit of this method is that the scene controller is all seeing and all knowing. It works for the UI, but it’s also available for other elements of the game. In addition, it can implement the singleton pattern which when combined with telling Unity not to destroy the object on scene transition, offers us a persistent data conduit.
The downside? It’s messy. And complex. Technically, this diagram can be warped a bit. The UI doesn’t need its own controller, for example, and the interface script can live on the top-level element (“canvas”) of each UI we need to communicate with the scene controller. We could also eschew the scene controller itself and make the UI controller the top level way of data store interaction, although we’d lose our data persistence unless we did have some singleton somewhere that wasn’t destroyed when we move between scenes.
So there we have my conundrum. As a hobbyist developer in this realm, I’m not sure what the best option is. I had been using the more complex method previously, but now that I see things in writing I’m thinking of trying the less complex method, although I’m not sure what pitfalls are unaccounted for along that trail.
Are there other methods? This is where I’d love to hear from other developers who have worked with Unity UI and who are willing to offer advice!