UI Templates and Setup (v5.0)
v5.0 provides a comprehensive set of UI templates for building interfaces, selection systems, and user feedback. This guide covers template setup, customization, and integration using the drag-and-drop editor first approach.
For a complete setup overview, see Getting Started Setup.
Editor-First Approach
🎯 Primary Method: Drag and drop .tscn scenes directly into your game’s HUD/UI stack, then configure settings in the Inspector rather than through script.
Benefits of Editor-First Approach:
- Visual Layout: See UI placement in real-time
- Inspector Configuration: All settings available in the Inspector
- No Script Dependencies: UI works without additional code
- Easy Iteration: Adjust properties without recompiling
- Scene Tree Integration: Natural Godot workflow
Template Overview
UI templates are located in /templates/ui/ and provide pre-built components for common building interface needs.
Core UI Templates
- placeable_selection_ui.tscn - Building selection interface
- action_bar.tscn - Main action buttons and controls
- action_log.tscn - Message and feedback display
- target_informer.tscn - Target information display
- camera_zoom_slider.tscn - Camera zoom controls
Placeable Selection UI
Template Structure
PlaceableSelectionUI (Control)
├── CategoryTabs (TabContainer)
│ ├── Buildings (ScrollContainer)
│ ├── Decorations (ScrollContainer)
│ └── Units (ScrollContainer)
├── ItemGrid (GridContainer)
├── PreviewPanel (Panel)
└── SearchBox (LineEdit)
Setup Instructions (Editor-First)
Drag and Drop Template
- Open your UI/HUD scene in the editor
- Drag
placeable_selection_ui.tscn from the FileSystem dock into your scene tree - Position it within your UI hierarchy (typically under a CanvasLayer or Control node)
Configure in Inspector
Connect to Building System (Optional)
Adjust Visual Properties
- Use the Inspector to modify colors, sizes, and layouts
- Adjust anchors and margins for proper screen positioning
- Configure theme overrides for custom styling
Script Alternative (Advanced Only):
1
2
3
4
| # Only use if you need dynamic UI creation
var selection_ui = preload("res:///templates/ui/placement_selection/placeable_selection_ui.tscn").instantiate()
$UI/HUD.add_child(selection_ui)
# Configure properties as shown above
|
Other UI Templates
Action Bar
Editor Setup:
- Drag
action_bar.tscn into your UI scene - Configure button actions in the Inspector:
build_confirm_action: "build_confirm"
build_cancel_action: "build_cancel"
rotate_left_action: "rotate_left"
rotate_right_action: "rotate_right"
Action Log
Editor Setup:
- Drag
action_log.tscn into your UI scene - Configure display settings:
max_messages: 50
auto_clear_time: 5.0
show_timestamps: true
Editor Setup:
- Drag
target_informer.tscn into your UI scene - Position near cursor or game area
- Configure display format in Inspector
Camera Zoom Slider
Editor Setup:
- Drag
camera_zoom_slider.tscn into your UI scene - Configure zoom limits:
min_zoom: 0.5
max_zoom: 3.0
zoom_step: 0.1
Editor-First Best Practices
Visual Layout
- Use the Scene Tree: Drag and drop to organize UI hierarchy
- Live Preview: See changes immediately in the 2D editor
- Anchor System: Use anchors for responsive design
- Theme Integration: Apply custom themes via the Inspector
Configuration Workflow
- Instance Template: Drag
.tscn file into scene - Select Node: Click the instanced UI node
- Configure Properties: Use the Inspector for all settings
- Test Layout: Run scene to verify positioning
- Iterate: Adjust properties without code changes
Property Assignment
- Drag References: Assign system nodes by dragging from Scene Tree
- Resource Assignment: Load resources via the Inspector
- Path Configuration: Use NodePath properties for scene references
- Export Variables: All important properties are exported for Inspector access
Customization Options
Category Configuration
Editor Method:
- Create category files in your categories folder
- Configure folder paths in the Inspector
- Templates auto-load categories based on folder structure
File Structure:
res://your_game/categories/
├── buildings.json
├── decorations.json
└── units.json
{
“name”: “Buildings”,
“icon”: “res://icons/buildings.png”,
“description”: “Structures and buildings”,
“tags”: [“structure”, “building”]
}
#### Placeable Resources
```gdscript
# Create placeable resources
extends PlaceableResource
@export var scene: PackedScene
@export var cost: Dictionary = {"wood": 10, "stone": 5}
@export var description: String = "A basic building"
@export var icon: Texture2D
Action Bar
Template Structure
ActionBar (HBoxContainer)
├── BuildModeButton (Button)
├── ManipulateModeButton (Button)
├── DeleteModeButton (Button)
├── Separator (VSeparator)
├── UndoButton (Button)
├── RedoButton (Button)
└── SettingsButton (Button)
Setup and Configuration
1
2
3
4
5
6
7
8
9
10
11
| # Instance and configure action bar
var action_bar = preload("res:///templates/ui/action_bar.tscn").instantiate()
$UI/HUD.add_child(action_bar)
# Connect to systems
action_bar.building_system = $Systems/BuildingSystem
action_bar.manipulation_system = $Systems/ManipulationSystem
# Customize button actions
action_bar.build_mode_button.pressed.connect(_on_build_mode_pressed)
action_bar.delete_mode_button.pressed.connect(_on_delete_mode_pressed)
|
1
2
3
4
5
6
7
| func _on_build_mode_pressed():
var building_system = $Systems/BuildingSystem
building_system.set_mode(BuildingSystem.Mode.BUILD)
func _on_delete_mode_pressed():
var manipulation_system = $Systems/ManipulationSystem
manipulation_system.set_mode(ManipulationSystem.Mode.DELETE)
|
Action Log
Template Structure
GBActionLog (PanelContainer)
├── ScrollContainer (ScrollContainer)
│ └── MessageList (VBoxContainer)
└── Header (HBoxContainer)
├── TitleLabel (Label)
└── ClearButton (Button)
Configuration
1
2
3
4
5
6
7
8
9
10
11
12
| # Setup action log
var action_log = preload("res:///templates/ui/action_log/action_log.tscn").instantiate()
$UI/HUD.add_child(action_log)
# Configure log settings
action_log.max_messages = 50
action_log.message_duration = 5.0
action_log.show_timestamps = true
# Connect to event bus
var event_bus = composition_container.get_event_bus()
event_bus.message_logged.connect(action_log.add_message)
|
Custom Message Types
1
2
3
4
| # Add custom message styling
action_log.add_message("Building placed", Color.GREEN, "building")
action_log.add_message("Error: Invalid placement", Color.RED, "error")
action_log.add_message("Info: Grid mode activated", Color.BLUE, "info")
|
Template Structure
TargetInformer (Panel)
├── Icon (TextureRect)
├── TitleLabel (Label)
├── DescriptionLabel (Label)
└── CostLabel (Label)
Setup
1
2
3
4
5
6
7
| # Setup target informer
var target_informer = preload("res:///templates/ui/target_informer.tscn").instantiate()
$UI/HUD.add_child(target_informer)
# Connect to targeting system
var targeting_system = $Systems/GridTargetingSystem
targeting_system.target_changed.connect(target_informer.update_target_info)
|
1
2
3
4
5
6
| # Update target information
func update_target_info(target_data: TargetData):
$Icon.texture = target_data.icon
$TitleLabel.text = target_data.name
$DescriptionLabel.text = target_data.description
$CostLabel.text = format_cost(target_data.cost)
|
Camera Controls
Zoom Slider Setup
1
2
3
4
5
6
7
8
9
| # Setup camera zoom controls
var zoom_slider = preload("res:///templates/ui/camera_zoom_slider.tscn").instantiate()
$UI/HUD.add_child(zoom_slider)
# Connect to camera
var camera = $World/Camera2D
zoom_slider.min_zoom = 0.5
zoom_slider.max_zoom = 3.0
zoom_slider.value_changed.connect(camera.set_zoom)
|
Custom Camera Controls
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| # Add custom camera controls
func setup_camera_controls():
var camera = $World/Camera2D
# Pan controls
InputEventPan.connect(_on_camera_pan)
# Zoom controls
InputEventZoom.connect(_on_camera_zoom)
func _on_camera_pan(direction: Vector2):
camera.position += direction * pan_speed
func _on_camera_zoom(delta: float):
var new_zoom = camera.zoom.x + delta
camera.zoom = Vector2(new_zoom, new_zoom)
|
Custom UI Components
Creating Custom Templates
- Copy Existing Template
1
2
| # Duplicate an existing template
# Modify as needed for your game
|
- Extend Base Classes
1
2
3
4
5
6
7
8
9
10
11
| # Custom selection UI
extends PlaceableSelectionUI
func _ready():
super._ready()
# Add custom initialization
setup_custom_features()
func setup_custom_features():
# Add custom tabs, filters, etc.
pass
|
Custom Placeable Cards
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| # Custom placeable card UI
extends Control
@export var placeable_resource: PlaceableResource
@onready var icon: TextureRect = $Icon
@onready var name_label: Label = $NameLabel
@onready var cost_label: Label = $CostLabel
func setup(placeable: PlaceableResource):
placeable_resource = placeable
icon.texture = placeable.icon
name_label.text = placeable.name
cost_label.text = format_cost(placeable.cost)
func _on_pressed():
# Handle selection
BuildingSystem.select_placeable(placeable_resource)
|
Integration Patterns
Complete UI Setup
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| # Complete UI setup for a building game
func setup_building_ui():
var hud = $UI/HUD
# Add core components
var selection_ui = create_selection_ui()
var action_bar = create_action_bar()
var action_log = create_action_log()
var target_informer = create_target_informer()
# Position components
selection_ui.anchors_preset = PRESET_TOP_RIGHT
action_bar.anchors_preset = PRESET_BOTTOM_WIDE
action_log.anchors_preset = PRESET_BOTTOM_RIGHT
target_informer.anchors_preset = PRESET_TOP_CENTER
# Connect systems
connect_ui_to_systems()
|
Responsive UI Layout
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Responsive UI that adapts to screen size
func setup_responsive_ui():
var screen_size = get_viewport().get_visible_rect().size
if screen_size.x < 1024: # Mobile
setup_mobile_layout()
elif screen_size.x < 1920: # Tablet
setup_tablet_layout()
else: # Desktop
setup_desktop_layout()
func setup_mobile_layout():
# Compact layout for mobile
$SelectionUI.scale = Vector2(0.8, 0.8)
$ActionBar.position = Vector2(0, screen_size.y - 100)
|
Theming and Styling
Custom Theme Setup
1
2
3
4
5
6
7
| # Apply custom theme to UI components
func apply_custom_theme():
var custom_theme = preload("res://themes/building_theme.tres")
$SelectionUI.theme = custom_theme
$ActionBar.theme = custom_theme
$ActionLog.theme = custom_theme
|
Theme Customization
1
2
3
4
5
6
7
8
9
10
11
| # Create custom theme variations
func create_theme_variants():
# Day theme
var day_theme = Theme.new()
day_theme.set_color("font_color", "Label", Color.BLACK)
day_theme.set_color("panel", "Panel", Color.WHITE)
# Night theme
var night_theme = Theme.new()
night_theme.set_color("font_color", "Label", Color.WHITE)
night_theme.set_color("panel", "Panel", Color.BLACK)
|
UI Pooling
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Pool UI elements for better performance
class UIElementPool:
var available_elements: Array[Control] = []
var active_elements: Array[Control] = []
func get_element() -> Control:
if available_elements.is_empty():
return create_new_element()
return available_elements.pop_back()
func return_element(element: Control):
element.visible = false
active_elements.erase(element)
available_elements.append(element)
|
Lazy Loading
1
2
3
4
5
6
7
| # Lazy load UI components
func lazy_load_ui():
# Only load UI when needed
if not ui_loaded:
load_selection_ui()
load_action_bar()
ui_loaded = true
|
Accessibility
Keyboard Navigation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Setup keyboard navigation
func setup_keyboard_navigation():
# Tab order
$SelectionUI.focus_next = $ActionBar
$ActionBar.focus_next = $ActionLog
# Keyboard shortcuts
set_process_input(true)
func _input(event):
if event.is_action_pressed("ui_accept"):
handle_confirm_action()
elif event.is_action_pressed("ui_cancel"):
handle_cancel_action()
|
Screen Reader Support
1
2
3
4
5
6
7
8
| # Add accessibility labels
func setup_accessibility():
$BuildModeButton.tooltip_text = "Enter build mode for placing structures"
$DeleteModeButton.tooltip_text = "Enter delete mode for removing objects"
# Add accessibility hints
$SelectionUI.set_accessibility_name("Building selection panel")
$SelectionUI.set_accessibility_hint("Choose from available buildings to place")
|
Testing and Debugging
UI Testing Framework
1
2
3
4
5
6
7
8
9
10
11
12
| # Test UI interactions
func test_selection_ui():
var selection_ui = $SelectionUI
# Test category switching
selection_ui.switch_to_category("Buildings")
assert(selection_ui.current_category == "Buildings")
# Test item selection
var first_item = selection_ui.get_first_placeable()
selection_ui.select_placeable(first_item)
assert(selection_ui.selected_placeable == first_item)
|
Debug Visualization
1
2
3
4
5
6
7
8
| # Debug UI layout
func _draw():
if debug_mode:
# Draw UI bounds
draw_ui_bounds()
# Draw interaction areas
draw_interaction_areas()
|
Best Practices
1. Consistent Design
- Use consistent spacing and sizing
- Follow established UI patterns
- Maintain visual hierarchy
- Pool expensive UI elements
- Use lazy loading for complex components
- Optimize for target frame rate
3. Accessibility First
- Include keyboard navigation
- Add proper tooltips and labels
- Support screen readers
4. Responsive Design
- Adapt to different screen sizes
- Support both mobile and desktop
- Test on various devices
Common Patterns
Modal Dialogs
1
2
3
4
5
6
| # Custom confirmation dialogs
func show_confirmation_dialog(title: String, message: String, callback: Callable):
var dialog = create_confirmation_dialog()
dialog.setup(title, message, callback)
add_child(dialog)
dialog.popup_centered()
|
1
2
3
4
5
| # Context-sensitive help
func setup_help_system():
var help_system = HelpSystem.new()
help_system.register_tooltip($BuildModeButton, "build_mode_help")
help_system.register_tooltip($DeleteModeButton, "delete_mode_help")
|
The UI template system provides a solid foundation for building interfaces while allowing extensive customization to match your game’s specific needs and visual style.