diff --git a/Cargo.toml b/Cargo.toml index 9602ef33fb..2724fe9af1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3922,6 +3922,16 @@ description = "A simple 2D screen shake effect" category = "Camera" wasm = true +[[example]] +name = "2d_on_ui" +path = "examples/camera/2d_on_ui.rs" +doc-scrape-examples = true + +[package.metadata.example.2d_on_ui] +name = "2D on Bevy UI" +description = "Shows how to render 2D objects on top of Bevy UI" +category = "Camera" +wasm = true [package.metadata.example.fps_overlay] name = "FPS overlay" diff --git a/examples/README.md b/examples/README.md index 4f5030563a..e130a96a0f 100644 --- a/examples/README.md +++ b/examples/README.md @@ -280,6 +280,7 @@ Example | Description Example | Description --- | --- +[2D on Bevy UI](../examples/camera/2d_on_ui.rs) | Shows how to render 2D objects on top of Bevy UI [2D top-down camera](../examples/camera/2d_top_down_camera.rs) | A 2D top-down camera smoothly following player movements [Camera Orbit](../examples/camera/camera_orbit.rs) | Shows how to orbit a static scene using pitch, yaw, and roll. [Custom Projection](../examples/camera/custom_projection.rs) | Shows how to create custom camera projections. diff --git a/examples/camera/2d_on_ui.rs b/examples/camera/2d_on_ui.rs new file mode 100644 index 0000000000..df54da98b9 --- /dev/null +++ b/examples/camera/2d_on_ui.rs @@ -0,0 +1,70 @@ +//! This example shows how to render 2D objects on top of Bevy UI, by using a second camera with a higher `order` than the UI camera. + +use bevy::{color::palettes::tailwind, prelude::*, render::view::RenderLayers}; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_systems(Startup, setup) + .add_systems(Update, rotate_sprite) + .run(); +} + +fn setup(mut commands: Commands, asset_server: Res) { + // The default camera. `IsDefaultUiCamera` makes this the default camera to render UI elements to. Alternatively, you can add the `UiTargetCamera` component to root UI nodes to define which camera they should be rendered to. + commands.spawn((Camera2d, IsDefaultUiCamera)); + + // The second camera. The higher order means that this camera will be rendered after the first camera. We will render to this camera to draw on top of the UI. + commands.spawn(( + Camera2d, + Camera { + order: 1, + // Don't draw anything in the background, to see the previous camera. + clear_color: ClearColorConfig::None, + ..default() + }, + // This camera will only render entities which are on the same render layer. + RenderLayers::layer(1), + )); + + commands.spawn(( + // We could also use a `UiTargetCamera` component here instead of the general `IsDefaultUiCamera`. + Node { + width: Val::Percent(100.), + height: Val::Percent(100.), + display: Display::Flex, + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + ..default() + }, + BackgroundColor(tailwind::ROSE_400.into()), + children![( + Node { + height: Val::Percent(30.), + width: Val::Percent(20.), + min_height: Val::Px(150.), + min_width: Val::Px(150.), + border: UiRect::all(Val::Px(2.)), + ..default() + }, + BorderRadius::all(Val::Percent(25.0)), + BorderColor::all(Color::WHITE), + )], + )); + + // This 2D object will be rendered on the second camera, on top of the default camera where the UI is rendered. + commands.spawn(( + Sprite { + image: asset_server.load("textures/rpg/chars/sensei/sensei.png"), + custom_size: Some(Vec2::new(100., 100.)), + ..default() + }, + RenderLayers::layer(1), + )); +} + +fn rotate_sprite(time: Res