Responsive Game UI

Code and workflow to make a responsive game UI in UI Builder

What you'll develop on this page

We will make a Game UI that will respond to click events as well as display game and player data and add it to our Project.

Github branch link: https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/tree/Game-UI-Overlay

What will appear in our GameUI

We will make a simple game UI overlay that provides the user the ability to return to NavigationScene as well as see game and player information.

Our GameUI uxml will use TitleScreenUI for its .screen and .header selector stylings. Although this isn't totally necessary because we will actually make a new selector class that modifies both of these selectors (.screen needs to be updated for white text and the header needs to be updated to expand to fit its contents), we decided to still include TitleScreenUI USS in GameUI uxml just to demonstrate how to use 2 USSs in a single UXML in UI Builder... It just seems like an entire section in a gitbook dedicated to UI should have at least one (albeit nominal) example of multiple USS sheets, you know?

We will create a new USS called "GameUI" that will hold GameUI specific stylings.

Our GameUI will have a footer that hugs the bottom of the screen similar to how the header hugs the top of the screen.

The right side of the header will contain game information. Although the game information will be static in this section, we'll make it dynamic in the next Multiplayer section.

The bottom left of the screen will display static instructions on how to navigate the game. If you end up updating the game controls please be sure to update these instructions as well.

The bottom right of the screen will display player-specific information. Although the game information will be static in this section, we'll make it dynamic in the next Multiplayer section..

Creating our GameUI

  • Now that we are ready to start switching between scenes let's give our game scene the respect it deserves and change its name from "SampleScene" to "MainScene" 🏋️‍♂️

  • Navigate to Assets/Scenes

    • Right-click SampleScene and rename to MainScene

    • If you have a SampleSceneSettings file in your Project folder, then right-click on SampleSceneSettings and rename it to MainSceneSettings

    • Right-click on SampleScene/ (folder) and rename to MainScene

  • Open up our newly respected MainScene Scene (not folder) so that MainScene is in Hierarchy

  • Right-click in the Hierarchy and create an empty GameObject named "GameUI"

    • Now there is a GameUI GameObject in the MainScene

    • Add a "Input System Event System (UI Toolkit)" component

    • Add a UI Document component

      • Drag "PanelSettings" from Assets/UI onto Panel Settings

  • Right-click in the Assets/UI folder and create a new UI Document named "GameUIManager" (Create > UI Toolkit > UI Document)

    • Drag GameUIManager uxml onto Source Asset field in the UI Document component in Inspector when the GameUI GameObject is selected in Hierarchy

  • Create a new script for our GameUIManager custom Visual Element (cVE), "GameUIManager"

    • Right-click in UI > Create > C# Script

  • Paste the code snippet below into GameUIManager.cs (cVE):

using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UIElements;
using Unity.Burst;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Networking.Transport;
using Unity.NetCode;

public class GameUIManager : VisualElement
{
    VisualElement m_LeaveArea;

    public new class UxmlFactory : UxmlFactory<GameUIManager, UxmlTraits> { }

    public GameUIManager()
    {
        this.RegisterCallback<GeometryChangedEvent>(OnGeometryChange);
    }

    void OnGeometryChange(GeometryChangedEvent evt)
    {
        m_LeaveArea = this.Q("quit-game");

        m_LeaveArea?.RegisterCallback<ClickEvent>(ev => ClickedButton());
    }

    // Start is called before the first frame update
    void Start()
    {
        
    }

