Of GUI and Tooltips
I’m starting a series of articles on the technical side of things, to show what’s the solution taken for common problems in game development, trying to improve them and share it with fellow developers.
Nantucket is made with Unity, it has been awesome so far, after more than a year in development we feel quite comfortable using both the engine and the editor. But there are situations where we preferred to implement the solution ourselves instead of using built-in libraries or getting asset store packages. The whole UI library is an example of this.
Possible UI Solutions
At time of starting the development of it (mid 2014) there was no
uGUI, so the only feasible built-in solution was the legacy
OnGUI. We scrapped it right away because was not flexible enough to handle overlapping interfaces and different resolutions.
We evaluated the idea to purchase
nGUI, but at that time was too expensive for us for what we needed.
We haven’t tested the new
uGUI yet, but at this point of development is too much work of refactoring to switch.
So we went for building our solution from the ground up, so we could implement a library that contains only what we needed and is easily extendable.
Each in-game component that interacts with the player has a
Collider2D, in order to be detected by mouse movements.
Collider Manager provides a series of functions which give information about colliders, their position, and their Z order. It’s used mainly to understand which objects are pointed by the mouse pointer, both GUI components and game objects.
To handle Z order, the
Collider Manager has a list of
Layers ordered by priority. That’s all we need to handle overlapping user interfaces and detect whether the player is interacting with the map or with the interface.
In this picture, there are three
Layers ordered from high to low priority:
UIClickable, UIBackground, MapCity. Using the
Collider Manager, is possible to detect whether the mouse is pointing to the ship slot and show the tooltip, or decide to accept the click on a city and handle cases like: the city is covered by the interface background, if the user clicks where the city is, the
Collider Manager understands that the user is clicking on the interface and not on the city.
The first big choice we had is to implement the whole interface in world space coordinates. This let us design the UIs in the Unity scene together with the other scene objects, and it was great for us, because we had the possibility to see how the UI fit in the screen, and how it’s placed relative to the other objects, even in edit mode, reducing a lot the turnaround times.
But using world space coordinates has its drawbacks:
- Aspect ratio is fixed. In case the player uses one different from 16:9, there are black bars on the sides
- The interface is designed for FullHD resolutions. For different resolutions there could be a lot of aliasing in text and sprites due to texture filtering
Everything in the GUI is a
GUI Component, a simple script that provide functions to change the state (i.e. edit text, change color, change sprite) and it handles mouse events that happen on the component itself.
All the GUI state and behaviours are handled by the
GUI Manager, which has 2 main tasks:
- Dispatches mouse events like Mouse Over, Click, Drag & Drop to the GUI component
- Updates the info to show in each component, but only when needed to avoid performance issues
We use built-in
TextMesh components for UI texts, they are good enough for our purposes, but we didn’t find a good solution to avoid aliasing. We might consider using another solution for text in the future.
As you may have seen in some gameplay footage, we use tooltips a lot in Nantucket. We think is the best way to provide the player all the information he needs at the moment, without letting him confused and doing the best to help him to take the right decision.
Every object with a
Collider2D component in the scene can be a target for tooltips, all it needs is to have a
TooltipComponent attached. The
TooltipComponent provides a text to the
Tooltip Manager, which in order shows a tooltip with that text when the player moves the mouse over the object.
The text content in the tooltip varies a lot in terms of size, and the target object can be in any position in the screen. So we added a database of different versions of
Tooltip Objects, which varies in: text lines number, arrow direction, arrow position.
There is a central
Tooltip Manager which handles all the tooltip functionality, its main loop is:
- Pick an object pointed by the mouse with a Tooltip Component, using the
- Wait a delay while the mouse always points to that object
- Select a
Tooltip Objectfrom the database depending on: Text lines, Component position, Tooltip preferred direction. The tooltip object will be placed just outside of the collider of the target object, so the object won’t be obscured by the tooltip
- Show the tooltip
- Hide the tooltip when the mouse doesn’t point to that object anymore
Tooltip Manager makes sure that the tooltip object is always on screen so, for example, if the object is on the far right, the tooltip will go on the left even if the preferred direction is on the other side.
The tooltip object database handles until 6 lines of text for now, but we already have tooltip texts longer than that, so we added a special tooltip objects which is a big flat rectangle that encloses all the text. Before the game ships we may implement a solution to have modular tooltips, in order to handle all the text sizes.
That’s all, I’d like to hear voice in the comments, any feedback or question is welcome.