Commit 0c90f04
authored
Add Automatic Directional Navigation Graph Generation (bevyengine#21668)
## Objective
Resolves bevyengine#21661
Adds automatic directional navigation graph generation based on UI node
positions and sizes, eliminating the need for tedious manual graph
construction in dynamic UIs.
## Solution
Implements a spatial navigation algorithm that automatically computes
the nearest neighbor in each compass direction for UI elements, while
respecting any manually-defined edges.
### Features
- **Automatic edge generation**: Finds the best neighbor in each of 8
compass directions based on distance, alignment, and overlap
- **Manual override support**: Manual edges always take precedence over
auto-generated ones
- **Configurable**: `AutoNavigationConfig` resource allows tuning
alignment requirements, distance limits, and preference weighting
- **Opt-in**: Entities must have `AutoDirectionalNavigation` component
added to use, and therefore **not** a breaking change
- **Generic**: Core algorithm works with any `Vec2` position/size data,
not just `bevy_ui`
### Implementation
**New Components & Resources**
(`bevy_input_focus/src/directional_navigation.rs`):
- `AutoDirectionalNavigation` - Marker component to enable
auto-navigation
- `AutoNavigationConfig` - Configuration resource with settings:
- `min_alignment_factor`: Minimum perpendicular overlap (0.0-1.0)
required for cardinal directions
- `max_search_distance`: Optional distance limit for connections
- `prefer_aligned`: Whether to strongly prefer well-aligned nodes
**Core Algorithm**:
```rust
pub fn auto_generate_navigation_edges(
nav_map: &mut DirectionalNavigationMap,
nodes: &[(Entity, Vec2, Vec2)], // (entity, center_pos, size)
config: &AutoNavigationConfig,
)
```
For each node and each direction:
1. Filter candidates that are actually in that direction (cone-based
check)
2. Calculate overlap factor for cardinal directions (horizontal overlap
for N/S, vertical for E/W)
3. Score candidates based on:
- Distance (closer is better)
- Alignment with direction vector (more aligned is better)
- Overlap factor (must meet minimum threshold)
4. Select the best-scoring candidate as the neighbor
**Scoring Formula**:
```
score = distance + alignment_penalty
where alignment_penalty = (1.0 - alignment) * distance * 2.0
```
This makes misaligned nodes significantly less attractive while still
considering distance.
### Usage
**Before (manual)**:
```rust
// Must manually specify all connections
for row in 0..N_ROWS {
let entities_in_row: Vec<Entity> = (0..N_COLS)
.map(|col| button_entities.get(&(row, col)).unwrap())
.copied()
.collect();
directional_nav_map.add_looping_edges(&entities_in_row, CompassOctant::East);
}
// Repeat for columns...
for col in 0..N_COLS {
let entities_in_column: Vec<Entity> = (0..N_ROWS)
.map(|row| button_entities.get(&(row, col)).unwrap())
.copied()
.collect();
directional_nav_map.add_edges(&entities_in_column, CompassOctant::South);
}
```
**After**:
```rust
// Just add the `AutoDirectionalNavigation` component!
commands.spawn((
Button,
Node { /* ... */ },
AutoDirectionalNavigation::default(),
// ... other components
));
```
## Testing
- Added new example: `auto_directional_navigation`
- Ran existing `directional_navigation`
## Showcase
### New Example: `auto_directional_navigation`
Demonstrates automatic navigation with irregularly-positioned buttons.
Unlike a regular grid, these buttons are scattered, but auto-navigation
figures out the correct connections - also shows currently focused
button, and the last "input" pressed to show the logical flow of
navigating:
```bash
cargo run --example auto_directional_navigation
```
https://github.com/user-attachments/assets/8dce1d8d-53b5-41b8-bc9a-7e32067f7978
**Key differences from manual `directional_navigation` example**:
- No manual `add_edges()` or `add_looping_edges()` calls
- Buttons positioned irregularly (not in a perfect grid)
- Works with absolute positioning and dynamic layouts
## Migration Guide
No breaking changes - this is a purely additive feature.
To adopt automatic navigation:
1. Add `AutoDirectionalNavigation` component to focusable entities
2. Optionally configure `AutoNavigationConfig` resource1 parent 2facb25 commit 0c90f04
File tree
8 files changed
+1385
-5
lines changed- crates
- bevy_input_focus
- src
- bevy_math/src
- examples
- ui
- release-content/release-notes
8 files changed
+1385
-5
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4704 | 4704 | | |
4705 | 4705 | | |
4706 | 4706 | | |
| 4707 | + | |
| 4708 | + | |
| 4709 | + | |
| 4710 | + | |
| 4711 | + | |
| 4712 | + | |
| 4713 | + | |
| 4714 | + | |
| 4715 | + | |
| 4716 | + | |
| 4717 | + | |
4707 | 4718 | | |
4708 | 4719 | | |
4709 | 4720 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| 64 | + | |
64 | 65 | | |
65 | 66 | | |
66 | 67 | | |
67 | 68 | | |
| 69 | + | |
68 | 70 | | |
69 | 71 | | |
70 | 72 | | |
| |||
0 commit comments