Fragsurf

Building a powerful user interface

Some engines make UI development so difficult that it becomes the kind of task you'd like to avoid, that drags on over time and has a negative impact. I bought an asset that allows me to create the UI with html, css, and javascript. Web development is tried & tested and has been polished for many years, and it's probably better than any integrated UI system such as the one that Unity offers. I don't know why modern engines continue to roll in their own custom solutions, they almost always suck. Valve, on the other hand, is doing it right with Panorama.

When I first ingerated this html based UI solution, I was just happy to get away from Unity's UI and didn't spend much time setting it up in a way that will make things easy in the future when the files start getting large and complicated.

Binding Data

I have been creating a new system that integrates the HTML UI in a much more powerful and modular way to increase producitivity in the long-run. One of the first problems I had to solve was easily binding data between HTML and C#. Previously if I wanted to update, say, how fast I'm going in a HUD element, I would have a C# function that executes javascript in the browser each tick, a function in a browser to handle that, and an element in the html to render it.

void Update() {
     Browser.CallFunction("updateVelocity", Target.Velocity);   
}
function updateVelocity(velocity) {
     $("#velocity").textContent = velocity;   
}

This looks simple enough at a glance, but once you start having a ton of different things that need to be updated suddenly you have dozens of functions and the scripts are getting bloated and harder to work with. In comes data-bind, an easy solution to update values with minimal scripting requirement, and bypass javascript functions all-together.

void Init() {
     Browser.AddBind("Target.Velocity", () => Target.Velocity);   
}
<div data-bind="Target.Velocity"></div>

I've taken it a step further, and we can pass in Target as an entire object and access any public property from it. So if Target is a player object with a name, velocity, and position, we can do something like this:

void Init() {
    Browser.AddBind("Target", Target);
}
<div data-bind="Target" data-format>
    Name {Target.Name}
    Speed {Target.Velocity}
    Position {Target.Position}
</div>

The amount of headache this is going to prevent is immense, and while it's taking time to get it programmed in and implemented, it's definitely going to be worth it.

Styling

After reading Garry's blog about the Panorama UI I was a little bit jealous that I didn't have support for Less, I was stuck using vanilla javascript and vanilla css. So I went ahead and implemented Less, and suddenly writing stylesheets is considerably easier, cleaner, and enjoyable.

Customization

The new UI is pulled in during the runtime from the same folder that contains maps and everything else. They are plain old html files, and anybody can modify them to create a completely custom user-interface. Players can enable hotloading to refresh the UI in-game whenever a change is detected in a file.

I have to remember to implement a reset function, because it's guaranteed that somebody is gonna break their game with this sooner or later.

Minor setbacks

Ideally I'll be able to implement the new system while leaving old one in place and re-implementing the old UI little by little while keeping everything working and compatible. This means I don't have to redo everything before pushing another update. Hopefully it pans out.