Update split_screen example with 4 cameras (#12010)

# Objective

Improve `split_screen` example to use 4 cameras.

This serves as a visual regression test for #12006.

## Solution

With the fix of #11968:


![image](https://github.com/bevyengine/bevy/assets/6532395/57e9e013-7d23-429f-98ac-c6542d6b4bea)

Without (current `main`):


![image](https://github.com/bevyengine/bevy/assets/6532395/0b2a88a4-97f8-408d-8a0e-ce917efc668d)
This commit is contained in:
Jerome Humbert 2024-02-20 22:15:44 +00:00 committed by GitHub
parent 1d0ea78f36
commit 5a74ff6f5e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -50,81 +50,65 @@ fn setup(
..default() ..default()
}); });
// Left Camera // Cameras and their dedicated UI
let left_camera = commands for (index, (camera_name, camera_pos)) in [
.spawn(( ("Player 1", Vec3::new(0.0, 200.0, -150.0)),
Camera3dBundle { ("Player 2", Vec3::new(150.0, 150., 50.0)),
transform: Transform::from_xyz(0.0, 200.0, -100.0).looking_at(Vec3::ZERO, Vec3::Y), ("Player 3", Vec3::new(100.0, 150., -150.0)),
..default() ("Player 4", Vec3::new(-100.0, 80., 150.0)),
}, ]
LeftCamera, .iter()
)) .enumerate()
.id(); {
let camera = commands
.spawn((
Camera3dBundle {
transform: Transform::from_translation(*camera_pos)
.looking_at(Vec3::ZERO, Vec3::Y),
camera: Camera {
// Renders cameras with different priorities to prevent ambiguities
order: index as isize,
// Don't clear after the first camera because the first camera already cleared the entire window
clear_color: if index > 0 {
ClearColorConfig::None
} else {
ClearColorConfig::default()
},
..default()
},
..default()
},
CameraPosition {
pos: UVec2::new((index % 2) as u32, (index / 2) as u32),
},
))
.id();
// Right Camera // Set up UI
let right_camera = commands commands
.spawn(( .spawn((
Camera3dBundle { TargetCamera(camera),
transform: Transform::from_xyz(100.0, 100., 150.0).looking_at(Vec3::ZERO, Vec3::Y), NodeBundle {
camera: Camera { style: Style {
// Renders the right camera after the left camera, which has a default priority of 0 width: Val::Percent(100.),
order: 1, height: Val::Percent(100.),
// don't clear on the second camera because the first camera already cleared the window padding: UiRect::all(Val::Px(20.)),
clear_color: ClearColorConfig::None, ..default()
},
..default() ..default()
}, },
..default() ))
}, .with_children(|parent| {
RightCamera, parent.spawn(TextBundle::from_section(
)) *camera_name,
.id(); TextStyle {
font_size: 20.,
// Set up UI ..default()
commands },
.spawn(( ));
TargetCamera(left_camera), buttons_panel(parent);
NodeBundle { });
style: Style { }
width: Val::Percent(100.),
height: Val::Percent(100.),
..default()
},
..default()
},
))
.with_children(|parent| {
parent.spawn(TextBundle::from_section(
"Left",
TextStyle {
font_size: 20.,
..default()
},
));
buttons_panel(parent);
});
commands
.spawn((
TargetCamera(right_camera),
NodeBundle {
style: Style {
width: Val::Percent(100.),
height: Val::Percent(100.),
..default()
},
..default()
},
))
.with_children(|parent| {
parent.spawn(TextBundle::from_section(
"Right",
TextStyle {
font_size: 20.,
..default()
},
));
buttons_panel(parent);
});
fn buttons_panel(parent: &mut ChildBuilder) { fn buttons_panel(parent: &mut ChildBuilder) {
parent parent
@ -179,10 +163,9 @@ fn setup(
} }
#[derive(Component)] #[derive(Component)]
struct LeftCamera; struct CameraPosition {
pos: UVec2,
#[derive(Component)] }
struct RightCamera;
#[derive(Component)] #[derive(Component)]
struct RotateCamera(Direction); struct RotateCamera(Direction);
@ -195,33 +178,22 @@ enum Direction {
fn set_camera_viewports( fn set_camera_viewports(
windows: Query<&Window>, windows: Query<&Window>,
mut resize_events: EventReader<WindowResized>, mut resize_events: EventReader<WindowResized>,
mut left_camera: Query<&mut Camera, (With<LeftCamera>, Without<RightCamera>)>, mut query: Query<(&CameraPosition, &mut Camera)>,
mut right_camera: Query<&mut Camera, With<RightCamera>>,
) { ) {
// We need to dynamically resize the camera's viewports whenever the window size changes // We need to dynamically resize the camera's viewports whenever the window size changes
// so then each camera always takes up half the screen. // so then each camera always takes up half the screen.
// A resize_event is sent when the window is first created, allowing us to reuse this system for initial setup. // A resize_event is sent when the window is first created, allowing us to reuse this system for initial setup.
for resize_event in resize_events.read() { for resize_event in resize_events.read() {
let window = windows.get(resize_event.window).unwrap(); let window = windows.get(resize_event.window).unwrap();
let mut left_camera = left_camera.single_mut(); let size = UVec2::new(window.physical_width(), window.physical_height()) / 2;
left_camera.viewport = Some(Viewport {
physical_position: UVec2::new(0, 0),
physical_size: UVec2::new(
window.resolution.physical_width() / 2,
window.resolution.physical_height(),
),
..default()
});
let mut right_camera = right_camera.single_mut(); for (camera_position, mut camera) in &mut query {
right_camera.viewport = Some(Viewport { camera.viewport = Some(Viewport {
physical_position: UVec2::new(window.resolution.physical_width() / 2, 0), physical_position: camera_position.pos * size,
physical_size: UVec2::new( physical_size: size,
window.resolution.physical_width() / 2, ..default()
window.resolution.physical_height(), });
), }
..default()
});
} }
} }