This past three weeks has been for the most part a complete mess. I've been in the process of moving house, but it's not just any move, it's unpacking a whole lot of stuff we had in storage for the past two years. It's moving from a smaller unit into a bigger one, working on getting setup more permanently. In other words, its been a hectic time for me personally.
In whatever time I've had in between I've managed to squeeze in some work on the UI some more. Not quite enough for a release but... its something. My main focus has been working on getting the core UI ready for controller input, and hoo boy has that been a tricky beast to figure out.
In Interloper I did things the dumb way. I manually assigned all the controller layouts wherever possible, and wherever not possible I automated them, but did so badly. This worked, but anytime I wanted to change something it ended up in a bit of a mess. To this day, most menus in Interloper suck to navigate from a controller perspective. So my plan for Exoloper was to rethink this a little. I went through a couple iterations, and I'm pretty happy with the place I ended up.
First off, I use a model somewhat similar to the standard iOS layout of Windows, ViewControllers and Views, where an app lives within a window (in this case, core UI is in one window, bug reporter and tutorial ui's have their own windows), each "page" of the game's UI has its own ViewController and a series of sub Views. These views can be arranged one at a time (for mobile) or multiple at once (for desktop). This is all important because when navigating UI with a controller you need something called "focus" which is the current active item on screen, what happens when you take a UI Screen from a single View, to multiple Views? What happens when you have popups? Etc, etc. The answer is to dictate this via the View Controller, and that in my case is built in a generic hierarchy.
Sometimes that's just a single button, which means whenever this page opens, that button will always be the button that's selected.
Other times, its done in order. If "btn-toGame" isn't active, then, "btn-tutorial" will be selected, and so on. This way handles multiple states for a given page relatively easily.
So that's focus. After initial focus the player should be able to navigate around the main focusable interactive elements on a page using a thumbstick. Fortunately, Unity's pretty good at this by default, though what I quickly found is that I actually needed to disable navigation for most elements by default.
See, Unity's UI navigation tools are smart enough to find elements to jump to, including errant things like scrollbars in scrollviews, which.. don't get me started. Anyway with everything mostly off the system works well enough for my purposes, however, some views then have buttons that shouldn't be navigated to, but should be interactable somehow, which comes to my second implementation: the catchily named UI Event Button Bridge!
This lovely component has a set of common controller buttons laid out as an enum (drop down list) that listen to an event in my global event manager (aka, input fired via REWIRED) that cause the button to be pressed when the event is fired. It also takes that layout enum choice and converts it into information for the indicator to pick the relevant icon for the interaction (via the package REICONED). In interloper, menu navigation beyond focus was purely achieved by directly writing this code in each view's control script, here, a simple generic component makes it much easier to maintain.
One last issue I came up against was modular cells in lists. Most of the lists in Exoloper contain a single button, so the solution there was to focus the first cell in a list, and listen for submit on each button to select the item, pretty easy. But! There's some more complicated cells. In particular, the Loadout list cell has multiple interactions.
Count the amount of buttons in the various states.. i dare ye
This jam packed button works well for touch, but immediately fell apart for controllers. The default navigation had the player foccusing on the delete button of the first cell in the list, then scrolling down to "select" losing focus when delete was pressed and more. I sat on this one for a long time, trying to figure out an ideal solution, should I redesign the cell for controllers? should I have distinct states the cell could be in for each interaction. In the end I slightly modified the cell so that each cell-button was linked to a controller interaction, and by default none of those interactions are valid. They become valid when the cell is active, maintaining focus, and delivering cell-complexity in one fell swoop.
This stuff isn't rocket science, but it's only possible because of making a better underlying architecture to the game. Most seasoned UI devs would probably look at this and go "duh" or even probably "why aren't you using this easier approach" but for me, this is now both elegant and maintainable.