Skip to content

Auto add default UI camera #3679

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/bevy_ui/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
//! This crate contains Bevy's UI system, which can be used to create UI for both 2D and 3D games
//! # Basic usage
//! Spawn [`entity::UiCameraBundle`] and spawn UI elements with [`entity::ButtonBundle`], [`entity::ImageBundle`], [`entity::TextBundle`] and [`entity::NodeBundle`]
//! When UI elements are present during startup, the [`entity::UiCameraBundle`] will be added automatically.
//! This UI is laid out with the Flexbox paradigm (see <https://cssreference.io/flexbox/> ) except the vertical axis is inverted
mod flex;
mod focus;
mod margins;
mod render;
mod startup;
mod ui_node;

pub mod entity;
Expand Down Expand Up @@ -72,6 +74,10 @@ impl Plugin for UiPlugin {
.register_type::<Val>()
.register_type::<widget::Button>()
.register_type::<widget::ImageMode>()
.add_startup_system_to_stage(
StartupStage::PostStartup,
startup::add_default_ui_cam_if_needed,
)
.add_system_to_stage(
CoreStage::PreUpdate,
ui_focus_system.label(UiSystem::Focus).after(InputSystem),
Expand Down
96 changes: 96 additions & 0 deletions crates/bevy_ui/src/startup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
use crate::prelude::UiCameraBundle;
use crate::ui_node::Node;
use crate::CAMERA_UI;
use bevy_ecs::prelude::{Commands, Entity, Query, With};
use bevy_render::prelude::{Camera, OrthographicProjection};

pub fn add_default_ui_cam_if_needed(
mut commands: Commands,
node_query: Query<Entity, With<Node>>,
ui_cam_query: Query<&Camera, With<OrthographicProjection>>,
) {
let world_contains_nodes = node_query.iter().next().is_some();
let world_contains_ui_cam = ui_cam_query
.iter()
.any(|cam| cam.name.as_deref() == Some(CAMERA_UI));

if world_contains_nodes && !world_contains_ui_cam {
commands.spawn_bundle(UiCameraBundle::default());
}
}

#[cfg(test)]
mod tests {
use crate::entity::{NodeBundle, UiCameraBundle};
use crate::startup::add_default_ui_cam_if_needed;
use bevy_ecs::prelude::{Stage, SystemStage, World};
use bevy_render::prelude::{Camera, OrthographicProjection};

#[test]
fn no_ui_camera_added_when_no_ui_nodes_exist() {
let mut world = World::default();

let mut startup_stage = SystemStage::parallel();
startup_stage.add_system(add_default_ui_cam_if_needed);

startup_stage.run(&mut world);

assert_eq!(
world
.query::<(&Camera, &OrthographicProjection)>()
.iter(&world)
.len(),
0
);
}

#[test]
fn ui_camera_added_when_ui_nodes_exist() {
let mut world = World::default();

world.spawn().insert_bundle(NodeBundle::default());

let mut startup_stage = SystemStage::parallel();
startup_stage.add_system(add_default_ui_cam_if_needed);

startup_stage.run(&mut world);

assert_eq!(
world
.query::<(&Camera, &OrthographicProjection)>()
.iter(&world)
.len(),
1
);
}

#[test]
fn no_duplicate_ui_camera_added_when_one_is_already_present() {
let mut world = World::default();

let cam_id = world.spawn().insert_bundle(UiCameraBundle::default()).id();

assert_eq!(
world
.query::<(&Camera, &OrthographicProjection)>()
.iter(&world)
.len(),
1
);

let mut startup_stage = SystemStage::parallel();
startup_stage.add_system(add_default_ui_cam_if_needed);

startup_stage.run(&mut world);

assert_eq!(
world
.query::<(&Camera, &OrthographicProjection)>()
.iter(&world)
.len(),
1
);

assert!(world.get::<Camera>(cam_id).is_some());
}
}
1 change: 0 additions & 1 deletion examples/2d/contributors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ fn setup_contributor_selection(mut commands: Commands, asset_server: Res<AssetSe

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
commands.spawn_bundle(UiCameraBundle::default());

commands.spawn_bundle((SelectTimer, Timer::from_seconds(SHOWCASE_TIMER_SECS, true)));

Expand Down
1 change: 0 additions & 1 deletion examples/game/breakout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {

// cameras
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
commands.spawn_bundle(UiCameraBundle::default());
// paddle
commands
.spawn_bundle(SpriteBundle {
Expand Down
1 change: 0 additions & 1 deletion examples/scene/scene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ fn save_scene_system(world: &mut World) {
// This is only necessary for the info message in the UI. See examples/ui/text.rs for a standalone
// text example.
fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn_bundle(UiCameraBundle::default());
commands.spawn_bundle(TextBundle {
style: Style {
align_self: AlignSelf::FlexEnd,
Expand Down
1 change: 0 additions & 1 deletion examples/tools/bevymark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let texture = asset_server.load("branding/icon.png");

commands.spawn_bundle(OrthographicCameraBundle::new_2d());
commands.spawn_bundle(UiCameraBundle::default());
commands.spawn_bundle(TextBundle {
text: Text {
sections: vec![
Expand Down
2 changes: 0 additions & 2 deletions examples/ui/button.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ fn button_system(
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// ui camera
commands.spawn_bundle(UiCameraBundle::default());
commands
.spawn_bundle(ButtonBundle {
style: Style {
Expand Down
1 change: 0 additions & 1 deletion examples/ui/font_atlas_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@ fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut query: Quer
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResMut<State>) {
let font_handle = asset_server.load("fonts/FiraSans-Bold.ttf");
state.handle = font_handle.clone();
commands.spawn_bundle(UiCameraBundle::default());
commands.spawn_bundle(TextBundle {
text: Text::with_section(
"a",
Expand Down
2 changes: 0 additions & 2 deletions examples/ui/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ struct FpsText;
struct ColorText;

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// UI camera
commands.spawn_bundle(UiCameraBundle::default());
// Text with one section
commands
.spawn_bundle(TextBundle {
Expand Down
1 change: 0 additions & 1 deletion examples/ui/text_debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ struct TextChanges;

fn infotext_system(mut commands: Commands, asset_server: Res<AssetServer>) {
let font = asset_server.load("fonts/FiraSans-Bold.ttf");
commands.spawn_bundle(UiCameraBundle::default());
commands.spawn_bundle(TextBundle {
style: Style {
align_self: AlignSelf::FlexEnd,
Expand Down
3 changes: 0 additions & 3 deletions examples/ui/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ fn main() {
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// ui camera
commands.spawn_bundle(UiCameraBundle::default());

// root node
commands
.spawn_bundle(NodeBundle {
Expand Down
2 changes: 0 additions & 2 deletions examples/window/scale_factor_override.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ fn main() {
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// ui camera
commands.spawn_bundle(UiCameraBundle::default());
// root node
commands
.spawn_bundle(NodeBundle {
Expand Down