Rebuilding Project 4’s UI System
Rebuilding Project 4’s UI System
AceiusIO - Sunday March 2nd 2025 - Reposted from Acei.us
Project 4‘s design calls for a somewhat complex HUD with quite a few menus and elements. While Bonetree already had a UI framework that was decent, there were quite a few things wrong with it that made it felt janky to use. So, I’ve spent the past few weeks rebuilding it.
Problems with the old system
For one, a lot of the names I used in it are just stupid.
- The base class that all UI elements inhert from in the system was called
Element
, but the namespace it was in wasControls
. This lead to me interchangeably referring to UI elements from the old system as element and control. - One of the main functions that descendants of
Element
have isSetSize
, butSetSize
does a lot more than actually size the element, it is also responsible for positioning the element in certain cases.
The old system also suffers from poor planning. For some reason, it didn’t occur to me until after I had already written a bunch of elements (such as text displays and buttons) that I would need to have some kind of element that could have child elements, so I hastily threw together a ContainerElement
. This element is used for most of Project 4’s UI, and it works, but not well.
The old system was also very inefficient, re-rendering every component every frame without any kind of caching, and it allocated a lot of strings which absolutely hammered the garbage collector.
The new system
The new system comes with many improvements over the old one. For starters, it has nearly 100% documentation coverage! While I haven’t run up against any problems remembering how to use Bonetree yet (since it’s been my main project for over a year now), I do want to open source it eventually, so documentation will greatly aid people who are perusing the code if that happens.
Next off, I put some thought into it’s design. Now, the base interface element class is called Widget
. Every widget has a parent, and can optionally have children, so the entire interface is no longer a messy list, but a tree. This also allows me to do some cool stuff with styling! In the old system, every single element had it’s own style object, but Widget
s don’t have to have one, and instead are able to inherit styles from their parent. Every widget is stored within a special widget known as the RootWidget
, an instance of which is held in the scene object.
Old widgets also stored their position in two properties of type int
, X
and Y
. The new system has two properties relating to position. The first of which is called Offset
, of type System.Point. It’s exact behavior depends on the value of Position
, which is an enum. I’ll let my wonderful documentation describe how it works exactly, but basically it alters the way the value of offset is interpreted.
The new system also makes use of caching wherever possible by drawing components into textures, and copying those to the screen. They are only updated when needed, saving a lot of processing power and giving the garbage collector a break. There are a couple of places I know I could improve performance, but honestly I don’t need to yet.
I have final exams & a robotics competition this week, so I haven’t had the time to fully migrate all the UI to the new system, but the next version of Project 4 that’s published on itch.io will definitely include it. I’m also considering joining a game jam to test out all the improvements I’ve made to Bonetree since I made Scale Tale for GMTK.
Leave a comment
Log in with itch.io to leave a comment.