mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
eb9db21113
# Objective Add support for presenting each UI tree on a specific window and viewport, while making as few breaking changes as possible. This PR is meant to resolve the following issues at once, since they're all related. - Fixes #5622 - Fixes #5570 - Fixes #5621 Adopted #5892 , but started over since the current codebase diverged significantly from the original PR branch. Also, I made a decision to propagate component to children instead of recursively iterating over nodes in search for the root. ## Solution Add a new optional component that can be inserted to UI root nodes and propagate to children to specify which camera it should render onto. This is then used to get the render target and the viewport for that UI tree. Since this component is optional, the default behavior should be to render onto the single camera (if only one exist) and warn of ambiguity if multiple cameras exist. This reduces the complexity for users with just one camera, while giving control in contexts where it matters. ## Changelog - Adds `TargetCamera(Entity)` component to specify which camera should a node tree be rendered into. If only one camera exists, this component is optional. - Adds an example of rendering UI to a texture and using it as a material in a 3D world. - Fixes recalculation of physical viewport size when target scale factor changes. This can happen when the window is moved between displays with different DPI. - Changes examples to demonstrate assigning UI to different viewports and windows and make interactions in an offset viewport testable. - Removes `UiCameraConfig`. UI visibility now can be controlled via combination of explicit `TargetCamera` and `Visibility` on the root nodes. --------- Co-authored-by: davier <bricedavier@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Alice Cecile <alice.i.cecil@gmail.com>
95 lines
3.1 KiB
Rust
95 lines
3.1 KiB
Rust
//! Showcases the [`RelativeCursorPosition`] component, used to check the position of the cursor relative to a UI node.
|
|
|
|
use bevy::{
|
|
prelude::*, render::camera::Viewport, ui::RelativeCursorPosition, winit::WinitSettings,
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
// Only run the app when there is user input. This will significantly reduce CPU/GPU use.
|
|
.insert_resource(WinitSettings::desktop_app())
|
|
.add_systems(Startup, setup)
|
|
.add_systems(Update, relative_cursor_position_system)
|
|
.run();
|
|
}
|
|
|
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
commands.spawn(Camera2dBundle {
|
|
camera: Camera {
|
|
// Cursor position will take the viewport offset into account
|
|
viewport: Some(Viewport {
|
|
physical_position: [200, 100].into(),
|
|
physical_size: [600, 600].into(),
|
|
..default()
|
|
}),
|
|
..default()
|
|
},
|
|
..default()
|
|
});
|
|
|
|
commands
|
|
.spawn(NodeBundle {
|
|
style: Style {
|
|
width: Val::Percent(100.),
|
|
height: Val::Percent(100.0),
|
|
align_items: AlignItems::Center,
|
|
justify_content: JustifyContent::Center,
|
|
flex_direction: FlexDirection::Column,
|
|
..default()
|
|
},
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
parent
|
|
.spawn(NodeBundle {
|
|
style: Style {
|
|
width: Val::Px(250.),
|
|
height: Val::Px(250.),
|
|
margin: UiRect::bottom(Val::Px(15.)),
|
|
..default()
|
|
},
|
|
background_color: Color::rgb(235., 35., 12.).into(),
|
|
..default()
|
|
})
|
|
.insert(RelativeCursorPosition::default());
|
|
|
|
parent.spawn(TextBundle {
|
|
text: Text::from_section(
|
|
"(0.0, 0.0)",
|
|
TextStyle {
|
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
|
font_size: 40.0,
|
|
color: Color::rgb(0.9, 0.9, 0.9),
|
|
},
|
|
),
|
|
..default()
|
|
});
|
|
});
|
|
}
|
|
|
|
/// This systems polls the relative cursor position and displays its value in a text component.
|
|
fn relative_cursor_position_system(
|
|
relative_cursor_position_query: Query<&RelativeCursorPosition>,
|
|
mut output_query: Query<&mut Text>,
|
|
) {
|
|
let relative_cursor_position = relative_cursor_position_query.single();
|
|
|
|
let mut output = output_query.single_mut();
|
|
|
|
output.sections[0].value =
|
|
if let Some(relative_cursor_position) = relative_cursor_position.normalized {
|
|
format!(
|
|
"({:.1}, {:.1})",
|
|
relative_cursor_position.x, relative_cursor_position.y
|
|
)
|
|
} else {
|
|
"unknown".to_string()
|
|
};
|
|
|
|
output.sections[0].style.color = if relative_cursor_position.mouse_over() {
|
|
Color::rgb(0.1, 0.9, 0.1)
|
|
} else {
|
|
Color::rgb(0.9, 0.1, 0.1)
|
|
};
|
|
}
|