There's 2 good ways to make UI right now in s&box. You can either use Razor, or make Panels yourself. We recommend using Razor.
Making a Panel
Here's an example panel that has a Label which counts up forever.
MyPanel.cs
[UseTemplate]
public class MyPanel : Panel
{
public Label MyLabel { get; set; }
public override void Tick()
{
Label.Text = $"{Time.Now}";
}
}
[UseTemplate]
will load a template with the same class name (MyPanel.html
).
MyPanel.html
<link rel="stylesheet" href="MyPanel.scss"/>
<div>
<label class="name" @ref="MyLabel">Placeholder Text</label>
</div>
<link rel="stylesheet" href="MyPanel.scss"/>
will load a stylesheet with the file name that you specify. It works on relative paths from your .html
file.
MyPanel.scss
MyPanel {
position: absolute;
left: 64px;
top: 64px;
.name {
font-family: Poppins;
color: white;
font-size: 32px;
}
}
Tips and Tricks
You can set Panel classes - See Panel.SetClass, and Panel.BindClass
If a panel is not behaving as expected you can troubleshoot it using the Panel Inspector. While in Editor Mode, open the Explorer and hit Panels.
Scaling
By default, UI is scaled based on 1080p.
To change how scaling works, override your hud's UpdateScale()
method as such:
using Sandbox;
using Sandbox.UI;
public class Hud : RootPanel
{
protected override void UpdateScale( Rect screenSize )
{
Scale = 1;
}
}
Drawing Polygons
Example:
public class MyGUI : RootPanel
{
public override void DrawBackground(ref RenderState state)
{
Span<Vertex> vertices = new Vertex[] {
new Vertex( new Vector3( 100, 100 ), new Vector4( 0, 0, 0, 0 ), new Color32(255, 0, 0 ) ),
new Vertex( new Vector3( 300, 100 ), new Vector4( 0, 0, 0, 0 ), new Color32(0, 255, 0 ) ),
new Vertex( new Vector3( 300, 300 ), new Vector4( 0, 0, 0, 0 ), new Color32(0, 0, 255 ) ),
};
var attribs = new RenderAttributes();
attribs.Set( "Texture", Texture.White );
Graphics.Draw( vertices, 3, Material.UI.Basic, attribs, Graphics.PrimitiveType.Triangles );
}
}
Examples
These examples may be obsolete.
Example: HUD w/ health display
Down below you can see an example from our Sandbox gamemode.
SandboxHud
implements the HudEntity<RootPanel>
class and loads a stylesheet and all other UI components.
The Health
class implements Panel
and adds a bunch of stuff to the UI within its constructor.
It also has access to the local player's health within the Tick
-override, so the UI can be updated accordingly.
using Sandbox;
using Sandbox.UI;
[Library]
public partial class SandboxHud : HudEntity<RootPanel>
{
public SandboxHud()
{
if ( !IsClient )
return;
RootPanel.StyleSheet.Load( "/ui/SandboxHud.scss" );
RootPanel.AddChild<NameTags>();
RootPanel.AddChild<CrosshairCanvas>();
RootPanel.AddChild<ChatBox>();
RootPanel.AddChild<VoiceList>();
RootPanel.AddChild<KillFeed>();
RootPanel.AddChild<Scoreboard<ScoreboardEntry>>();
RootPanel.AddChild<Health>();
RootPanel.AddChild<InventoryBar>();
RootPanel.AddChild<CurrentTool>();
RootPanel.AddChild<SpawnMenu>();
}
}
Source: sandbox - SandboxHud.cs
using Sandbox;
using Sandbox.UI;
using Sandbox.UI.Construct;
public class Health : Panel
{
public Label Label;
public Health()
{
Label = Add.Label( "100", "value" );
}
public override void Tick()
{
var player = Local.Pawn;
if ( player == null ) return;
Label.Text = $"{player.Health.CeilToInt()}";
}
}
Source: sandbox - Health.cs
Example: Interacting with UI
We are able to interact with the stylesheet from the c# file. We can for exemple
- AddClass to a panel/Label
- RemoveClass to a panel/Label
In the exemple below we are removing the health hud if the player is in a car by using
(Panel, Label or this).AddClass(string classname)
and (Panel, Label or this).RemoveClass(string classname)
.
using Sandbox;
using Sandbox.UI;
using Sandbox.UI.Construct;
public class Health : Panel
{
public Label Label;
public Health()
{
Label = Add.Label( "100", "health-label active" );
}
public override void Tick()
{
var player = Local.Pawn;
if ( player == null ) return;
if (player.Health.CeilToInt() == -1)
{
Label.RemoveClass("active")
}
else
{
Label.AddClass("active")
}
Label.Text = $"{player.Health.CeilToInt()}";
}
}
.health-label
{
position: absolute;
background-color: rgba( black, 0.5 );
right: 100px;
bottom: 48px;
font-size: 40px;
font-weight: bold;
color: white;
height: 80px;
padding: 0 20px;
align-items: center;
opacity: 0;
&.active {
opacity: 1;
}
}