<img height="1" width="1" style="display:none;" alt="" src="https://px.ads.linkedin.com/collect/?pid=4958233&amp;fmt=gif">
 
RSS Feed

Software Engineering | Olaf Spiewok |
11 July 2023

In part 1 of this series, we started exploring how the right tools can make your game development processes easier and more efficient, using the example of our BuildAndDeploy package.

Creating tools helps you to improve your productivity. Tools can save time, reduce the cost spent on repetitive tasks and reduce the risk of errors by streamlining the build and deploy processes. The time and effort saved by using a tool will enable you to spend that time on more important tasks or may simply help you to shorten your time to market and make your builds available much faster – especially for Games as a Service, shortening release cycles is critical for the success of a game.

In this part, let’s look at another Unity tool our team developed.

UI Toolkit – UXML Binding Generator

 

Introduction

Unity has implemented its new UI Toolkit, which allows you to create UIs by decoupling the interface within XML-like files (called *.uxml) and binding them to the appropriate game and UI state. The XML contains the structure of the UI hierarchy and allows you to customise the appearance of each node with various attributes, like name, size, colour, margin etc. This is especially helpful in a large-scale project since it reduces collision between UI, logic and scene by having multiple files and a well-documented history of UI changes.

One drawback of this decoupling is that splitting UI from logic can result in incorrect code assignments if the UI component name attribute or type changes and the logic code is not updated correctly. That’s where our Binding Generator comes into play.

Our motivation

The Binding Generator creates a code class for each UI XML file, which will allow you to easily detect changes in your UIs. Once a UXML file is changed by adding new elements or changing its type or the name attributes of an element node, the generated code will allow you to throw compiler errors wherever those nodes get used within the code. This prevents runtime exceptions and corrupted UI states and gives you a consistent overview of all ‘UI content’ while developing any one specific UI. This helps to improve your productivity – and gives you that warm feeling that everything is going well. Similar approaches apply to the Microsoft XAML UI, Android UI or iOS interface builders.

UXML Binding code sample

Usage and benefits

We tried to make the tool as easy to use as possible, so we made a package. Simply add it using the Unity package manager, and you are ready to go. Follow the instructions in the documentation (./getting-started.md) to get an overview of how to use the tool. To give you a head start, here’s a sneak preview and some benefits the Binding tool may give you:

1. You can customise your Binding approach using the Uxml Binding Settings within the Project Settings. Besides selecting the template file, which is used to generate the code, you will find various properties to customise your auto-generated code file. You can change the namespace, class name format and the output directory to which all your bindings will be saved. In addition, there are multiple ‘Binding Generator Types’, which allow you to be more memory-, performance- or debug-aware when auto-generating your code files.

UXML Binding settings

2. After a Unity UXML file is changed, right-click on the file(s) or folder(s) and use the context menu to trigger the code generator for each file. You can also toggle “On Changed” binding generation within the UXML Binding settings to automate this. Once the binding class is created, you need to instantiate it within your code and associate it to your VisualTreeAsset to get your queries and your properties filled. Since all properties now reflect an element in your UI hierarchy, any changes or an updated generator file will let the compiler report any inconsistencies at compile time.

3. The tool is highly customisable, and you can change the Script Template used for the auto-generation process. You want to have a class or struct? Derive it from a given base class or interface? Contain multiple convenient methods? Just change the template, and you can tailor the generated files to your requirements!

Script template

4. You can convert all UXML files at once using the file context menu, which will spare you lots of manual conversions. If you want to exclude some folders from the process, you can select these as ‘ignored folders’. Using CI systems, you can also update the code as a ‘pre-build’ step to ensure all your files are up to date.

5. Querying code within your logic UI classes is moved to the Binding classes/structs, which makes your code clean and robust. 

6. The UXML Binding Generator is a lightweight package that you don’t need to add to your published code. Once all binding files have been generated, the generator package can be removed without dependency issues since only the generated code itself is needed.

