UI Framework¶
Learn how to create user interfaces with Brine2D's built-in UI framework - buttons, text inputs, dialogs, and more.
Quick Start¶
using Brine2D.UI;
public class MenuScene : Scene
{
private readonly UICanvas _uiCanvas;
public MenuScene(UICanvas uiCanvas)
{
_uiCanvas = uiCanvas;
}
protected override Task OnLoadAsync(CancellationToken ct)
{
// Create button
var playButton = new Button
{
Text = "Play",
X = 350,
Y = 250,
Width = 100,
Height = 40
};
playButton.OnClick += () =>
{
Logger.LogInformation("Play button clicked!");
// Load game scene
};
_uiCanvas.AddElement(playButton);
return Task.CompletedTask;
}
protected override void OnUpdate(GameTime gameTime)
{
_uiCanvas.Update(gameTime);
}
protected override void OnRender(GameTime gameTime)
{
_uiCanvas.Render(Renderer);
}
}
Topics¶
| Guide | Description | Difficulty |
|---|---|---|
| UI Components | 15+ built-in UI components | ⭐ Beginner |
| Custom UI | Create custom UI elements | ⭐⭐ Intermediate |
Key Concepts¶
UICanvas¶
The UICanvas manages all UI elements for a scene:
// Register as scoped (per-scene)
builder.Services.AddUICanvas();
// Inject in scene
public class MenuScene : Scene
{
private readonly UICanvas _canvas;
public MenuScene(UICanvas canvas)
{
_canvas = canvas;
}
}
Benefits: - Automatic input handling - Z-ordering (layers) - Lifecycle management - Input layer integration
Available Components¶
Brine2D includes 15+ production-ready UI components:
| Component | Description |
|---|---|
| Button | Clickable button with text/icon |
| Label | Static or dynamic text |
| TextInput | Text entry field |
| Slider | Value slider (volume, brightness) |
| Checkbox | Toggle on/off |
| RadioButton | Single selection from group |
| ProgressBar | Loading/health bar |
| Panel | Container for other elements |
| Dialog | Modal popup window |
| Tooltip | Hover information |
| Dropdown | Selection menu |
| ScrollView | Scrollable container |
| TabControl | Tabbed interface |
| Image | Display texture |
| LayoutContainer | Automatic positioning |
Common Tasks¶
Create Button¶
var button = new Button
{
Text = "Start Game",
X = 350,
Y = 250,
Width = 100,
Height = 40,
BackgroundColor = Color.Blue,
TextColor = Color.White
};
button.OnClick += () =>
{
Logger.LogInformation("Button clicked!");
};
_uiCanvas.AddElement(button);
Create Text Input¶
var nameInput = new TextInput
{
X = 300,
Y = 200,
Width = 200,
Height = 30,
Placeholder = "Enter your name..."
};
nameInput.OnTextChanged += (text) =>
{
Logger.LogInformation("Name: {Name}", text);
};
_uiCanvas.AddElement(nameInput);
Create Slider¶
var volumeSlider = new Slider
{
X = 300,
Y = 250,
Width = 200,
Height = 20,
MinValue = 0f,
MaxValue = 1f,
Value = 0.8f
};
volumeSlider.OnValueChanged += (value) =>
{
_audio.SetMasterVolume(value);
Logger.LogInformation("Volume: {Volume:P0}", value);
};
_uiCanvas.AddElement(volumeSlider);
Create Dialog¶
var dialog = new Dialog
{
Title = "Quit Game?",
Message = "Are you sure you want to quit?",
X = 250,
Y = 200,
Width = 300,
Height = 150
};
dialog.AddButton("Yes", () =>
{
Application.Quit();
});
dialog.AddButton("No", () =>
{
dialog.Close();
});
_uiCanvas.AddElement(dialog);
HUD (Health Bar)¶
// Health label
var healthLabel = new Label
{
Text = "Health:",
X = 10,
Y = 10,
TextColor = Color.White
};
// Health bar
var healthBar = new ProgressBar
{
X = 80,
Y = 10,
Width = 200,
Height = 20,
MinValue = 0,
MaxValue = 100,
Value = 75, // 75% health
ForegroundColor = Color.Green,
BackgroundColor = Color.DarkGray
};
_uiCanvas.AddElement(healthLabel);
_uiCanvas.AddElement(healthBar);
// Update health
healthBar.Value = _playerHealth;
Layout Container¶
// Automatic vertical layout
var menu = new VerticalLayoutContainer
{
X = 350,
Y = 200,
Spacing = 10
};
menu.AddChild(new Button { Text = "Play", Width = 100, Height = 40 });
menu.AddChild(new Button { Text = "Options", Width = 100, Height = 40 });
menu.AddChild(new Button { Text = "Quit", Width = 100, Height = 40 });
_uiCanvas.AddElement(menu);
// Buttons automatically positioned vertically with 10px spacing
Input Layers¶
UI elements automatically create input layers for priority handling:
// UI layer (priority 100 - high)
var dialog = new Dialog { ... };
_uiCanvas.AddElement(dialog);
// When dialog is open, game input is blocked
// Dialog consumes input events first
// When dialog closes, game input resumes
Best Practices¶
✅ DO¶
- Use UICanvas - One per scene
- Position with X/Y - Absolute screen coordinates
- Handle events - OnClick, OnValueChanged, etc.
- Use layouts - Automatic positioning
- Z-order matters - Last added = on top
// ✅ Good pattern
protected override Task OnLoadAsync(CancellationToken ct)
{
// Create all UI
CreateMenuUI();
return Task.CompletedTask;
}
protected override void OnUpdate(GameTime gameTime)
{
// Update UI
_uiCanvas.Update(gameTime);
}
protected override void OnRender(GameTime gameTime)
{
// Render game first
DrawGameObjects();
// Render UI last (on top)
_uiCanvas.Render(Renderer);
}
❌ DON'T¶
- Don't create multiple UICanvas - One per scene
- Don't forget to update - Call Update() in OnUpdate()
- Don't forget to render - Call Render() in OnRender()
- Don't manually handle input - UICanvas does it
- Don't hardcode positions - Use layouts or calculate from screen size
// ❌ Bad - hardcoded for 800x600
var button = new Button { X = 400, Y = 300 };
// ✅ Good - centered
var button = new Button
{
X = (screenWidth - buttonWidth) / 2,
Y = (screenHeight - buttonHeight) / 2
};
Styling¶
Custom Colors¶
var button = new Button
{
Text = "Custom",
BackgroundColor = new Color(50, 50, 50, 255), // Dark gray
HoverColor = new Color(70, 70, 70, 255), // Lighter on hover
PressedColor = new Color(30, 30, 30, 255), // Darker when pressed
TextColor = Color.White,
BorderColor = Color.Blue,
BorderWidth = 2
};
Custom Fonts¶
var label = new Label
{
Text = "Custom Font",
Font = await _assets.GetOrLoadFontAsync("assets/fonts/custom.ttf", 24),
TextColor = Color.Gold
};
Troubleshooting¶
UI Not Responding to Input¶
Symptom: Buttons don't respond to clicks
Solutions:
- Check Update() is called:
protected override void OnUpdate(GameTime gameTime)
{
_uiCanvas.Update(gameTime); // Must be called!
}
- Verify element is added:
_uiCanvas.AddElement(button); // Don't forget!
- Check Z-order:
// Elements added last are on top
_uiCanvas.AddElement(background); // Bottom
_uiCanvas.AddElement(button); // Top (receives input)
UI Not Visible¶
Symptom: UI elements not drawn
Solutions:
- Check Render() is called:
protected override void OnRender(GameTime gameTime)
{
_uiCanvas.Render(Renderer); // Must be called!
}
- Check coordinates:
// Make sure element is on screen
Logger.LogDebug("Button at ({X}, {Y})", button.X, button.Y);
- Check visibility:
button.Visible = true; // Default is true
Text Not Showing¶
Symptom: Button has no text
Solutions:
- Check font is loaded:
if (button.Font == null)
{
Logger.LogWarning("Button has no font");
}
- Check text color:
button.TextColor = Color.White; // Not transparent!
Related Topics¶
- UI Components - Complete component list
- Custom UI - Build custom elements
- Input Layers - Priority-based input
- Mouse Input - Mouse handling
Ready to build UI? Start with UI Components!