How to create simple UI in s&box
The UI system in s&box is powerful, and easy to use. This guide gives you an introduction to using it.
This article is outdated, as templates have been replaced with a Razor based system. It will be updated soon.
s&box is praised for having an easy-to-use and versatile UI system. A combination of HTML, SCSS, and C# make it easy to create and style user interfaces. This guide will give an introduction to creating a simple UI in s&box.
RootPanel
RootPanel is your introduction to your user interface. It should act as the parent to all other panels. You can create a RootPanel by simply deriving the RootPanel class in your C# class, as seen below.
Initializing this class will create the RootPanel.
In the above example, we ensure we are only creating MyHud on the client. This means MyHud and all children are client-side only. You can reference the client and pawn using Local.Client
and Local.Pawn
.
Element Flow
When you create multiple elements in s&box, how is the order determined in how they are displayed? The answer is simple: flexbox.
Flexbox is module for CSS that provides a simple way to organize layouts. Every single panel in s&box follows default flex rules. Certain properties allow you to control how flex displays its children, such as flex-direction, flex-grow, and flex-wrap.
One popular method of learning flexbox we recommend before diving too deep into s&box UI is flexbox froggy.
Panel Inspector
You can see the panel we just created by using the Panel Inspector view in the s&box editor.
In the Panels view, click the dropdown and select ExampleUI.MyHud.
Once selected, you can click on MyHud and see the outline for our RootPanel. You should see a white box outlining your game screen. This view will become more useful as we add more panels to our game.
Now that we have created a RootPanel, we should probably put some panels in it.
Static UI (HTML)
Using HTML templates is the easiest way to create UI quickly. It has lots of advantages:
- Hotloading works fantastically
- Easy to populate complex layouts quickly
- Less verbose than its C# equivalent
To use a template, you can simply add the [UseTemplate] attribute to your C# class, and then create a .html file of the same name. Using our example from above, we would modify the code slightly:
Then, create a file named MyHud.html:
If you start or restart your game, you should now see text in the top-left corner of your screen that says "My Sample Game". But it doesn't look very good yet. We are going to add style to it using scss.
Styling
Often, developers name their stylesheets the same as their panels and html templates, but it's not a requirement. For the sake of simplicity, we are going to create a .scss file called MyHud.scss:
Next, we have to link this stylesheet to our template. The easiest way to do this is in our template. Add this line to the top of MyHud.html:
If you already have your game open, adding the <link> and saving the .html file should hotload the style for you. The "My Sample Game" text should now be huge!
Dynamic UI (C#)
Using C# to create our UI is also a great option. Instead of using a template, let's start with a barebones MyHud.cs again. This time, though, we will start filling up the class.
We can load a stylesheet manually, or we can set the styles of the components manually. While this is slower, more verbose, and often not recommended, it can be useful if you need to update a style based your game's state or other conditions.
TitleLabel = Add.Label( "My Sample Game", "title-label" );
TitleLabel.Style.FontColor = Color.Red;
TitleLabel.Style.FontSize = 72;
Hotloading
You may notice that changing these styles is not hotloading like it might when changing our .html and .scss files. Since MyHud is created once when the game starts, it won't run the constructor for MyHud again, thus requiring a restart to see the changes.
You can override the OnHotloaded() method to ensure something is run after a hotload, but keep in mind anything you do in this method will never actually be called when your game is played.
Tick
Every UI element created in C# can override the Tick() method to constantly check certain conditions based on your game's state. Consider the following example:
Since we created the UI client-side, we can use Local.Client
to check the client running the code. We then set the label's text to the client's name.
While setting a label to our client's name is a very simple example, you can see how useful this pattern could be. You could update a client's score based on a networked variable in your game class, populate a scoreboard using a list of all players.
Hybrid
Hybrid UI is the ideal situation for most use cases. It uses a combination of templates, C#, and stylesheets to create a well-oiled user interface machine.
Start with a template, and for any elements that need to be changed or updated, you can bind that element to a property in your C# class.
Check out the s&box wiki page on UI Layout Binding for more information. You can bind individual property, call events, and more with the various binding functionality s&box provides!
HudEntity
One last thing to cover is HudEntity. It is an entity that wraps your RootPanel (or any panel). You can reference it for use in RPCs, but it hasn't found much proper use in s&box development yet. Since it is an entity, you should initialize slightly differently. Check out the code below for an example:
Conclusion
Creating user interfaces in s&box is fast, easy, and fun! After following this tutorial, you should have everything you need to start writing basic user interfaces in s&box.