We are a small team in Unity’s Copenhagen office that works with engineers and artists, both within the company and from the community, to create instructional e-books, articles, and demos to help you use Unity. Most of our stuff you can find on the Unity best practices hub.
We’re posting today to let you know about a new project we just launched, called QuizU. QuizU is a sample of an interactive quiz application that shows how UI Toolkit components can work together, leveraging various design patterns, in a small but functional game, complete with multiple screens and game flow management.
QuizU was created mainly with programmers in mind, explaining UI Toolkit concepts and tools from a developer perspective.
This post is the first in a series of articles that provide additional information on how we implemented the project using UI Toolkit. The sample is just a simple quiz game mechanic but the intent is to show and teach implementation techniques that you can use in your own projects.
Download QuizU from the Unity Asset Store, running on 2022 LTS to follow along.
The other articles in this series are:
- QuizU: State patterns for game flow
- QuizU: Managing menu screens in UI Toolkit
- QuizU: The Model View Presenter pattern
- QuizU: Event handling in UI Toolkit
- QuizU: UI Toolkit performance tips
QuizU complements two big pieces of content we released last year to help you get started with UI Toolkit:
- UI Toolkit sample – Dragon Crashers: This demo is a slice of a full-featured interface added to the 2D project Dragon Crashers, a mini RPG, using the Unity 2021 LTS UI Toolkit workflow at runtime.
- User interface design and implementation in Unity: This free e-book covers UI design and art creation fundamentals, and then moves on to instructional sections on UI development in Unity, mainly with UI Toolkit, but also with a chapter covering Unity UI.
But first a major shoutout to Wilmer Lin, the main creator of the demo and instructional content in this article series. Wilmer is the author of a number of our e-books. He’s a 3D and visual effects artist with over 15 years of industry experience in film and television, now working as an independent game developer and educator. Wilmer’s feature credits include X-Men: Days of Future Past, The Incredible Hulk, and The Chronicles of Narnia: The Lion, the Witch, and the Wardrobe. We also worked with our UI Toolkit R&D team and several internal experts in bringing all of this material together.
Ok! That was quite the preamble! Let’s dive into our first article explaining QuizU.
QuizU implements common design patterns and event-driven architecture. Think of it as a study tool or a starter project for a larger application. And don’t forget to play the game, too – it’s a fun way to test how well you know Unity or perhaps prepare for a Unity certification.
Test your knowledge in QuizU or use it as a starting point for creating your own quiz game.
UI Toolkit demos
QuizU is designed to help make it easier to get started using the UI Toolkit. The project provides 10 small, digestible samples that demonstrate different aspects of UI Toolkit.
A mini quiz game with UI management
The sample project showcases a UI-centric quiz game that implements various patterns for managing UI and game flow. It offers practical insights into handling multiple UI screens or breaking a large UI into smaller displays.
The QuizU project is a UI Toolkit-based game sample.
QuizU also showcases several core design patterns, including the usage of the state and model-view-controller (MVC) design patterns. These can help anchor your game architecture, so new features don’t break your existing application.
Here, the game components communicate with each other through events, promoting loose coupling for scalability and testability.
The QuizU project in Unity UI Toolkit offers a variety of standalone demo scenes, each serving as a bite-sized showcase of a specific UI Toolkit topic.
Think of these scenes as a set of recipes while exploring the UI Toolkit. Here’s a brief sampling of what’s inside:
UXML and Visual Trees: UXML files form a hierarchical structure of UI elements. These visual trees serve as a blueprint for your user interface.
Flexbox: The Flexible Box Layout Model (flexbox) provides an efficient layout model for arranging UI elements dynamically within a container.
Unity Style Sheets (USS): USS allows developers to customize UI elements with predefined styles. Reskinning your UI is just a matter of swapping style sheets.
UQuery: UQuery simplifies the process of searching through a complex hierarchy of UI elements, enabling seamless navigation to specific UI components within the visual tree.
Pseudo-classes: Pseudo-classes can be used to create interactive and animated UI elements with minimal extra code, adding extra ‘juice’ to your visual interface (e.g. enlarging a button when hovering over it or changing a text field color after selection).
UI Toolkit Event System: UI Toolkit has its own complementing event system, designed to handle your UI’s clicks, changes, and pointer input, even across complex hierarchies.
Manipulators: Encapsulating related event callbacks into a single class, a manipulator promotes reusability and makes it easier to define user interactions (e.g. a click-and-drag manipulator for an inventory system, a gesture manipulator for a pinch-to-zoom effect, etc.).
Custom Controls: The demo shows how to define and instantiate custom VisualElement through UxmlFactory and UxmlTraits classes. These custom controls can then be reused through scripts or the UI Builder.
As you dive deeper into the UI Toolkit, use these demo scenes as a source of inspiration or a reference guide. Then, you’ll be ready to create your own rich, interactive user interfaces.
While the sample demos can help you understand specific topics in UI Toolkit, we’ve also compiled many of these techniques into a mini-game so you see how UI Toolkit fits into a more complete project.
Select a Quiz topic and then test your own Unity knowledge.
Test your Unity knowledge in QuizU.
The visual style is minimalistic so you can focus on the mechanics of putting the UI together without getting lost in the design details. This way you can see clearly how the UI elements combine into a cohesive user interface. It also makes it easier for you to reskin and apply your own theme using the project as a boilerplate template.
To help you manage your UI Toolkit-based interfaces, the project also demonstrates a stack-based navigation system for handling multiple screens. An upcoming article in this series explains this navigation system in detail, but for now, here are its main components in brief:
Several Visual Tree Assets combine into a single UXML in UI Builder (UIScreens.uxml). Each visual tree corresponds to one UI in the application. A UI Document component reads this master UXML and then generates the relevant on-screen UI from that.
A stack-based state machine – or “screen stack” – manages the UIs. Each screen is a fullscreen UI under the control of a UIManager class and is treated as a layer of a stack. Think of it like working with a pile of plates: You can only interact with the top plate, and to get to a plate beneath the top one, you have to remove plates on top of it. The last plate you put on is always the first one you take off.
When a new screen opens, the UI Manager pushes onto the top of the stack and makes it the active state. When a screen is closed, it pops off the stack. This is a simple and effective way to navigate between modal screens.
More complex UI Screens can be broken into smaller visual parts. The main Game Screen is a composite of several smaller displays. Each smaller “sub-screen” is handled independently; it can interact with the other smaller sub-screens or with the main UI Screen. This keeps everything more modular and reusable.
Whether you are creating a menu system for a game jam or developing a more complex project, this stack-based navigation system can provide a flexible and scalable framework for managing multiple UI screens.
UI Toolkit offers a comprehensive suite of features and tools to support you in building runtime UIs for game applications and Editor extensions. UI Toolkit introduces a new workflow and architecture that offers several improvements and advantages over UI development with UGUI.
UI Toolkit comes with a learning curve but also a number of advantages:
Scalability and Performance: UI Toolkit is designed to be more efficient and performant, particularly for complex user interfaces.
Style Separation: UI Toolkit separates styling from the logic using USS (Unity Style Sheets), similar to CSS in web development. This can make your UI code cleaner and easier to maintain. Designers can iterate on aesthetics without touching any code.
UXML Templates: You can define reusable templates and instantiate them in your code. This can make it easier to design complex UI layouts.
Unified support for runtime and Editor: The UI Toolkit works in both the Unity Editor and at runtime, allowing you to use the same system for creating custom Editor windows and in-game UI.
The QuizU sample includes several standalone scenes that illustrate key concepts within the UI Toolkit. Each one represents a specific technique or feature. Consider these scenes as a set of recipes to inspire and guide you as you evaluate UI Toolkit for your next project.
Navigate to the Demo Selection Screen via the Main Menu screen, or if you prefer, disable the bootloader scene (Quiz > Don’t Load Bootstrap Scene on Play) and load each scene manually.
Let’s break down some concepts highlighted in these demo scenes.
Select a demo from the Demo Selection Screen.
UXML, or Unity XML, is the markup language used to structure and organize user interfaces in UI Toolkit. It provides a blueprint for constructing a visual tree, a hierarchy of UI elements. Every element declared in a UXML file corresponds to one node in the visual tree.
UXML files can also serve as reusable templates for UI elements, much like prefabs do for GameObjects. When a UXML file (or template) is loaded or instantiated, a corresponding visual tree is created in memory.
Consider UXML files as building blocks for UI structures and controls. UXML supports nesting, allowing your team members to work on individual UXML files and then combine them into a master hierarchy. This can prevent merge conflicts and promote modularity.
The demo introduces the visual tree hierarchy.
GroupBox versus VisualElement
The example features a GroupBox to group elements visually with a built-in border and label. Alternatively, you can customize a VisualElement with your own styling and add a Label to achieve a similar look.
These rules allow for responsive design, adapting designs to various screen sizes and resolutions. Both row and column direction, control of the wrapping of elements, and managing the growth and shrinkage of elements based on available space are all possible with flexbox rules.
Building on the concept of visual trees in UI Toolkit, visual elements can act as flex containers using the flexbox layout rules. When functioning as parents, these containers can help organize child elements in an efficient manner.
Our Flexbox demo scene walks you through the basic rules of working with a flex container and its children. For more information on element positioning, see the UI Toolkit Layout Engine documentation.
Adjusting the Flexbox properties.
Unity’s UI Toolkit provides a flexible system of styling using USS (Unity Style Sheets). Similar to their CSS equivalents, USS style sheets allow you to change the appearance of your elements by swapping predefined styles.
In the demo scene, compare the stylesheet code for a default button and several variants with different styles applied. Modifying font styles, colors, sizes, and positions is as easy as applying .uss files.
Change an element’s appearance through USS styles
UQuery is a feature that simplifies finding elements within a complex hierarchy in UI Toolkit.
This demo scene demonstrates its usage, by providing a query selector which highlights the selected UI elements, making it easier to interact with specific UI components in the visual tree.
UQuery can make it easy to search through a complex hierarchy.
Pseudo-classes are special selectors that target UI elements based on their state or certain characteristics, such as :hover, :active, and :focus, similar to their function in CSS.
This demo scene shows the basic usage of pseudo-classes for simple animations and interactivity. With a few extra styles and no extra code in most cases, we can make the UI elements respond to the user’s input.
Pseudo-classes target elements based on their state.
USS transitions allow you to modify UI properties over time, making your UI come alive with simple animations.
The demo provides some simple examples of how to add USS transitions for improving the visual feedback to the user.
USS transitions provide an easy way to animate your UI for improved visual feedback.
UI Toolkit comes with its own event system, designed to cater to user interface events (e.g. click events, change events, pointer/mouse events, etc.).
Note that this UI Toolkit event system can complement other events in your application, such as the Input System events or System delegates. While the UI Toolkit concentrates on UI-specific actions, the Input System can broadly handle raw device-level inputs. Standard .NET events provide a general way to interact with anything else. You can connect one type of event to another for the desired behavior.
The demo scene shows how separate elements – a Slider, Button, and TextField – can communicate using UI Toolkit events.
Create interactions with the UI Toolkit event system.
The UI Toolkit event system operates through a system of event propagation that allows events to traverse the visual tree hierarchy. The demo shows how an event trickles down, reaches its target, and then bubbles up. Use event dispatch to your advantage when setting up a container with several child elements.
Events can propagate through the visual tree.
A manipulator is a utility class that can help you handle specific types of user interaction with UI elements.
Imagine click-and-drag interaction or a pinch-to-zoom operation. These can involve several related event callbacks to work properly – the response to the mouse click, the dragging action, and then the mouse release. Manipulators allow you to bundle those event callbacks together for easier management.
Once the manipulator is created, it’s reusable and ready to add to your UI elements. Simply attach them to any elements that need the functionality.
In summary, a manipulator essentially streamlines setting up that user interaction, so you don’t have to handle each callback one by one.
This demo showcases a custom manipulator that makes an element draggable with the mouse pointer. Making game pieces or floating windows is then just a matter of adding the example manipulator to the parts of your UI that need that specific user interaction.
Manipulators can be used for creating interactive behavior for your UI, such as the draggable elements in this example.
UI Toolkit also allows you to create custom controls that extend the functionality of the base UI Toolkit classes, giving you additional features or behaviors specific to your application’s needs.
The UxmlFactory class functions as a link between UXML and your C# code. This factory class allows UI Toolkit to instantiate your custom component when it’s encountered in a UXML document. In UI Builder, this allows you to drop these custom controls into your Hierarchy.
The UxmlTraits class defines the properties and fields for your custom element. Custom UxmlTraits appear in the UI Builder’s Inspector.
The demo illustrates how UxmlFactory and UxmlTraits classes are used to define and instantiate a custom VisualElement in Unity’s UI Toolkit.
The example showcases a custom button that can toggle between two color states.
A custom Button can be reused within the UI Builder.
As you further your understanding of the UI Toolkit, we hope these demo scenes inspire you with new ideas, or serve as references for specific techniques and patterns.
We also suggest exploring the comprehensive examples in the documentation. These showcase how to assemble elements into functional UIs for both runtime and Editor scripting.
Game programming patterns are reusable solutions to common problems in software development. They can help streamline your code, making it more readable and maintainable.
The QuizU game implements several of these patterns, including:
The state pattern allows an object to alter its behavior when its internal state changes. This pattern can reduce a more complex object into a predetermined set of states. The QuizU project uses a SequenceManager and UIManager that show different types of state machines.
The model-view-presenter (MVP) pattern maintains a strict separation between the app’s data (Model), UI (View), and the controlling intermediary that binds the two (Presenter). This improves readability and maintainability.
The observer pattern can help decouple objects to reduce their interdependencies. This can improve testability and reduce class size. QuizU uses System.Action delegates as well as the UI Toolkit event system.
We’ll look in detail at each of these patterns in the posts to follow, so stay tuned.
Learn more in the guide Level up your code with game programming patterns. This e-book provides insights into the SOLID principles and various design patterns, introducing practical examples in Unity.
The observer pattern governs how objects in the sample project communicate. In QuizU, almost everything that “happens” in the application is the result of an event.
Using static events can let objects pass messages without directly referencing each other because they are globally accessible from anywhere in the application, provided they have the appropriate access level. This decoupling makes your components easier to maintain and debug – without affecting the rest of the game’s systems. Static events add a layer between the publishing objects that broadcast the signals and the objects which may be listening.
One benefit of event-driven development is that you can reduce reliance on the singleton pattern. Singletons can be convenient in smaller applications due to their global accessibility and persistent states; however, they can cause problems in larger, complex systems. Singletons often produce tightly-coupled code, making it difficult to debug or extend. Plus, the ease of access that singletons offer often leads to misuse or overuse.
Instead, event-driven development uses the publish-subscribe model for messaging. Events can allow for modular components that can be tested more easily.
Different parts of the application use events to communicate. You can find the events in the Scripts/Events folder.
Want to input your quiz answer, play a sound or queue up the next question? You can implement them as events. Invoke messages using the static event class and pass along any required data as a payload. Any object can listen for specific events and execute any handlers in response.
The events in QuizU fall into the following categories, with separate classes for each:
Game Events (\Quiz\Scripts\Events\GameEvents.cs): These events manage the core game flow. They update questions, handle user-selected answers, display feedback, and manage game states (start, pause, abort, win, lose).
Level Selection Events (\Quiz\Scripts\Events\LevelSelectionEvents.cs): These events allow the user to choose a quiz from the Level Selection Screen.
Scene Events (\Quiz\Scripts\Events\SceneEvents.cs): These events manage loading, unloading, and progress updates of different scenes in the game.
Settings Events (\Quiz\Scripts\Events\SettingsEvents.cs): These events handle changes to master, SFX, and music volume.
UIToolkit Events (Quiz\Scripts\Events\UIEvents.cs): UI Toolkit maintains a separate set of events in order to interact with UI elements, such as buttons, sliders, and input fields. They process everything from clicks and drags to value changes, and can be used to trigger updates or transitions in the game.
By dividing the game logic into these different event classes, QuizU can handle complex game state transitions and interactions in a clean and organized way. For example, when a user selects an answer, the AnswerSelected event is triggered in the GameEvents.cs. That, in turn, updates the game state and UI in UIEvents.cs.
This breaks the application into small “islands of code” that can function more independently from each other. UI, game logic, settings – they all just need to listen for events and react accordingly.
The demo project uses a couple of common techniques to help start the game application in a consistent and predictable state. One of these is a Scene Bootstrapper (or bootloader) which is an editor extension script responsible for setting up the game’s initial state. This initialization code is separate from the game logic and ensures that all dependencies are set up correctly for the objects in the scene.
The bootstrapper configures essential GameObjects, managers, or services when a scene is loaded to avoid dependency issues.
If your Unity application spans several scenes, the bootloader can force loading a specific bootstrap scene, which is the first scene from the Build Settings. When exiting Play mode, the Editor reloads the previous scene.
Another component in the bootstrap scene, the Sequence Manager (more information is provided on this component in an upcoming article), can then instantiate essential prefabs on scene load. In this specific demo project, everything needed to create the game is a prefab, including a camera, SplashScreen, UI menus, and a SceneLoader.
The SceneLoader then additively loads (and unloads) any gameplay scenes as needed. In most cases, these scenes are composed of prefabs.
The Bootloader initializes dependencies to control flow of project scenes.
Each mini-game level is a separate Unity scene and appears in the Build Settings. Disable the SceneBootstrapper in the GameSystems menu if you want to explore those individual scenes.
Many projects also include a staging area for the main menu after the bootstrap scene. This demo project omits a main menu scene.
The StyleExample.cs file in _StyleGuide folder is a project-specific style guide for C# naming conventions, formatting rules, and usage guidelines, most of which are applied in QuizU. This promotes readability and consistency in coding, especially when working in a team environment.
While there is no “right style” other than what works best for you and your team, the style we are following here is inspired by general industry standards for C#. In our demo we decided to make a few tweaks from the original guide as an example. You can learn more by checking out our e-book Create a C# code style guide for more information about style guides.
The project includes some helpful smaller scripts not specific to the quiz application which can be found in the \Quiz\Scripts\Utilities folder:
- EventRegistry: This utility class manages the registration and unregistration of UI Toolkit events. Because so much of the game flow hinges on setting up events, the EventRegistry makes that process easier. See Event handling in UI Toolkit for more information.
- Coroutines: This helper class provides static methods for managing coroutines. This can help a System.Object or ScriptableObject run a coroutine on a separate MonoBehaviour.
- DestroyOnLoad: Apply this to temporary objects to remove them during the scene load process.
- NullRefChecker: If you are using the Inspector to set required dependencies, use this to validate your fields. Bypass this behavior using the custom Optional attribute.
- Tooltip: This shows how to use a UI Toolkit Manipulator to make a simple tooltip that stays within the boundaries of the screen.
The ScriptTemplates folder includes two files to set up formatting, namespaces, and base classes for new MonoBehaviours and ScriptableObjects. Similar to the utilities, they are not specific to the demo and you can modify or create additional templates as needed.
Finally, we use ScriptableObjects as data containers to help us manage information such as questions, quizzes, and menu data. Using ScriptableObjects, we can easily separate data from logic which simplifies data management for more streamlined development.
For more about ScriptableObjects, see the e-book Create modular game architecture with ScriptableObjects from our best practices guides.
So, that’s our first post in our series that unpacks the new QuizU demo. Feel free to leave your comments and questions for each post in this series. We look forward to hearing from you. Thanks for reading!