User Interface¶
PixelRoot32 provides a complete UI system for creating menus, HUDs, and interface elements. This guide covers all UI components and layout systems.
UI Elements¶
All UI elements inherit from UIElement, which itself inherits from Entity. This means UI elements can be added to scenes just like any other entity.
UILabel¶
Display text on screen:
#include <graphics/ui/UILabel.h>
// Create a label
pixelroot32::graphics::ui::UILabel* scoreLabel = new pixelroot32::graphics::ui::UILabel(
"Score: 0", // text
10, // x position
10, // y position
pixelroot32::graphics::Color::White, // color
1 // size multiplier
);
// Add to scene
addEntity(scoreLabel);
// Update text dynamically
scoreLabel->setText("Score: 100");
// Center horizontally
scoreLabel->centerX(240); // Screen width
UIButton¶
Create clickable buttons:
#include <graphics/ui/UIButton.h>
// Create a button
pixelroot32::graphics::ui::UIButton* startButton = new pixelroot32::graphics::ui::UIButton(
"Start Game", // text
4, // navigation index
50, // x position
100, // y position
140, // width
30, // height
[]() { // callback function
// Button clicked - start game
startGame();
}
);
// Configure style
startButton->setStyle(
pixelroot32::graphics::Color::White, // text color
pixelroot32::graphics::Color::Blue, // background color
true // draw background
);
// Add to scene
addEntity(startButton);
UICheckBox¶
Create interactive checkboxes:
#include <graphics/ui/UICheckBox.h>
// Create a checkbox
pixelroot32::graphics::ui::UICheckBox* soundCheckbox = new pixelroot32::graphics::ui::UICheckBox(
"Enable Sound", // text
4, // navigation index
50, // x position
140, // y position
140, // width
20, // height
true, // initial checked state
[](bool checked) { // callback function
// Checkbox state changed
setSoundEnabled(checked);
},
1 // font size
);
// Configure style
soundCheckbox->setStyle(
pixelroot32::graphics::Color::White, // text color
pixelroot32::graphics::Color::Blue, // background color
false // draw background
);
// Add to scene
addEntity(soundCheckbox);
UIPanel¶
Create visual containers with background and border:
#include <graphics/ui/UIPanel.h>
// Create a panel
pixelroot32::graphics::ui::UIPanel* dialog = new pixelroot32::graphics::ui::UIPanel(
50, // x
50, // y
140, // width
140 // height
);
// Configure appearance
dialog->setBackgroundColor(pixelroot32::graphics::Color::Black);
dialog->setBorderColor(pixelroot32::graphics::Color::White);
dialog->setBorderWidth(2);
// Add content (typically a layout)
dialog->setChild(menuLayout);
// Add to scene
addEntity(dialog);
Layouts¶
Layouts automatically organize UI elements, eliminating the need for manual position calculations.
UIVerticalLayout¶
Organize elements vertically with automatic scrolling:
#include <graphics/ui/UIVerticalLayout.h>
// Create vertical layout
pixelroot32::graphics::ui::UIVerticalLayout* menu = new pixelroot32::graphics::ui::UIVerticalLayout(
10, // x
60, // y
220, // width
160 // height (viewport)
);
// Configure layout
menu->setPadding(5); // Internal padding
menu->setSpacing(6); // Space between elements
menu->setScrollEnabled(true); // Enable scrolling
// Set navigation buttons
menu->setNavigationButtons(0, 1); // UP=0, DOWN=1
// Set button styles
menu->setButtonStyle(
pixelroot32::graphics::Color::White, // selected text
pixelroot32::graphics::Color::Cyan, // selected background
pixelroot32::graphics::Color::White, // unselected text
pixelroot32::graphics::Color::Black // unselected background
);
// Add buttons (no manual positioning needed!)
for (int i = 0; i < 10; i++) {
UIButton* btn = new UIButton(
"Option " + std::to_string(i),
i,
0, 0, // Position ignored - layout handles it
200, 20,
[i]() { handleOption(i); }
);
menu->addElement(btn);
}
// Add layout to scene
menu->setRenderLayer(2); // UI layer
addEntity(menu);
UIHorizontalLayout¶
Organize elements horizontally:
#include <graphics/ui/UIHorizontalLayout.h>
// Create horizontal layout (menu bar)
pixelroot32::graphics::ui::UIHorizontalLayout* menuBar = new pixelroot32::graphics::ui::UIHorizontalLayout(
0, // x
0, // y
240, // width
30 // height
);
menuBar->setPadding(5);
menuBar->setSpacing(4);
menuBar->setScrollEnabled(true);
menuBar->setNavigationButtons(2, 3); // LEFT=2, RIGHT=3
// Add menu items
menuBar->addElement(new UIButton("File", 0, 0, 0, 60, 20, []() {}));
menuBar->addElement(new UIButton("Edit", 1, 0, 0, 60, 20, []() {}));
menuBar->addElement(new UIButton("View", 2, 0, 0, 60, 20, []() {}));
addEntity(menuBar);
UIGridLayout¶
Organize elements in a grid (matrix):
#include <graphics/ui/UIGridLayout.h>
// Create grid layout (inventory)
pixelroot32::graphics::ui::UIGridLayout* inventory = new pixelroot32::graphics::ui::UIGridLayout(
10, // x
60, // y
220, // width
160 // height
);
inventory->setColumns(4); // 4 columns
inventory->setPadding(5);
inventory->setSpacing(4);
inventory->setNavigationButtons(0, 1, 2, 3); // UP, DOWN, LEFT, RIGHT
// Add items (automatically arranged in grid)
for (int i = 0; i < 16; i++) {
UIButton* item = new UIButton(
"Item " + std::to_string(i),
i,
0, 0, // Position ignored
50, 50,
[i]() { useItem(i); }
);
inventory->addElement(item);
}
addEntity(inventory);
UIAnchorLayout¶
Position elements at fixed screen positions (perfect for HUDs):
#include <graphics/ui/UIAnchorLayout.h>
// Create anchor layout for HUD
pixelroot32::graphics::ui::UIAnchorLayout* hud = new pixelroot32::graphics::ui::UIAnchorLayout(
0, // x
0, // y
240, // screen width
240 // screen height
);
hud->setScreenSize(240, 240);
// Add HUD elements at different anchor points
UILabel* scoreLabel = new UILabel("Score: 0", 0, 0, Color::White, 1);
UILabel* livesLabel = new UILabel("Lives: 3", 0, 0, Color::White, 1);
hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);
hud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);
addEntity(hud);
Available Anchors: - TOP_LEFT, TOP_RIGHT, TOP_CENTER - BOTTOM_LEFT, BOTTOM_RIGHT, BOTTOM_CENTER - LEFT_CENTER, RIGHT_CENTER - CENTER
UIPaddingContainer¶
Add padding around a single element:
#include <graphics/ui/UIPaddingContainer.h>
// Create padding container
pixelroot32::graphics::ui::UIPaddingContainer* container = new pixelroot32::graphics::ui::UIPaddingContainer(
10, // x
10, // y
200, // width
100 // height
);
// Set uniform padding
container->setPadding(10);
// Or set asymmetric padding
container->setPadding(5, 15, 10, 10); // left, right, top, bottom
// Add child element
container->setChild(button);
addEntity(container);
Navigation¶
Layouts handle D-pad navigation automatically:
Vertical Navigation¶
verticalLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN);
// Layout automatically:
// - Highlights selected button
// - Scrolls to keep selected button visible
// - Handles wrapping (optional)
Horizontal Navigation¶
Grid Navigation¶
gridLayout->setNavigationButtons(Buttons::UP, Buttons::DOWN, Buttons::LEFT, Buttons::RIGHT);
// Layout automatically:
// - Handles 4-direction navigation
// - Wraps around edges
// - Updates selection
Manual Selection¶
// Set selected element programmatically
layout->setSelectedIndex(2);
// Get selected element
int selected = layout->getSelectedIndex();
UIElement* element = layout->getSelectedElement();
Complete Example: Main Menu¶
#include <core/Scene.h>
#include <graphics/ui/UIVerticalLayout.h>
#include <graphics/ui/UIButton.h>
#include <graphics/ui/UILabel.h>
#include <graphics/ui/UIPanel.h>
class MainMenuScene : public pixelroot32::core::Scene {
private:
pixelroot32::graphics::ui::UIVerticalLayout* menuLayout;
pixelroot32::graphics::ui::UIPanel* menuPanel;
public:
void init() override {
// Create panel
menuPanel = new pixelroot32::graphics::ui::UIPanel(40, 40, 160, 160);
menuPanel->setBackgroundColor(pixelroot32::graphics::Color::Black);
menuPanel->setBorderColor(pixelroot32::graphics::Color::White);
menuPanel->setBorderWidth(2);
menuPanel->setRenderLayer(2);
addEntity(menuPanel);
// Create layout inside panel
menuLayout = new pixelroot32::graphics::ui::UIVerticalLayout(0, 0, 160, 160);
menuLayout->setPadding(10);
menuLayout->setSpacing(8);
menuLayout->setNavigationButtons(0, 1);
menuLayout->setButtonStyle(
pixelroot32::graphics::Color::White,
pixelroot32::graphics::Color::Cyan,
pixelroot32::graphics::Color::White,
pixelroot32::graphics::Color::Black
);
// Add title
pixelroot32::graphics::ui::UILabel* title = new pixelroot32::graphics::ui::UILabel(
"GAME MENU", 0, 0, pixelroot32::graphics::Color::Yellow, 2
);
menuLayout->addElement(title);
// Add menu buttons
menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
"Start Game", 0, 0, 0, 140, 25, []() { startGame(); }
));
menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
"Options", 1, 0, 0, 140, 25, []() { showOptions(); }
));
menuLayout->addElement(new pixelroot32::graphics::ui::UIButton(
"Quit", 2, 0, 0, 140, 25, []() { quitGame(); }
));
menuPanel->setChild(menuLayout);
}
void update(unsigned long deltaTime) override {
// Handle input for layout navigation
auto& input = engine.getInputManager();
menuLayout->handleInput(input);
Scene::update(deltaTime);
}
void draw(pixelroot32::graphics::Renderer& renderer) override {
Scene::draw(renderer);
}
};
Complete Example: HUD¶
class GameHUD : public pixelroot32::core::Entity {
private:
pixelroot32::graphics::ui::UIAnchorLayout* hud;
pixelroot32::graphics::ui::UILabel* scoreLabel;
pixelroot32::graphics::ui::UILabel* livesLabel;
pixelroot32::graphics::ui::UILabel* healthLabel;
public:
GameHUD()
: Entity(0, 0, 240, 240, pixelroot32::core::EntityType::UI_ELEMENT) {
setRenderLayer(2); // UI layer
// Create HUD layout
hud = new pixelroot32::graphics::ui::UIAnchorLayout(0, 0, 240, 240);
hud->setScreenSize(240, 240);
// Create labels
scoreLabel = new pixelroot32::graphics::ui::UILabel(
"Score: 0", 0, 0, pixelroot32::graphics::Color::White, 1
);
livesLabel = new pixelroot32::graphics::ui::UILabel(
"Lives: 3", 0, 0, pixelroot32::graphics::Color::White, 1
);
healthLabel = new pixelroot32::graphics::ui::UILabel(
"Health: 100%", 0, 0, pixelroot32::graphics::Color::Green, 1
);
// Position labels
hud->addElement(scoreLabel, pixelroot32::graphics::ui::Anchor::TOP_LEFT);
hud->addElement(livesLabel, pixelroot32::graphics::ui::Anchor::TOP_RIGHT);
hud->addElement(healthLabel, pixelroot32::graphics::ui::Anchor::BOTTOM_CENTER);
}
void update(unsigned long deltaTime) override {
// Update HUD text (example)
char buffer[32];
snprintf(buffer, sizeof(buffer), "Score: %d", currentScore);
scoreLabel->setText(buffer);
}
void draw(pixelroot32::graphics::Renderer& renderer) override {
// HUD draws itself through its layout
}
// Add HUD to scene
void addToScene(Scene* scene) {
scene->addEntity(hud);
}
};
Best Practices¶
Organization¶
- Use render layer 2: Keep all UI on the top layer
- Group related elements: Use panels to group menu items
- Separate HUD from menus: Use different layouts for different UI types
- Reuse layouts: Create layout factories for common patterns
Performance¶
- Layouts use viewport culling: Only visible elements are rendered
- Minimize text updates: Updating text has overhead
- Use appropriate layouts: Choose the right layout for your needs
- Limit element count: Too many elements can impact performance
Navigation¶
- Set navigation buttons: Configure D-pad navigation for layouts
- Handle input in update(): Check for button presses to trigger actions
- Provide visual feedback: Selected buttons should be clearly visible
- Test navigation flow: Ensure navigation feels responsive
Common Patterns¶
Menu System¶
class MenuSystem {
UIVerticalLayout* currentMenu;
public:
void showMainMenu() {
currentMenu = createMainMenu();
scene->addEntity(currentMenu);
}
void showPauseMenu() {
currentMenu = createPauseMenu();
scene->addEntity(currentMenu);
}
void hideMenu() {
if (currentMenu) {
scene->removeEntity(currentMenu);
currentMenu = nullptr;
}
}
};
Dynamic UI Updates¶
void updateHUD(int score, int lives, int health) {
char buffer[32];
snprintf(buffer, sizeof(buffer), "Score: %d", score);
scoreLabel->setText(buffer);
snprintf(buffer, sizeof(buffer), "Lives: %d", lives);
livesLabel->setText(buffer);
snprintf(buffer, sizeof(buffer), "Health: %d%%", health);
healthLabel->setText(buffer);
}
Next Steps¶
Now that you understand the UI system, you've completed the core game development topics. Continue with: - Advanced Graphics - Advanced sprite techniques - Camera and Scrolling - Create scrolling levels - Performance Tuning - Improve performance
See also: - API Reference - UIElement - API Reference - UIButton - API Reference - UI Layouts - Manual - UI Overview