Skip to content

Commit cf9e665

Browse files
committed
fix: considers camera targets during directional navigation
1 parent f3bc1ec commit cf9e665

File tree

1 file changed

+63
-33
lines changed

1 file changed

+63
-33
lines changed

crates/bevy_input_focus/src/directional_navigation.rs

Lines changed: 63 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ use bevy_ecs::{
6767
system::SystemParam,
6868
};
6969
use bevy_math::{CompassOctant, Dir2, Vec2};
70-
use bevy_ui::{ComputedNode, UiGlobalTransform};
70+
use bevy_ui::{ComputedNode, ComputedUiTargetCamera, UiGlobalTransform};
7171
use thiserror::Error;
7272

7373
use crate::InputFocus;
@@ -418,17 +418,23 @@ pub struct DirectionalNavigation<'w, 's> {
418418
's,
419419
(
420420
Entity,
421+
&'static ComputedUiTargetCamera,
421422
&'static ComputedNode,
422423
&'static UiGlobalTransform,
423424
&'static InheritedVisibility,
424425
),
425426
With<AutoDirectionalNavigation>,
426427
>,
427-
/// A query used to get the [`FocusableArea`] for a given entity to be used in automatic navigation.
428-
focusable_area_query: Query<
428+
/// A query used to get the target camera and the [`FocusableArea`] for a given entity to be used in automatic navigation.
429+
camera_and_focusable_area_query: Query<
429430
'w,
430431
's,
431-
(Entity, &'static ComputedNode, &'static UiGlobalTransform),
432+
(
433+
Entity,
434+
&'static ComputedUiTargetCamera,
435+
&'static ComputedNode,
436+
&'static UiGlobalTransform,
437+
),
432438
With<AutoDirectionalNavigation>,
433439
>,
434440
}
@@ -449,11 +455,12 @@ impl<'w, 's> DirectionalNavigation<'w, 's> {
449455
if let Some(new_focus) = self.map.get_neighbor(current_focus, direction) {
450456
self.focus.set(new_focus);
451457
Ok(new_focus)
452-
} else if let Some(origin) = self.entity_to_focusable_area(current_focus)
458+
} else if let Some((target_camera, origin)) =
459+
self.entity_to_camera_and_focusable_area(current_focus)
453460
&& let Some(new_focus) = find_best_candidate(
454461
&origin,
455462
direction,
456-
&self.get_navigable_nodes(),
463+
&self.get_navigable_nodes(target_camera),
457464
&self.config,
458465
)
459466
{
@@ -471,39 +478,62 @@ impl<'w, 's> DirectionalNavigation<'w, 's> {
471478
}
472479

473480
/// Returns a vec of [`FocusableArea`] representing nodes that are eligible to be automatically navigated to.
474-
fn get_navigable_nodes(&self) -> Vec<FocusableArea> {
481+
/// The camera of any navigable nodes will equal the desired `target_camera`.
482+
fn get_navigable_nodes(&self, target_camera: Entity) -> Vec<FocusableArea> {
475483
self.navigable_entities_query
476484
.iter()
477-
.filter_map(|(entity, computed, transform, inherited_visibility)| {
478-
// Skip hidden or zero-size nodes
479-
if computed.is_empty() || !inherited_visibility.get() {
480-
return None;
481-
}
482-
483-
let (_scale, _rotation, translation) = transform.to_scale_angle_translation();
484-
Some(FocusableArea {
485-
entity,
486-
position: translation,
487-
size: computed.size(),
488-
})
489-
})
485+
.filter_map(
486+
|(entity, computed_target_camera, computed, transform, inherited_visibility)| {
487+
// Skip hidden or zero-size nodes
488+
if computed.is_empty() || !inherited_visibility.get() {
489+
return None;
490+
}
491+
// Accept nodes that have the same target camera as the desired target camera
492+
if let Some(tc) = computed_target_camera.get()
493+
&& tc == target_camera
494+
{
495+
let (_scale, _rotation, translation) =
496+
transform.to_scale_angle_translation();
497+
Some(FocusableArea {
498+
entity,
499+
position: translation,
500+
size: computed.size(),
501+
})
502+
} else {
503+
// The node either does not have a target camera or it is not the same as the desired one.
504+
None
505+
}
506+
},
507+
)
490508
.collect()
491509
}
492510

493-
/// Gets the [`FocusableArea`] of the provided entity, if it exists.
511+
/// Gets the target camera and the [`FocusableArea`] of the provided entity, if it exists.
494512
///
495-
/// Returns None if there was a [`QueryEntityError`](bevy_ecs::query::QueryEntityError).
496-
fn entity_to_focusable_area(&self, entity: Entity) -> Option<FocusableArea> {
497-
self.focusable_area_query
498-
.get(entity)
499-
.map_or(None, |(entity, computed, transform)| {
500-
let (_scale, _rotation, translation) = transform.to_scale_angle_translation();
501-
Some(FocusableArea {
502-
entity,
503-
position: translation,
504-
size: computed.size(),
505-
})
506-
})
513+
/// Returns None if there was a [`QueryEntityError`](bevy_ecs::query::QueryEntityError) or
514+
/// if the entity does not have a target camera.
515+
fn entity_to_camera_and_focusable_area(
516+
&self,
517+
entity: Entity,
518+
) -> Option<(Entity, FocusableArea)> {
519+
self.camera_and_focusable_area_query.get(entity).map_or(
520+
None,
521+
|(entity, computed_target_camera, computed, transform)| {
522+
if let Some(target_camera) = computed_target_camera.get() {
523+
let (_scale, _rotation, translation) = transform.to_scale_angle_translation();
524+
Some((
525+
target_camera,
526+
FocusableArea {
527+
entity,
528+
position: translation,
529+
size: computed.size(),
530+
},
531+
))
532+
} else {
533+
None
534+
}
535+
},
536+
)
507537
}
508538
}
509539

0 commit comments

Comments
 (0)