    void  ClickedButton() {

        Debug.Log("Clicked quit game");
    }  
}
  • Open up UI Builder (Window > UI Toolkit > UI Builder)

  • Navigate to the Library section of the left panel, click the Project tab and under UI Documents (UXML) within the Asset/UI folder, hover over the GameUIManager uxml for the open icon on the right to appear, and click the icon to open GameUIManager.uxml in Hierarchy

  • In StyleSheets (top left) hit the "+" and

    • Add Existing USS "TitleScreenUI"

      • Sometimes we found in our testing that searching "TitleScreenUI" in Finder's search bar led to no results. If that happens to you just use the old fashion way of finding TitleScreenUI by opening up the Assets folder, then opening up the UI folder, and then scrolling to find TitleScreenUI.uss

    • Create New USS "GameUI" (save it in Assets/UI folder, which you may need to expand Finder in order to do so)

  • Find GameUIManager in the Custom Controls (C#) section of Library > Project tab and drag it into Hierarchy

  • While #GameUIManager is highlighted in Hierarchy, go to Inspector and type "GameUIManager" into the Name field

  • Save the GameUIManager uxml (best to save while GameUIManager.uxml is selected in Hierarchy -- for some reason it's less confusing to UI Builder that way!)

You will notice we are following the same "ScreenManager" pattern we used in NavigationScene.

Although we do not switch between views like we do in TitleScreenManager, we want to set up our game UI so it is easy to extend in the future.

We have already reviewed how to create and style views in the "Styling a View" section of our gitbook, so for the next few files we provide you with the code rather than re-creating the views piece-by-piece (not a lot to gain from more of the same).

  • Paste the code snippet below into GameUIManager.uxml:

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
    <Style src="TitleScreenUI.uss" />
    <Style src="GameUI.uss" />
    <GameUIManager name="GameUIManager" style="width: 100%; height: 100%;">
        <ui:VisualElement name="screen" class="screen game-ui-screen">
            <ui:VisualElement name="header" class="header game-ui-header">
                <ui:Button text="Quit Game" name="quit-game" class="quit-game-button" />
                <ui:VisualElement name="top-right-container" class="top-right-container">
                    <ui:Label text="Frank&apos;s Game" name="game-name" class="top-right-values" />
                    <ui:Label text="GAME NAME" name="game-name-label" class="top-right-labels" />
                    <ui:VisualElement name="spacer" class="spacers" />
                    <ui:Label text="127.0.0.1" name="game-ip" class="top-right-values" />
                    <ui:Label text="IP ADDRESS" name="ip-address-label" class="top-right-labels" />
                    <ui:VisualElement name="spacer" class="spacers" />
                    <ui:Label name="highest-score" class="top-right-values" />
                    <ui:Label text="HIGHEST SCORE" name="highest-score-label" class="top-right-labels" />
                </ui:VisualElement>
            </ui:VisualElement>
            <ui:VisualElement name="footer" class="footer">
                <ui:VisualElement name="bottom-left" class="bottom-left">
                    <ui:Label text="Use &quot;p&quot; key to self-destruct" name="instructions-1" class="instruction-text" />
                    <ui:Label text="Use space bar to fire missles" name="instructions-2" class="instruction-text" />
                    <ui:Label text="Right-click and move mouse to rotate" name="instructions-3" class="instruction-text" />
                    <ui:Label text="Use WASD keys to thrust" name="instructions-4" class="instruction-text" />
                </ui:VisualElement>
                <ui:VisualElement name="bottom-right" style="margin-right: 10px;">
                    <ui:Label text="Jonathan" name="player-name" class="top-right-values" />
                    <ui:Label text="PLAYER NAME" name="game-name-label" class="top-right-labels" />
                    <ui:VisualElement name="spacer" class="spacers" />
                    <ui:Label text="0" name="current-score" class="top-right-values" />
                    <ui:Label text="CURRENT SCORE" name="current-score-label" class="top-right-labels" />
                    <ui:VisualElement name="spacer" class="spacers" />
                    <ui:Label text="0" name="high-score" class="top-right-values" />
                    <ui:Label text="HIGH SCORE" name="current-score-label" class="top-right-labels" />
                </ui:VisualElement>
            </ui:VisualElement>
        </ui:VisualElement>
    </GameUIManager>
</ui:UXML>
  • Paste the code snippet below into GameUI.uss:

.quit-game-button:hover {
    border-top-left-radius: 9px;
    border-bottom-left-radius: 9px;
    border-top-right-radius: 9px;
    border-bottom-right-radius: 9px;
    border-left-width: 5px;
    border-right-width: 5px;
    border-top-width: 5px;
    border-bottom-width: 5px;
}

.quit-game-button:active {
    background-color: rgb(255, 255, 255);
    color: rgb(0, 0, 0);
}

.quit-game-button {
    flex-direction: column-reverse;
    padding-left: 0;
    padding-right: 0;
    padding-top: 0;
    padding-bottom: 0;
    margin-left: 10px;
    margin-right: 0;
    margin-top: 0;
    margin-bottom: 0;
    background-color: rgba(0, 0, 0, 0);
    border-left-width: 3px;
    border-right-width: 3px;
    border-top-width: 3px;
    border-bottom-width: 3px;
    border-top-left-radius: 10px;
    border-bottom-left-radius: 10px;
    border-top-right-radius: 10px;
    border-bottom-right-radius: 10px;
    height: 68px;
    border-left-color: rgb(255, 255, 255);
    border-right-color: rgb(255, 255, 255);
    border-top-color: rgb(255, 255, 255);
    border-bottom-color: rgb(255, 255, 255);
    font-size: 24px;
    color: rgb(255, 255, 255);
    white-space: normal;
    max-width: 140px;
    width: 100%;
}

.game-ui-screen {
    background-color: rgba(0, 0, 0, 0);
    justify-content: space-between;
    color: rgb(255, 255, 255);
}

.game-ui-header {
    height: auto;
}

.top-right-container {
    margin-right: 10px;
    margin-top: 10px;
}

.top-right-values {
    color: rgb(255, 255, 255);
    -unity-text-align: upper-right;
    font-size: 18px;
}

.top-right-labels {
    -unity-text-align: upper-right;
    color: rgb(255, 255, 255);
    font-size: 10px;
}

.spacers {
    height: 3px;
}

.footer {
    bottom: 0;
    flex-direction: row;
    justify-content: space-between;
    position: absolute;
    flex-grow: 1;
    width: 100%;
    height: auto;
    padding-bottom: 10px;
}

.bottom-left {
    flex-direction: column-reverse;
    margin-left: 10px;
}

.instruction-text {
    color: rgb(255, 255, 255);
    white-space: normal;
    font-size: 14px;
}
  • Once you've updated the GameUI uxml and Game UI USS with the code above, return to MainScene

  • Hit "play" in MainScene and checkout the GameUI in action

    • You can click on the "Quit Game" button which will trigger a console log

We've now built responsive GameUI

  • We renamed our SampleScene to MainScene

  • We created our GameUI GameObject

    • We added Event System (UI Toolkit)

    • We added UI Document

  • We created GameUIManager uxml and placed it in UI Document's "Source Asset"

  • We dragged our Panel Settings to UI Document's "Panel Settings"

  • We created GameUIManager uxml and c VE

  • We added TitleScreenUI and new GameUI as USS to GameUIManager

  • We updated GameUIManager uxml and GameUI USS

Github branch link:

git clone https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/ git checkout 'Game-UI-Overlay'

Last updated