The only drawback of all this file-binding is that, depending on your generator type, a slight memory footprint may remain when you create thousands of Binding classes/structs. You can minimise that footprint by changing the generator type and, in edge-case scenarios where lists create thousands of visual tree assets, adding static methods inside the templates. Thus, you can find the binding approach best suited for your project and even derive or partialise your auto-generated binding classes to make the most of them. 

A practical example

To demonstrate how helpful the binding package can be, imagine a complex UI like the one in Unity’s Dragon Crashers sample.

Dragon Crashers UI example

A vast number of buttons, labels, list items, tabs and the like are grouped within various UI files and reflect each UI element within the sample.

UXML file with individual UI elements

All node entries have a type and a name attribute with which you can identify the VisualElement within your code. In a project without the UXML Binding Generator package, you would have to query each individual node element by using the query method:

Query method example

Somewhere within your business logic, a number of query methods combined with constant string declarations will allow you to access and use the corresponding node element, which hopefully matches the loaded UXML file.

But what happens if a designer or developer changes the name attribute or type of the queried element? You’ll have to change the constant or adjust the query type manually… a step that is easily forgotten, which can lead to exceptions or issues that you can only detect at runtime.

Using the Binding Generator – and training your team to remember to generate the corresponding code files after changing a UI – will move all of this querying code to an automatically generated file, which can be instantiated and accessed by using properties instead:

Querying via an aggregate file

Whenever the UXML gets changed, an update of the Binding file will be instantly reflected in the code since the properties have changed and give you compile time feedback.

No null references at runtime and no longer hours of remapping between UI and business logic needed… fantastic, right?!

Conclusion

The UXML Binding Generator gives you a lot of flexibility to convert the XML files created by UI designers into code-generated files which you can work with on the programming side. This will bypass many headaches around changes in UI files, which you’d often only detect within runtime. Since all related changes will now be reflected in properties available at compile time, the compiler can support you with any inconsistencies.

Whenever we have a project using UI Toolkit, we include this package to avoid all the manual querying.

UXML UI Binding tool overview

No matter if your project contains 1 or 1000 UXML files, using the Binding Generator gives you the freedom to get the UI filled up with logic and the ability to wire a safety net around the relationship between the two.

Olaf Spiewok

Senior Developer

Olaf has been part of Endava for more than 13 years, with his focus being on game development. As a universal game development whizz, he is comfortable working with different platforms, like standalone systems, Nintendo DS, television, or mobile, and frameworks, among them Unity, React, Cocos, Android, and iOS – and the associated variety of programming language skills. Olaf is proficient in a diverse range of game development areas, including UI, workflow, gameplay, integration, and maintenance. Besides his development work, Olaf spends his free time with his family and dog, playing games – digital and analogue, indoors and outdoors – as well as learning to understand the Berlin dialect.

 

FROM THIS AUTHOR

  • 04 July 2023

    Boost Your Game’s Success with Tools – Part 1

  • 04 January 2022

    Create Production-Ready, Automated Deliverables Using a Build Pipeline for Games – Part 2

  • 16 November 2021

    Create Production-Ready, Automated Deliverables Using a Build Pipeline for Games – Part 1

 

