add gamepad support to menus
This commit is contained in:
281
docs/UI_COMPONENTS.md
Normal file
281
docs/UI_COMPONENTS.md
Normal file
@@ -0,0 +1,281 @@
|
||||
# UI Components
|
||||
|
||||
This document describes the custom UI components available in the Skelly project.
|
||||
|
||||
## ValueStepper Component
|
||||
|
||||
### Overview
|
||||
|
||||
**ValueStepper** is a reusable UI control for stepping through discrete values with left/right arrow navigation. It provides an intuitive interface for selecting from predefined options and is particularly well-suited for game settings menus.
|
||||
|
||||
**Location**: `scenes/ui/components/ValueStepper.tscn` and `scenes/ui/components/ValueStepper.gd`
|
||||
|
||||
### Why ValueStepper Exists
|
||||
|
||||
Godot's built-in controls have limitations for discrete option selection:
|
||||
- **OptionButton**: Dropdown popups don't work well with gamepad navigation
|
||||
- **SpinBox**: Designed for numeric values, not text options
|
||||
- **HSlider**: Better for continuous values, not discrete choices
|
||||
|
||||
ValueStepper fills this gap by providing:
|
||||
- ✅ **Gamepad-friendly** discrete option selection
|
||||
- ✅ **No popup complications** - values displayed inline
|
||||
- ✅ **Dual input support** - mouse clicks + keyboard/gamepad
|
||||
- ✅ **Clean horizontal layout** with current value always visible
|
||||
- ✅ **Perfect for game settings** like language, difficulty, resolution
|
||||
|
||||
### Features
|
||||
|
||||
- **Multiple Data Sources**: Built-in support for language, resolution, difficulty
|
||||
- **Custom Values**: Easy setup with custom arrays of values
|
||||
- **Navigation Integration**: Built-in highlighting and input handling
|
||||
- **Signal-Based**: Clean event communication with parent scenes
|
||||
- **Visual Feedback**: Automatic highlighting and animations
|
||||
- **Audio Support**: Integrated click sounds
|
||||
- **Flexible Display**: Separate display names and internal values
|
||||
|
||||
### Visual Structure
|
||||
|
||||
```
|
||||
[<] [Current Value] [>]
|
||||
```
|
||||
|
||||
- **Left Arrow Button** (`<`): Navigate to previous value
|
||||
- **Value Display**: Shows current selection (e.g., "English", "Hard", "1920×1080")
|
||||
- **Right Arrow Button** (`>`): Navigate to next value
|
||||
|
||||
## API Reference
|
||||
|
||||
### Signals
|
||||
|
||||
```gdscript
|
||||
signal value_changed(new_value: String, new_index: int)
|
||||
```
|
||||
Emitted when the value changes, providing both the new value string and its index.
|
||||
|
||||
### Properties
|
||||
|
||||
```gdscript
|
||||
@export var data_source: String = "language"
|
||||
@export var custom_format_function: String = ""
|
||||
```
|
||||
|
||||
- **data_source**: Determines the data type ("language", "resolution", "difficulty", or "custom")
|
||||
- **custom_format_function**: Reserved for future custom formatting (currently unused)
|
||||
|
||||
### Key Methods
|
||||
|
||||
#### Setup and Configuration
|
||||
```gdscript
|
||||
func setup_custom_values(custom_values: Array[String], custom_display_names: Array[String] = [])
|
||||
```
|
||||
Configure the stepper with custom values and optional display names.
|
||||
|
||||
#### Value Management
|
||||
```gdscript
|
||||
func get_current_value() -> String
|
||||
func set_current_value(value: String)
|
||||
func change_value(direction: int)
|
||||
```
|
||||
Get, set, or modify the current value programmatically.
|
||||
|
||||
#### Navigation Integration
|
||||
```gdscript
|
||||
func set_highlighted(highlighted: bool)
|
||||
func handle_input_action(action: String) -> bool
|
||||
func get_control_name() -> String
|
||||
```
|
||||
Integration methods for navigation systems and visual feedback.
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Basic Usage in Scene
|
||||
|
||||
1. **Add to Scene**: Instance `ValueStepper.tscn` in your scene
|
||||
2. **Set Data Source**: Configure the `data_source` property
|
||||
3. **Connect Signal**: Connect the `value_changed` signal
|
||||
|
||||
```gdscript
|
||||
# In your scene script
|
||||
@onready var language_stepper: ValueStepper = $LanguageStepper
|
||||
|
||||
func _ready():
|
||||
language_stepper.value_changed.connect(_on_language_changed)
|
||||
|
||||
func _on_language_changed(new_value: String, new_index: int):
|
||||
print("Language changed to: ", new_value)
|
||||
```
|
||||
|
||||
### Built-in Data Sources
|
||||
|
||||
#### Language Selection
|
||||
```gdscript
|
||||
# Set data_source = "language" in editor or code
|
||||
language_stepper.data_source = "language"
|
||||
```
|
||||
Automatically loads available languages from SettingsManager.
|
||||
|
||||
#### Resolution Selection
|
||||
```gdscript
|
||||
# Set data_source = "resolution"
|
||||
resolution_stepper.data_source = "resolution"
|
||||
```
|
||||
Provides common resolution options with display names.
|
||||
|
||||
#### Difficulty Selection
|
||||
```gdscript
|
||||
# Set data_source = "difficulty"
|
||||
difficulty_stepper.data_source = "difficulty"
|
||||
```
|
||||
Provides difficulty levels: Easy, Normal, Hard, Nightmare.
|
||||
|
||||
### Custom Values
|
||||
|
||||
```gdscript
|
||||
# Setup custom theme selector
|
||||
var theme_values = ["light", "dark", "blue", "green"]
|
||||
var theme_names = ["Light Theme", "Dark Theme", "Blue Theme", "Green Theme"]
|
||||
theme_stepper.setup_custom_values(theme_values, theme_names)
|
||||
theme_stepper.data_source = "theme" # For better logging
|
||||
```
|
||||
|
||||
### Navigation System Integration
|
||||
|
||||
```gdscript
|
||||
# In a navigation-enabled menu
|
||||
var navigable_controls: Array[Control] = []
|
||||
|
||||
func _setup_navigation():
|
||||
navigable_controls.append(volume_slider)
|
||||
navigable_controls.append(language_stepper) # Add stepper to navigation
|
||||
navigable_controls.append(back_button)
|
||||
|
||||
func _update_visual_selection():
|
||||
for i in range(navigable_controls.size()):
|
||||
var control = navigable_controls[i]
|
||||
if control is ValueStepper:
|
||||
control.set_highlighted(i == current_index)
|
||||
else:
|
||||
# Handle other control highlighting
|
||||
pass
|
||||
|
||||
func _handle_input(action: String):
|
||||
var current_control = navigable_controls[current_index]
|
||||
if current_control is ValueStepper:
|
||||
if current_control.handle_input_action(action):
|
||||
AudioManager.play_ui_click()
|
||||
return true
|
||||
return false
|
||||
```
|
||||
|
||||
## Integration Patterns
|
||||
|
||||
### Settings Menu Pattern
|
||||
See `scenes/ui/SettingsMenu.gd` for a complete example of integrating ValueStepper into a settings menu with full navigation support.
|
||||
|
||||
### Multiple Steppers Navigation
|
||||
See `examples/ValueStepperExample.gd` for an example showing multiple steppers with keyboard/gamepad navigation.
|
||||
|
||||
## Extending ValueStepper
|
||||
|
||||
### Adding New Data Sources
|
||||
|
||||
1. **Add to `_load_data()` method**:
|
||||
```gdscript
|
||||
func _load_data():
|
||||
match data_source:
|
||||
"language":
|
||||
_load_language_data()
|
||||
"your_custom_type":
|
||||
_load_your_custom_data()
|
||||
# ... other cases
|
||||
```
|
||||
|
||||
2. **Implement your loader**:
|
||||
```gdscript
|
||||
func _load_your_custom_data():
|
||||
values = ["value1", "value2", "value3"]
|
||||
display_names = ["Display 1", "Display 2", "Display 3"]
|
||||
current_index = 0
|
||||
```
|
||||
|
||||
3. **Add value application logic**:
|
||||
```gdscript
|
||||
func _apply_value_change(new_value: String, index: int):
|
||||
match data_source:
|
||||
"your_custom_type":
|
||||
# Apply your custom logic here
|
||||
YourManager.set_custom_setting(new_value)
|
||||
```
|
||||
|
||||
### Custom Formatting
|
||||
|
||||
Override `_update_display()` for custom display formatting:
|
||||
|
||||
```gdscript
|
||||
func _update_display():
|
||||
if data_source == "your_custom_type":
|
||||
# Custom formatting logic
|
||||
value_display.text = "Custom: " + display_names[current_index]
|
||||
else:
|
||||
super._update_display() # Call parent implementation
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
### When to Use ValueStepper
|
||||
- ✅ **Discrete options**: Language, difficulty, resolution, theme
|
||||
- ✅ **Settings menus**: Any option with predefined choices
|
||||
- ✅ **Game configuration**: Graphics quality, control schemes
|
||||
- ✅ **Limited options**: 2-10 options work best
|
||||
|
||||
### When NOT to Use ValueStepper
|
||||
- ❌ **Continuous values**: Use sliders for volume, brightness
|
||||
- ❌ **Large lists**: Use ItemList or OptionButton for 20+ items
|
||||
- ❌ **Text input**: Use LineEdit for user-entered text
|
||||
- ❌ **Numeric input**: Use SpinBox for number entry
|
||||
|
||||
### Performance Considerations
|
||||
- ValueStepper is lightweight and suitable for multiple instances
|
||||
- Data loading happens once in `_ready()`
|
||||
- Visual updates are minimal (just text changes)
|
||||
|
||||
### Accessibility
|
||||
- Visual highlighting provides clear focus indication
|
||||
- Audio feedback confirms user actions
|
||||
- Keyboard and gamepad support for non-mouse users
|
||||
- Consistent navigation patterns
|
||||
|
||||
## Common Issues and Solutions
|
||||
|
||||
### Stepper Not Responding to Input
|
||||
- Ensure `handle_input_action()` is called from parent's `_input()`
|
||||
- Check that the stepper has proper focus/highlighting
|
||||
- Verify input actions are defined in project input map
|
||||
|
||||
### Values Not Saving
|
||||
- Override `_apply_value_change()` to handle persistence
|
||||
- Connect to `value_changed` signal for custom save logic
|
||||
- Ensure SettingsManager or your data manager is configured
|
||||
|
||||
### Display Names Not Showing
|
||||
- Check that `display_names` array is properly populated
|
||||
- Ensure `display_names.size()` matches `values.size()`
|
||||
- Verify `_update_display()` is called after data loading
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
scenes/ui/components/
|
||||
├── ValueStepper.gd # Main component script
|
||||
└── ValueStepper.tscn # Component scene
|
||||
|
||||
examples/
|
||||
├── ValueStepperExample.gd # Usage example script
|
||||
└── ValueStepperExample.tscn # Example scene
|
||||
|
||||
docs/
|
||||
└── UI_COMPONENTS.md # This documentation
|
||||
```
|
||||
|
||||
This component provides a solid foundation for any game's settings system and can be easily extended for project-specific needs.
|
||||
Reference in New Issue
Block a user