-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Directional navigation now considers UiTransform rotation #22399
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Directional navigation now considers UiTransform rotation #22399
Conversation
| } | ||
| } | ||
|
|
||
| fn get_rotated_bounds(size: Vec2, rotation: f32) -> Vec2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be better as a public helper method on UiTransform TBH :)
| border_radius: BorderRadius::all(px(12)), | ||
| ..default() | ||
| }, | ||
| // This is the key: just add this component for automatic navigation! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This comment is now misplaced.
alice-i-cecile
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The misplaced comment is blocking; everything else is bonus.
Fixed the comment misplacing and added a comment for the Transform line |
|
The merging of #22340 caused a conflict with your branch To resolve the conflict, I believe you just have to move the logic you edited in |
| ..default() | ||
| }, | ||
| // Apply a scale transform to demonstrate that navigation handles transforms | ||
| Transform::from_scale(Vec3::splat(2.0)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should be using UiTransform here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I tested your logic as follows (basically copying ickshonpe’s test case in the issue):
I replaced some code in the auto_directional_navigation example (between let button_positions… and the end of the for loop`). The main things changed are the UiTransform that I only apply to the center button, and the four buttons.
// Spawn buttons in a scattered/irregular pattern
// The auto-navigation system will figure out the connections!
let button_positions_and_dims = [
// Top left
(350.0, 100.0, 140, 80),
// Center. Will be scaled x2 and rotated PI/2 Radians
(550.0, 300.0, 240, 70),
// Bottom Left
(350.0, 500.0, 140, 80),
// Bottom Right
(750.0, 500.0, 140, 80),
];
let mut first_button = None;
for (i, (x, y, width, height)) in button_positions_and_dims().enumerate() {
let transform = if i == 1 {
UiTransform {
scale: Vec2::splat(2.0),
rotation: Rot2::FRAC_PI_2,
..default()
}
} else {
UiTransform::IDENTITY
};
let button_entity = commands
.spawn((
Button,
Node {
position_type: PositionType::Absolute,
left: px(*x),
top: px(*y),
width: px(*width),
height: px(*height),
border: UiRect::all(px(4)),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
border_radius: BorderRadius::all(px(12)),
..default()
},
// Apply the appropriate transform
transform,
// This is the key: just add this component for automatic navigation!
AutoDirectionalNavigation::default(),
ResetTimer::default(),
BackgroundColor::from(NORMAL_BUTTON),
Name::new(format!("Button {}", i + 1)),
))
.with_child((
Text::new(format!("Button {}", i + 1)),
TextLayout {
justify: Justify::Center,
..default()
},
))
.id();
if first_button.is_none() {
first_button = Some(button_entity);
}
}
commands.entity(root_node).add_children(&[instructions]);
// Set initial focus
if let Some(button) = first_button {
input_focus.set(button);
}
}Without the transform, it looks like this:

And navigation between the three non-center buttons works as expected.
With the transformation, it looks like this:

And navigation now works as I expect (the center button can now be navigated to by going left or right along the bottom row).
As far as editing the example for auto_directional_navigation.rs to show that this works, I personally think it can be a follow up, but you can use what I wrote as a guide to include something in this PR if you’d like. I’m not gonna click approve yet because the example now looks like this with the scaling!
# Objective Fixes #22234 The directional navigation system was ignoring `UiTransform` rotation and scaling when calculating which node to navigate to. This caused navigation to select incorrect nodes when they were rotated or scaled, because the system used unrotated layout positions instead of the visual positions seen by users. ## Solution - Added `get_rotated_bounds()` helper function to calculate the axis-aligned bounding box of a rotated rectangle - Updated `get_navigable_nodes()` to apply both rotation and scale transforms from `UiGlobalTransform` when creating `FocusableArea` structs - Updated `entity_to_camera_and_focusable_area()` to apply rotation and scale transforms - Used `bevy_math::ops` instead of `f32` methods for deterministic trigonometry The fix ensures that directional navigation uses the visual position of nodes (after transforms) rather than just the layout position, so users navigate to the button they actually see on screen. ## Testing - Tested with `auto_directional_navigation` example - navigation works correctly with scattered button layouts  --------- Co-authored-by: Carter Anderson <[email protected]>




Objective
Fixes #22234
The directional navigation system was ignoring
UiTransformrotation and scaling when calculating which node to navigate to. This caused navigation to select incorrect nodes when they were rotated or scaled, because the system used unrotated layout positions instead of the visual positions seen by users.Solution
get_rotated_bounds()helper function to calculate the axis-aligned bounding box of a rotated rectangleget_navigable_nodes()to apply both rotation and scale transforms fromUiGlobalTransformwhen creatingFocusableAreastructsentity_to_camera_and_focusable_area()to apply rotation and scale transformsbevy_math::opsinstead off32methods for deterministic trigonometryThe fix ensures that directional navigation uses the visual position of nodes (after transforms) rather than just the layout position, so users navigate to the button they actually see on screen.
Testing
auto_directional_navigationexample - navigation works correctly with scattered button layouts