Archive

  • 13 November 2023

    Delving Deeper Into Generative AI: Unlocking Benefits and Opportunities

  • 07 November 2023

    Retrieval Augmented Generation: Combining LLMs, Task-chaining and Vector Databases

  • 19 September 2023

    The Rise of Vector Databases

  • 27 July 2023

    Large Language Models Automating the Enterprise – Part 2

  • 20 July 2023

    Large Language Models Automating the Enterprise – Part 1

  • 11 July 2023

    Boost Your Game’s Success with Tools – Part 2

  • 04 July 2023

    Boost Your Game’s Success with Tools – Part 1

  • 01 June 2023

    Challenges for Adopting AI Systems in Software Development

  • 07 March 2023

    Will AI Transform Even The Most Creative Professions?

  • 14 February 2023

    Generative AI: Technology of Tomorrow, Today

  • 25 January 2023

    The Joy and Challenge of being a Video Game Tester

  • 14 November 2022

    Can Software Really Be Green

  • 26 July 2022

    Is Data Mesh Going to Replace Centralised Repositories?

  • 09 June 2022

    A Spatial Analysis of the Covid-19 Infection and Its Determinants

  • 17 May 2022

    An R&D Project on AI in 3D Asset Creation for Games

  • 07 February 2022

    Using Two Cloud Vendors Side by Side – a Survey of Cost and Effort

  • 25 January 2022

    Scalable Microservices Architecture with .NET Made Easy – a Tutorial

  • 04 January 2022

    Create Production-Ready, Automated Deliverables Using a Build Pipeline for Games – Part 2

  • 23 November 2021

    How User Experience Design is Increasing ROI

  • 16 November 2021

    Create Production-Ready, Automated Deliverables Using a Build Pipeline for Games – Part 1

  • 19 October 2021

    A Basic Setup for Mass-Testing a Multiplayer Online Board Game

  • 24 August 2021

    EHR to HL7 FHIR Integration: The Software Developer’s Guide – Part 3

  • 20 July 2021

    EHR to HL7 FHIR Integration: The Software Developer’s Guide – Part 2

  • 29 June 2021

    EHR to HL7 FHIR Integration: The Software Developer’s Guide – Part 1

  • 08 June 2021

    Elasticsearch and Apache Lucene: Fundamentals Behind the Relevance Score

  • 27 May 2021

    Endava at NASA’s 2020 Space Apps Challenge

  • 27 January 2021

    Following the Patterns – The Rise of Neo4j and Graph Databases

  • 12 January 2021

    Data is Everything

  • 05 January 2021

    Distributed Agile – Closing the Gap Between the Product Owner and the Team – Part 3

  • 02 December 2020

    8 Tips for Sharing Technical Knowledge – Part 2

  • 12 November 2020

    8 Tips for Sharing Technical Knowledge – Part 1

  • 30 October 2020

    API Management

  • 22 September 2020

    Distributed Agile – Closing the Gap Between the Product Owner and the Team – Part 2

  • 25 August 2020

    Cloud Maturity Level: IaaS vs PaaS and SaaS – Part 2

  • 18 August 2020

    Cloud Maturity Level: IaaS vs PaaS and SaaS – Part 1

  • 08 July 2020

    A Virtual Hackathon Together with Microsoft

  • 30 June 2020

    Distributed safe PI planning

  • 09 June 2020

    The Twisted Concept of Securing Kubernetes Clusters – Part 2

  • 15 May 2020

    Performance and security testing shifting left

  • 30 April 2020

    AR & ML deployment in the wild – a story about friendly animals

  • 16 April 2020

    Cucumber: Automation Framework or Collaboration Tool?

  • 25 February 2020

    Challenges in creating relevant test data without using personally identifiable information

  • 04 January 2020

    Service Meshes – from Kubernetes service management to universal compute fabric

  • 10 December 2019

    AWS Serverless with Terraform – Best Practices

  • 05 November 2019

    The Twisted Concept of Securing Kubernetes Clusters

  • 01 October 2019

    Cognitive Computing Using Cloud-Based Resources II

  • 17 September 2019

    Cognitive Computing Using Cloud-Based Resources

  • 03 September 2019

    Creating A Visual Culture

  • 20 August 2019

    Extracting Data from Images in Presentations

  • 06 August 2019

    Evaluating the current testing trends

  • 23 July 2019

    11 Things I wish I knew before working with Terraform – part 2

  • 12 July 2019

    The Rising Cost of Poor Software Security

  • 09 July 2019

    Developing your Product Owner mindset

  • 25 June 2019

    11 Things I wish I knew before working with Terraform – part 1

  • 30 May 2019

    Microservices and Serverless Computing

  • 14 May 2019

    Edge Services

  • 30 April 2019

    Kubernetes Design Principles Part 1

  • 09 April 2019

    Keeping Up With The Norm In An Era Of Software Defined Everything

  • 25 February 2019

    Infrastructure as Code with Terraform

  • 11 February 2019

    Distributed Agile – Closing the Gap Between the Product Owner and the Team

  • 28 January 2019

    Internet Scale Architecture

OLDER POSTS