Overview Of UI Builder
Unity has recently added the new UI builder for designing and creating better user interfaces of interactive apps, games, and experiences. There are necessary components of UI Like Button, text field, scroll, etc. are already given. So, we can Drag and drop those components to design our UI documents (.uxml files) and for color and styling, a stylesheet (.uss file) is created. If you are familiar with XML, CSS, and C#, you can also design through code.
UXML: UXML is a markup language for the layout and positioning of components on a screen just like HTML is, for a webpage. It resembles other markup languages like HTML, XML & XAML, etc. If you are familiar with anyone then you can notice the similarities in UXML.If you are not familiar with any markup language, you can have a look at these documents of UXML. UXML defines the structure of UI.
All Visuals Elements have a common set of attributes like class, name, text, etc. The “name” is an important attribute because it is used to find that elements in C# and also in the stylesheet, USS. You can modify the value of the attribute manually or via UI builder.
USS: USS resembles the CSS of a webpage. Many properties of USS are similar to CSS Variables and it can use the Yoga Layout Engine. This is used for designing the layout.
UXML and USS are work parallelly because Without layout you can’t place element & without element, you can’t design UI.
The UI Builder is developed to provide more control and flexibility to the creator while building the UI. The UXML helps one in developing complex layouts as if one is developing an HTML webpage whereas the USS helps is reusing the styles and designing a consistent user interface across the project.
Here is the Roadmap of the blog where we will design and integrate a UI designed using UI builder :
Prerequisites checklist
- Unity 2019.x version or above.
- The basic workflow of the Unity engine.
- Familiar with the fundamentals of C# and Unity UI elements.
Setting up the project
- Create a New Project
- Install UI Builder Package from Package Manager.
- Open Package manager and enable Preview packages.
- Find UI Builder (com.unity.ui.builder) in Package manager and install it.
- Download and Import UI Element Runtime package for UXML & USS rendering from Github Link For Unity UI.
Open UI Builder Window from Window > UI Toolkit > UI Builder.
Introduction to the UI Builder Editor
- Explorer: Access the components of the open documents.
The Explorer is Divided into two portions: StyleSheet and Hierarchy.- StyleSheet: The StyleSheet portion lists all of the USS those used in the main USS document.you can also modify and create it.
- Hierarchy: The Hierarchy portion displays a live tree view of a UXML or displays your used component like text field, button, etc.. in the tree view document’s hierarchy.
- Library: Find available elements.
The Unity section lists the standard elements that Unity provides. Like Button, Text Field, Scroller, Slider, etc. These elements are work for all supported Unity Editor and run time themes. - Viewport: Show the Preview of our design UI and edit it.
You can edit the Canvas UI provided by UI Builder also save that runtime. Use the Preview button on the upright corner in the Viewport toolbar to preview your UI as though it were running on a device. - Code Previews: See the Preview of USS and UXML code that UI Builder generated or you can write on your own.
- Inspector: Edit properties like color, position, size, etc. of the selected elements (Button, text field, label, etc.) in Hierarchy.
The Inspector has three sections: Component, StyleSheet, and Inlined Styles.- Component: It shows the component properties of the selected component.
For Example, If in Hierarchy button is selected then in inspector show the Name, the text of the button, tooltips, etc. - StyleSheet: using this property you can Reuse the StyleSheet & also you can Create the New StyleSheet.
- Inlined Styles: These properties can help you to change the Size, Position, Margin & Padding, Color,etc.. of the selected component.
- Component: It shows the component properties of the selected component.
Designing the Main Menu Screen In UI Builder
First, we will set the UI Of the Main menu screen. Here are the steps for designing the main menu screen in the UI Builder :
- Select VisualElement in the Library section and Drag it into the Hierarchy section of Explorer Or Drag it onto the Canvas in the Viewport.
- Select VisualElement in the Hierarchy & change the name on Inspector to Screen.
- Select the parent of Screen to make Canvas & Set the canvas size 1080 X 1920 in the inspector.
- Now change the size of the screen to 1080 X 1920 in the inspector.
- Select screen Inspector -> Inlined Styles -> size set Width as 1080 px and the Height 1920 px.
- Drag one more visual element to the child of the screen & rename to Icon.
- Resize the Icon to the upper half of the screen.
- Select Icon Inspector -> Inlined Styles -> Background set sprite in Image.
- Change the Border and other properties according to your requirements in all elements.
- Drag one more visual element to the child of the screen & rename to Buttons.
- Resize the Buttons to the lower half of the screen.
- Drag the button from the library to Hierarchy & set in the child of Buttons(VisualElement).
- Rename the button to Play
- Now we change the text of Play Button Inspector ->Button(Component ) set the text property ” Tap To Play”.
- For the change of the font style, size, and alignment of “Tap To Play” Inspector -> Inlined Styles -> Text Change the size font size & alignment.
- A similar way to create an exit Button.
- Now we will create UXML of this Main Menu Screen.
- In Viewport Section click on File & save to your location the Main Menu Screen.
- And then, we will create USS of this Main Menu Screen.
Note: It’s not necessary. It’s for reusing the style.- Select Screen, Inspector -> StyleSheet -> Style Class List there is an empty text field write “.NameOfStylesheet” and click on Extract Inlined Style to New Class and save your USS location.
- Close the UI Builder window.
- Create a Gameplay Screen in a similar way.
Rendering This Designed UI On The Game View
- Right-click on the Hierarchy of Unity UIElements -> Panel to create a panel.
- In the Inspector, Panel Gameobject with three scripts attached. this is Panel Scaler, Panel Renderer and Event system all works like the old UI system of Unity accordingly canvas scaler, Canvas, and Event System.
- Now, Set our created Main menuScreen.uxml in UXML property of Panel Renderer type of this UXML is Visual Tree Asset.
- Let’s Play it in the game view.
Set the Button event on Designed UI Button
- Create a new C# script, the name of the script is “GeneralScreens”.
- Attach that script with the Gameobject in which the panel was created.
- Now, open the script GeneralScreens.cs and import UnityEngine.UIElements & Unity.UIElements.Runtime namespaces.
- Now we will need the reference of Button for adding button click event and this button is on the visual tree of Main Menu Screen.XML.
- So first of all, get the Reference of PanelRenderer because the panel render has the reference of UXML of our main menu screen. we will get the PanelRendere reference in the
panelRenderer in
Start() method because it is called at the start of the game.panelRenderer = this.GetComponent<PanelRenderer>();
- Now we will create two methods for the Play button & the Exit button.
- For the Play button OnPlay & for the Exit button OnExit.
private void OnPlay() { Debug.Log("Clicked on Tap to Start"); } private void OnExit() { Debug.Log("Clicked on Exit"); }
Here is a reference image for setting up properties like Type of Element, Name of Element & class list for C# script.
- Create the IEnumerable object because it can be subscribed to the UXML Load event of panel renderer.
- We get the visualTree On root variable. In this image root is Main Menu Screen.uxml.
- This root is the head of this Main Menu Screen tree. Then for Button, we need to find them by the name of the button.
- Take one variable for the Play button(Tap to Start), say “tapToStart”.
- Find the Play button in visualTree using root.Q<Button>(“Play”).
- Now, we will check if it exists or not. If it exists, then we subscribe to its click event.
- In a similar way, we will find for “Exit“ and subscribe to its respective events accordingly.
IEnumerable<Object> OnloadUXML() { var root = panelRenderer.visualTree; var tapToStart = root.Q<Button>("Play"); if (tapToStart != null) { //subscribe Play button event tapToStart.clicked += OnGameStart; } var exit = root.Q<Button>("Exit"); if (exit != null) { //subscribe Exit button event exit.clicked += OnExit; } return null; }
- After that, we call the OnloadXML with the load of UXML in panelRenderer.
- For the UXML load, we will subscribe to the OnloadXML with the postUxmlReload event of PanelRenderer in Start(). So it can be called at the time of loading and reloading.
public class GeneralScreens : MonoBehaviour { PanelRenderer panelRenderer; void Start() { panelRenderer = this.GetComponent<PanelRenderer>(); if (panelRenderer) { panelRenderer.postUxmlReload += OnloadUXML; } } //call OnLoad of UXML in panelRenedere IEnumerable<Object> OnloadUXML() { var root = panelRenderer.visualTree; //Find & Subscribe Method onclick event On "Tap to Start" (Name in UXML is "Play" ) Button of Mainmenu Screen var tapToStart = root.Q<Button>("Play"); // find Play button in Uxml(visualTree) if (tapToStart != null) { tapToStart.clicked += OnPlay; // subscribe event } //Find & Subscribe Method onclick event On "Exit" (Name in UXML is "Exit" ) Button of Mainmenu Screen var exit = root.Q<Button>("Exit");// find Exit button in Uxml(visualTree) if (exit != null) { exit.clicked += OnExit; // subscribe event } return null; } // Call OnTap of Play button of MainmenuScreen private void OnPlay() { Debug.Log("Clicked on Tap to Start"); } // Call OnTap of Exit button of MainmenuScreen private void OnExit() { Debug.Log("Clicked on Exit"); } // Call OnTap of Back button of GamePlayeScreen void OnBack() { Debug.Log("OnBack"); StartCoroutine(TransitionScreens(this.gamePlay, mainmenu)); // screen transition from GameplayScreen to MainmenuScreen } }
- In a similar way, create UXML of Gameplay Screen and set the Back button. Assign the name of that Button “Back” and the name of the screen “GamePlayScreen.uxml”.
- Similarly, in script create one more panel object find the Back button, and assign the method OnBack accordingly.
Set the Screen Transition
- For Screen Transition, we need the reference of the PanelRenderer on both of the screens so we set the references from MainMenu and GamePlay and assign it to the inspector.
- Using the TransitionScreens coroutine, we set the transition from one screen to another screen. There, “from” means the current screen and “to” means your destination screen.
- Disable the panel renderer & Event System of the gameplay Screen Because at a time, only one event system & one screen will render or work and that is the main menu screen so we Disable the EventSystem & PanelRenderer of gameplay Screen.
// For Screen Transition IEnumerator TransitionScreens(PanelRenderer from, PanelRenderer to) { from.visualTree.style.display = DisplayStyle.None; from.gameObject.GetComponent<UIElementsEventSystem>().enabled = false; to.enabled = true; to.visualTree.style.display = DisplayStyle.Flex; to.gameObject.GetComponent<UIElementsEventSystem>().enabled = true; from.enabled = false; yield return null; }
This is what the final script should look like :
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UIElements; using Unity.UIElements.Runtime; public class GeneralScreens : MonoBehaviour { public PanelRenderer mainmenu; public PanelRenderer gamePlay; PanelRenderer panelRenderer; void Start() { panelRenderer = this.GetComponent<PanelRenderer>(); if (panelRenderer) { panelRenderer.postUxmlReload += OnloadUXML; } } //call OnLoad of UXML in panelRenedere IEnumerable<Object> OnloadUXML() { var root = panelRenderer.visualTree; //Find & Subscribe Method onclick event On "Tap to Start" (Name in Uxml is "Play" ) Button of Mainmenu Screen var tapToStart = root.Q<Button>("Play"); // find Play button in Uxml(visualTree) if (tapToStart != null) { tapToStart.clicked += OnPlay; // subscribe event } //Find & Subscribe Method onclick event On "Exit" (Name in Uxml is "Exit" ) Button of Mainmenu Screen var exit = root.Q<Button>("Exit");// find Exit button in Uxml(visualTree) if (exit != null) { exit.clicked += OnExit; // subscribe event } //Find & Subscribe Method onclick event On "Let's Back" (Name in Uxml is "Back" ) Button of GamePlay Screen var back = root.Q<Button>("Back");// find Back button in Uxml(visualTree) if (back != null) { back.clicked += OnBack; // subscribe event } return null; } // Call OnTap of Play button of MainmenuScreen private void OnPlay() { Debug.Log("Clicked on Tap to Start"); StartCoroutine(TransitionScreens(this.mainmenu, gamePlay)); // screen transition from MainmenuScreen to GameplayScreen } // Call OnTap of Exit button of MainmenuScreen private void OnExit() { Debug.Log("Clicked on Exit"); Application.Quit(); } // Call OnTap of Back button of GamePlayeScreen void OnBack() { Debug.Log("OnBack"); StartCoroutine(TransitionScreens(this.gamePlay, mainmenu)); // screen transition from GameplayScreen to MainmenuScreen } // For Screen Transition IEnumerator TransitionScreens(PanelRenderer from, PanelRenderer to) { from.visualTree.style.display = DisplayStyle.None; from.gameObject.GetComponent<UIElementsEventSystem>().enabled = false; to.enabled = true; to.visualTree.style.display = DisplayStyle.Flex; to.gameObject.GetComponent<UIElementsEventSystem>().enabled = true; from.enabled = false; yield return null; } }
Conclusion
Thus, it was the basic introduction about how to start working with the new UI builder workflow in unity. There are many more features available, especially for UI Editor. I hope this blog will help you get started working with the UI elements & get the basic idea about the new workflow.