ui_target_camera/
ui_target_camera.rs

1//! Demonstrates how to use `UiTargetCamera` and camera ordering.
2
3use bevy::color::palettes::css::BLUE;
4use bevy::color::palettes::css::GREEN;
5use bevy::color::palettes::css::RED;
6use bevy::color::palettes::css::YELLOW;
7use bevy::log::LogPlugin;
8use bevy::log::DEFAULT_FILTER;
9use bevy::prelude::*;
10
11fn main() {
12    App::new()
13        .add_plugins(DefaultPlugins.set(LogPlugin {
14            // Disable camera order ambiguity warnings
15            filter: format!("{DEFAULT_FILTER},bevy_render::camera=off"),
16            ..Default::default()
17        }))
18        .add_systems(Startup, setup)
19        .run();
20}
21
22const BOX_SIZE: f32 = 100.;
23
24fn setup(mut commands: Commands) {
25    // Root UI node displaying instructions.
26    // Has no `UiTargetCamera`; the highest-order camera rendering to the primary window will be chosen automatically.
27    commands.spawn((
28        Node {
29                align_self: AlignSelf::Center,
30                justify_self: JustifySelf::Center,
31                justify_content: JustifyContent::Center,
32                bottom: px(2. * BOX_SIZE),
33                ..default()
34            },
35            Text::new("Each box is rendered by a different camera\n* left-click: increase the camera's order\n* right-click: decrease the camera's order")
36        ));
37
38    for (i, color) in [RED, GREEN, BLUE].into_iter().enumerate() {
39        let camera_entity = commands
40            .spawn((
41                // Ordering behavior is the same using `Camera3d`.
42                Camera2d,
43                Camera {
44                    // The viewport will be cleared according to the `ClearColorConfig` of the camera with the lowest order, skipping cameras set to `ClearColorConfig::NONE`.
45                    // If all are set to `ClearColorConfig::NONE`, no clear color is used.
46                    clear_color: ClearColorConfig::Custom(color.into()),
47                    order: i as isize,
48                    ..Default::default()
49                },
50            ))
51            .id();
52
53        // Label each box with the order of its camera target
54        let label_entity = commands
55            .spawn((
56                Text(format!("{i}")),
57                TextFont::from_font_size(50.),
58                TextColor(color.into()),
59            ))
60            .id();
61
62        commands
63            .spawn((
64                Node {
65                    align_self: AlignSelf::Center,
66                    justify_self: JustifySelf::Center,
67                    justify_content: JustifyContent::Center,
68                    align_items: AlignItems::Center,
69                    left: px(0.67 * BOX_SIZE * (i as f32 - 1.)),
70                    top: px(0.67 * BOX_SIZE * (i as f32 - 1.)),
71                    width: px(BOX_SIZE),
72                    height: px(BOX_SIZE),
73                    border: px(0.1 * BOX_SIZE).into(),
74                    ..default()
75                },
76                // Bevy UI doesn't support `RenderLayers`. Each UI layout can only have one render target, selected using `UiTargetCamera`.
77                UiTargetCamera(camera_entity),
78                BackgroundColor(Color::BLACK),
79                BorderColor::all(YELLOW),
80            ))
81            .observe(
82                move |on_pressed: On<Pointer<Press>>,
83                      mut label_query: Query<&mut Text>,
84                      mut camera_query: Query<&mut Camera>| {
85                    let Ok(mut label_text) = label_query.get_mut(label_entity) else {
86                        return;
87                    };
88                    let Ok(mut camera) = camera_query.get_mut(camera_entity) else {
89                        return;
90                    };
91                    camera.order += match on_pressed.button {
92                        PointerButton::Primary => 1,
93                        _ => -1,
94                    };
95                    label_text.0 = format!("{}", camera.order);
96                },
97            )
98            .add_child(label_entity);
99    }
100}