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,43 +50,49 @@ fn setup(
..default() ..default()
}); });
// Left Camera // Cameras and their dedicated UI
let left_camera = commands for (index, (camera_name, camera_pos)) in [
("Player 1", Vec3::new(0.0, 200.0, -150.0)),
("Player 2", Vec3::new(150.0, 150., 50.0)),
("Player 3", Vec3::new(100.0, 150., -150.0)),
("Player 4", Vec3::new(-100.0, 80., 150.0)),
]
.iter()
.enumerate()
{
let camera = commands
.spawn(( .spawn((
Camera3dBundle { Camera3dBundle {
transform: Transform::from_xyz(0.0, 200.0, -100.0).looking_at(Vec3::ZERO, Vec3::Y), transform: Transform::from_translation(*camera_pos)
..default() .looking_at(Vec3::ZERO, Vec3::Y),
},
LeftCamera,
))
.id();
// Right Camera
let right_camera = commands
.spawn((
Camera3dBundle {
transform: Transform::from_xyz(100.0, 100., 150.0).looking_at(Vec3::ZERO, Vec3::Y),
camera: Camera { camera: Camera {
// Renders the right camera after the left camera, which has a default priority of 0 // Renders cameras with different priorities to prevent ambiguities
order: 1, order: index as isize,
// don't clear on the second camera because the first camera already cleared the window // Don't clear after the first camera because the first camera already cleared the entire window
clear_color: ClearColorConfig::None, clear_color: if index > 0 {
ClearColorConfig::None
} else {
ClearColorConfig::default()
},
..default() ..default()
}, },
..default() ..default()
}, },
RightCamera, CameraPosition {
pos: UVec2::new((index % 2) as u32, (index / 2) as u32),
},
)) ))
.id(); .id();
// Set up UI // Set up UI
commands commands
.spawn(( .spawn((
TargetCamera(left_camera), TargetCamera(camera),
NodeBundle { NodeBundle {
style: Style { style: Style {
width: Val::Percent(100.), width: Val::Percent(100.),
height: Val::Percent(100.), height: Val::Percent(100.),
padding: UiRect::all(Val::Px(20.)),
..default() ..default()
}, },
..default() ..default()
@ -94,30 +100,7 @@ fn setup(
)) ))
.with_children(|parent| { .with_children(|parent| {
parent.spawn(TextBundle::from_section( parent.spawn(TextBundle::from_section(
"Left", *camera_name,
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 { TextStyle {
font_size: 20., font_size: 20.,
..default() ..default()
@ -125,6 +108,7 @@ fn setup(
)); ));
buttons_panel(parent); 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,35 +178,24 @@ 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,
window.resolution.physical_height(),
),
..default() ..default()
}); });
} }
} }
}
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
fn button_system( fn button_system(