Evan's Dev Blog 1/18 - Extending Unity's UI System
This week I started to expand on the UI systems in "Random Encounter" when I ran into a number of limitations regarding Unity's default UI. Though the Unity UI is great to quickly get something up and running, there are a number of situations where it is simply inadequate, and a more robust solution is desired instead. Today, I will detail some of the issues I have encountered with UI and how I have solved them.
Unity's Standalone Input Module is designed to handle touch input right out of the box. However, it does not apply limitations to the touch by default. For example, every finger tap will be processed, even if that behavior is illogical. If a finger touches and holds a button, there is nothing stopping the user from clicking a different button with their other finger.
Though this is a problem, it is fairly trivial to solve. My preferred solution is to create a new Button script derived from Unity's button. This Button uses Scriptable Object events to disable inputs to all buttons except the button that is clicked, and then re-enabled input when the button is released. If the events are assigned through code, it allows for the convenience of Unity's Button component but with this annoying quirk patched out.
Press and Hold Buttons
Unity's Button Component has one fatal flaw: it can only process a single type of input; clicking. This is sufficient for most solutions, but in "Random Encounter," this became a huge issue. As the player's spell list is randomized each turn, there must be a way to see what a spell does without selecting it. On PC, this could easily be handled through a mouseover system, but this is impossible for mobile. Instead, a spell's info will be displayed when the spell's icon is pressed and held, disappearing when the player's finger moves off of or releases the button.
Thankfully, Unity's Event Trigger component uses implements listeners for the Pointer Down and Pointer Up events. With these listeners, we can simulate press and hold behavior. However, this allows a button to be clicked when the player clicks the button and drags their finger onto another part of the screen. To solve this, we can use the Pointer Exit event. My solution calls a function when a button press is released or if the player drags off the button's hitbox to say that the button is no longer selected. All gameplay altering behaviors will check if a button is selected before executing.
By far the biggest weakness of Unity's built in UI is its lack of support for multiplayer solutions. By default, multiple event systems are unsupported, meaning it is only possible to have one highlighted object at a time. My first encounter with this problem came when I was developing Smush. While I was able to solve it, my solution was far from ideal with many inelegant solutions. When it came time to develop menus for Stabby Cats, I knew I wanted to develop a cleaner solution that could be reused for future projects if need be. Thankfully, a portable solution turned out to be quite simple to develop.
Though duplicate event systems are unsupported, multiple event systems can be placed in the scene. All that is needed to make an event system multiplayer compliant is to create a derived class of the event system and overload its update to set EventSystem.current to the calling event system, process the base update function, then set current to null. Next, I created a Multiplayer Button class derived from Button. This button contains an event system as a member variable. The button's select class is overloaded to use the event system member variable as opposed to EventSystem.current. While this solution does disallow the usage of EventSystem.current, this is okay, as all components will have a reference to the event system that processes their events.
I have created a development repository for "Random Encounter!" This repo is significantly messier than the one linked in an older post, but it will contain more up to date examples, such as the UI examples from today's post. Check it out here. The multiplayer UI components can be found here.
See you all next week!