Deprecate SpatialBundle (#15830)

# Objective

- Required components replace bundles, but `SpatialBundle` is yet to be
deprecated

## Solution

- Deprecate `SpatialBundle`
- Insert `Transform` and `Visibility` instead in examples using it
- In `spawn` or `insert` inserting a default `Transform` or `Visibility`
with component already requiring either, remove those components from
the tuple

## Testing

- Did you test these changes? If so, how?
Yes, I ran the examples I changed and tests
- Are there any parts that need more testing?
The `gamepad_viewer` and and `custom_shader_instancing` examples don't
work as intended due to entirely unrelated code, didn't check main.
- How can other people (reviewers) test your changes? Is there anything
specific they need to know?
Run examples, or just check that all spawned values are identical
- If relevant, what platforms did you test these changes on, and are
there any important ones you can't test?
Linux, wayland trough x11 (cause that's the default feature)

---

## Migration Guide

`SpatialBundle` is now deprecated, insert `Transform` and `Visibility`
instead which will automatically insert all other components that were
in the bundle. If you do not specify these values and any other
components in your `spawn`/`insert` call already requires either of
these components you can leave that one out.

before:
```rust
commands.spawn(SpatialBundle::default());
```

after:
```rust
commands.spawn((Transform::default(), Visibility::default());
```
This commit is contained in:
NiseVoid 2024-10-13 19:28:22 +02:00 committed by GitHub
parent 0720e62f74
commit bdd0af6bfb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
19 changed files with 67 additions and 103 deletions

View file

@ -28,7 +28,6 @@ use bevy_render::{
skinning::{SkinnedMesh, SkinnedMeshInverseBindposes}, skinning::{SkinnedMesh, SkinnedMeshInverseBindposes},
Indices, Mesh, Mesh3d, MeshVertexAttribute, VertexAttributeValues, Indices, Mesh, Mesh3d, MeshVertexAttribute, VertexAttributeValues,
}, },
prelude::SpatialBundle,
primitives::Aabb, primitives::Aabb,
render_asset::RenderAssetUsages, render_asset::RenderAssetUsages,
render_resource::{Face, PrimitiveTopology}, render_resource::{Face, PrimitiveTopology},
@ -36,6 +35,7 @@ use bevy_render::{
CompressedImageFormats, Image, ImageAddressMode, ImageFilterMode, ImageLoaderSettings, CompressedImageFormats, Image, ImageAddressMode, ImageFilterMode, ImageLoaderSettings,
ImageSampler, ImageSamplerDescriptor, ImageType, TextureError, ImageSampler, ImageSamplerDescriptor, ImageType, TextureError,
}, },
view::Visibility,
}; };
use bevy_scene::Scene; use bevy_scene::Scene;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
@ -822,7 +822,7 @@ async fn load_gltf<'a, 'b, 'c>(
let mut scene_load_context = load_context.begin_labeled_asset(); let mut scene_load_context = load_context.begin_labeled_asset();
let world_root_id = world let world_root_id = world
.spawn(SpatialBundle::INHERITED_IDENTITY) .spawn((Transform::default(), Visibility::default()))
.with_children(|parent| { .with_children(|parent| {
for node in scene.nodes() { for node in scene.nodes() {
let result = load_node( let result = load_node(
@ -1359,7 +1359,7 @@ fn load_node(
// of negative scale factors is odd. if so we will assign a copy of the material with face // of negative scale factors is odd. if so we will assign a copy of the material with face
// culling inverted, rather than modifying the mesh data directly. // culling inverted, rather than modifying the mesh data directly.
let is_scale_inverted = world_transform.scale.is_negative_bitmask().count_ones() & 1 == 1; let is_scale_inverted = world_transform.scale.is_negative_bitmask().count_ones() & 1 == 1;
let mut node = world_builder.spawn(SpatialBundle::from(transform)); let mut node = world_builder.spawn((transform, Visibility::default()));
let name = node_name(gltf_node); let name = node_name(gltf_node);
node.insert(name.clone()); node.insert(name.clone());

View file

@ -1,3 +1,4 @@
#![expect(deprecated)]
use bevy_ecs::prelude::Bundle; use bevy_ecs::prelude::Bundle;
use bevy_transform::prelude::{GlobalTransform, Transform}; use bevy_transform::prelude::{GlobalTransform, Transform};
@ -16,6 +17,12 @@ use crate::view::{InheritedVisibility, ViewVisibility, Visibility};
/// ///
/// [`Component`]: bevy_ecs::component::Component /// [`Component`]: bevy_ecs::component::Component
#[derive(Bundle, Clone, Debug, Default)] #[derive(Bundle, Clone, Debug, Default)]
#[deprecated(
since = "0.15.0",
note = "Use the `Transform` and `Visibility` components instead.
Inserting `Transform` will now also insert a `GlobalTransform` automatically.
Inserting 'Visibility' will now also insert `InheritedVisibility` and `ViewVisibility` automatically."
)]
pub struct SpatialBundle { pub struct SpatialBundle {
/// The visibility of the entity. /// The visibility of the entity.
pub visibility: Visibility, pub visibility: Visibility,

View file

@ -203,20 +203,14 @@ const OFFSET_Y: f32 = 75.;
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(( commands.spawn((
SpatialBundle { Transform::from_xyz(-OFFSET_X, OFFSET_Y, 0.),
transform: Transform::from_xyz(-OFFSET_X, OFFSET_Y, 0.),
..default()
},
Shape::Circle(Circle::new(45.)), Shape::Circle(Circle::new(45.)),
DesiredVolume::Aabb, DesiredVolume::Aabb,
Intersects::default(), Intersects::default(),
)); ));
commands.spawn(( commands.spawn((
SpatialBundle { Transform::from_xyz(0., OFFSET_Y, 0.),
transform: Transform::from_xyz(0., OFFSET_Y, 0.),
..default()
},
Shape::Rectangle(Rectangle::new(80., 80.)), Shape::Rectangle(Rectangle::new(80., 80.)),
Spin, Spin,
DesiredVolume::Circle, DesiredVolume::Circle,
@ -224,10 +218,7 @@ fn setup(mut commands: Commands) {
)); ));
commands.spawn(( commands.spawn((
SpatialBundle { Transform::from_xyz(OFFSET_X, OFFSET_Y, 0.),
transform: Transform::from_xyz(OFFSET_X, OFFSET_Y, 0.),
..default()
},
Shape::Triangle(Triangle2d::new( Shape::Triangle(Triangle2d::new(
Vec2::new(-40., -40.), Vec2::new(-40., -40.),
Vec2::new(-20., 40.), Vec2::new(-20., 40.),
@ -239,10 +230,7 @@ fn setup(mut commands: Commands) {
)); ));
commands.spawn(( commands.spawn((
SpatialBundle { Transform::from_xyz(-OFFSET_X, -OFFSET_Y, 0.),
transform: Transform::from_xyz(-OFFSET_X, -OFFSET_Y, 0.),
..default()
},
Shape::Line(Segment2d::new(Dir2::from_xy(1., 0.3).unwrap(), 90.)), Shape::Line(Segment2d::new(Dir2::from_xy(1., 0.3).unwrap(), 90.)),
Spin, Spin,
DesiredVolume::Circle, DesiredVolume::Circle,
@ -250,10 +238,7 @@ fn setup(mut commands: Commands) {
)); ));
commands.spawn(( commands.spawn((
SpatialBundle { Transform::from_xyz(0., -OFFSET_Y, 0.),
transform: Transform::from_xyz(0., -OFFSET_Y, 0.),
..default()
},
Shape::Capsule(Capsule2d::new(25., 50.)), Shape::Capsule(Capsule2d::new(25., 50.)),
Spin, Spin,
DesiredVolume::Aabb, DesiredVolume::Aabb,
@ -261,10 +246,7 @@ fn setup(mut commands: Commands) {
)); ));
commands.spawn(( commands.spawn((
SpatialBundle { Transform::from_xyz(OFFSET_X, -OFFSET_Y, 0.),
transform: Transform::from_xyz(OFFSET_X, -OFFSET_Y, 0.),
..default()
},
Shape::Polygon(RegularPolygon::new(50., 6)), Shape::Polygon(RegularPolygon::new(50., 6)),
Spin, Spin,
DesiredVolume::Circle, DesiredVolume::Circle,

View file

@ -110,8 +110,6 @@ fn star(
ColoredMesh2d, ColoredMesh2d,
// The `Handle<Mesh>` needs to be wrapped in a `Mesh2d` for 2D rendering // The `Handle<Mesh>` needs to be wrapped in a `Mesh2d` for 2D rendering
Mesh2d(meshes.add(star)), Mesh2d(meshes.add(star)),
// This bundle's components are needed for something to be rendered
SpatialBundle::INHERITED_IDENTITY,
)); ));
// Spawn the camera // Spawn the camera

View file

@ -30,20 +30,17 @@ fn main() {
/// Spawns all the objects in the scene. /// Spawns all the objects in the scene.
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// Spawn a fog volume with a voxelized version of the Stanford bunny. // Spawn a fog volume with a voxelized version of the Stanford bunny.
commands commands.spawn((
.spawn(SpatialBundle { Transform::from_xyz(0.0, 0.5, 0.0),
visibility: Visibility::Visible, FogVolume {
transform: Transform::from_xyz(0.0, 0.5, 0.0),
..default()
})
.insert(FogVolume {
density_texture: Some(asset_server.load("volumes/bunny.ktx2")), density_texture: Some(asset_server.load("volumes/bunny.ktx2")),
density_factor: 1.0, density_factor: 1.0,
// Scatter as much of the light as possible, to brighten the bunny // Scatter as much of the light as possible, to brighten the bunny
// up. // up.
scattering: 1.0, scattering: 1.0,
..default() ..default()
}); },
));
// Spawn a bright directional light that illuminates the fog well. // Spawn a bright directional light that illuminates the fog well.
commands.spawn(( commands.spawn((

View file

@ -243,16 +243,14 @@ fn spawn_camera(commands: &mut Commands, assets: &ExampleAssets) {
} }
fn spawn_irradiance_volume(commands: &mut Commands, assets: &ExampleAssets) { fn spawn_irradiance_volume(commands: &mut Commands, assets: &ExampleAssets) {
commands commands.spawn((
.spawn(SpatialBundle { Transform::from_matrix(VOXEL_FROM_WORLD),
transform: Transform::from_matrix(VOXEL_FROM_WORLD), IrradianceVolume {
..SpatialBundle::default()
})
.insert(IrradianceVolume {
voxels: assets.irradiance_volume.clone(), voxels: assets.irradiance_volume.clone(),
intensity: IRRADIANCE_VOLUME_INTENSITY, intensity: IRRADIANCE_VOLUME_INTENSITY,
}) },
.insert(LightProbe); LightProbe,
));
} }
fn spawn_light(commands: &mut Commands) { fn spawn_light(commands: &mut Commands) {
@ -277,12 +275,7 @@ fn spawn_sphere(commands: &mut Commands, assets: &ExampleAssets) {
} }
fn spawn_voxel_cube_parent(commands: &mut Commands) { fn spawn_voxel_cube_parent(commands: &mut Commands) {
commands commands.spawn((Visibility::Hidden, Transform::default(), VoxelCubeParent));
.spawn(SpatialBundle {
visibility: Visibility::Hidden,
..default()
})
.insert(VoxelCubeParent);
} }
fn spawn_fox(commands: &mut Commands, assets: &ExampleAssets) { fn spawn_fox(commands: &mut Commands, assets: &ExampleAssets) {

View file

@ -113,11 +113,7 @@ fn setup(
// Spawn a FogVolume and use the repeating noise texture as its density texture. // Spawn a FogVolume and use the repeating noise texture as its density texture.
commands.spawn(( commands.spawn((
SpatialBundle { Transform::from_xyz(0.0, 32.0, 0.0).with_scale(Vec3::splat(64.0)),
visibility: Visibility::Visible,
transform: Transform::from_xyz(0.0, 32.0, 0.0).with_scale(Vec3::splat(64.0)),
..default()
},
FogVolume { FogVolume {
density_texture: Some(noise_texture), density_texture: Some(noise_texture),
density_factor: 0.05, density_factor: 0.05,

View file

@ -46,13 +46,7 @@ fn setup(
let light_transform = Transform::from_xyz(5.0, 5.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y); let light_transform = Transform::from_xyz(5.0, 5.0, 0.0).looking_at(Vec3::ZERO, Vec3::Y);
commands commands
.spawn(( .spawn((light_transform, Visibility::default(), Lights))
SpatialBundle {
transform: light_transform,
..default()
},
Lights,
))
.with_children(|builder| { .with_children(|builder| {
builder.spawn(PointLight { builder.spawn(PointLight {
intensity: 0.0, intensity: 0.0,

View file

@ -151,7 +151,8 @@ fn setup(
.with_children(|p| { .with_children(|p| {
// This entity is just used for animation, but doesn't display anything // This entity is just used for animation, but doesn't display anything
p.spawn(( p.spawn((
SpatialBundle::INHERITED_IDENTITY, Transform::default(),
Visibility::default(),
orbit_controller, orbit_controller,
AnimationTarget { AnimationTarget {
id: orbit_controller_animation_target_id, id: orbit_controller_animation_target_id,

View file

@ -44,7 +44,11 @@ fn setup(
let listener = SpatialListener::new(gap); let listener = SpatialListener::new(gap);
commands commands
.spawn((SpatialBundle::default(), listener.clone())) .spawn((
Transform::default(),
Visibility::default(),
listener.clone(),
))
.with_children(|parent| { .with_children(|parent| {
// left ear // left ear
parent.spawn(( parent.spawn((

View file

@ -35,7 +35,11 @@ fn setup(
let listener = SpatialListener::new(gap); let listener = SpatialListener::new(gap);
commands commands
.spawn((SpatialBundle::default(), listener.clone())) .spawn((
Transform::default(),
Visibility::default(),
listener.clone(),
))
.with_children(|parent| { .with_children(|parent| {
// left ear indicator // left ear indicator
parent.spawn(( parent.spawn((

View file

@ -108,10 +108,8 @@ fn spawn_view_model(
.spawn(( .spawn((
Player, Player,
CameraSensitivity::default(), CameraSensitivity::default(),
SpatialBundle { Transform::from_xyz(0.0, 1.0, 0.0),
transform: Transform::from_xyz(0.0, 1.0, 0.0), Visibility::default(),
..default()
},
)) ))
.with_children(|parent| { .with_children(|parent| {
parent.spawn(( parent.spawn((

View file

@ -146,9 +146,7 @@ fn setup(
// sclera // sclera
commands commands
.spawn(SpatialBundle::from_transform(Transform::from_xyz( .spawn((Transform::from_xyz(x, y, 2.0), Visibility::default()))
x, y, 2.0,
)))
.with_children(|commands| { .with_children(|commands| {
// sclera // sclera
commands.spawn(( commands.spawn((
@ -163,7 +161,8 @@ fn setup(
// pupil // pupil
commands commands
.spawn(( .spawn((
SpatialBundle::from_transform(Transform::from_xyz(0.0, 0.0, 1.0)), Transform::from_xyz(0.0, 0.0, 1.0),
Visibility::default(),
Pupil { Pupil {
eye_radius: radius, eye_radius: radius,
pupil_radius, pupil_radius,

View file

@ -35,7 +35,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let sprite_size = Vec2::splat(len / 2.0); let sprite_size = Vec2::splat(len / 2.0);
commands commands
.spawn(SpatialBundle::default()) .spawn((Transform::default(), Visibility::default()))
.with_children(|commands| { .with_children(|commands| {
for (anchor_index, anchor) in [ for (anchor_index, anchor) in [
Anchor::TopLeft, Anchor::TopLeft,

View file

@ -198,18 +198,16 @@ fn main() {
fn setup(mut commands: Commands) { fn setup(mut commands: Commands) {
// Spawn a single entity that has custom rendering. It'll be extracted into // Spawn a single entity that has custom rendering. It'll be extracted into
// the render world via [`ExtractComponent`]. // the render world via [`ExtractComponent`].
commands commands.spawn((
.spawn(SpatialBundle { Visibility::default(),
visibility: Visibility::Visible, Transform::default(),
transform: Transform::IDENTITY,
..default()
})
// This `Aabb` is necessary for the visibility checks to work. // This `Aabb` is necessary for the visibility checks to work.
.insert(Aabb { Aabb {
center: Vec3A::ZERO, center: Vec3A::ZERO,
half_extents: Vec3A::splat(0.5), half_extents: Vec3A::splat(0.5),
}) },
.insert(CustomRenderedEntity); CustomRenderedEntity,
));
// Spawn the camera. // Spawn the camera.
commands.spawn(( commands.spawn((

View file

@ -49,7 +49,6 @@ fn main() {
fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) { fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
commands.spawn(( commands.spawn((
Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))), Mesh3d(meshes.add(Cuboid::new(0.5, 0.5, 0.5))),
SpatialBundle::INHERITED_IDENTITY,
InstanceMaterialData( InstanceMaterialData(
(1..=10) (1..=10)
.flat_map(|x| (1..=10).map(move |y| (x as f32 / 10.0, y as f32 / 10.0))) .flat_map(|x| (1..=10).map(move |y| (x as f32 / 10.0, y as f32 / 10.0)))

View file

@ -80,11 +80,7 @@ fn setup(mut commands: Commands, mut meshes: ResMut<Assets<Mesh>>) {
CustomRenderedEntity, CustomRenderedEntity,
// We need to add the mesh handle to the entity // We need to add the mesh handle to the entity
Mesh3d(meshes.add(mesh.clone())), Mesh3d(meshes.add(mesh.clone())),
// This bundle's components are needed for something to be rendered Transform::from_xyz(x, y, 0.0),
SpatialBundle {
transform: Transform::from_xyz(x, y, 0.0),
..SpatialBundle::INHERITED_IDENTITY
},
)); ));
} }

View file

@ -156,7 +156,8 @@ fn setup(
let (base_rotation, ring_direction) = ring_directions[ring_index % 2]; let (base_rotation, ring_direction) = ring_directions[ring_index % 2];
let ring_parent = commands let ring_parent = commands
.spawn(( .spawn((
SpatialBundle::INHERITED_IDENTITY, Transform::default(),
Visibility::default(),
ring_direction, ring_direction,
Ring { radius }, Ring { radius },
)) ))

View file

@ -133,10 +133,10 @@ fn setup(mut commands: Commands, meshes: Res<ButtonMeshes>, materials: Res<Butto
// Buttons // Buttons
commands commands
.spawn(SpatialBundle { .spawn((
transform: Transform::from_xyz(BUTTONS_X, BUTTONS_Y, 0.), Transform::from_xyz(BUTTONS_X, BUTTONS_Y, 0.),
..default() Visibility::default(),
}) ))
.with_children(|parent| { .with_children(|parent| {
parent.spawn(GamepadButtonBundle::new( parent.spawn(GamepadButtonBundle::new(
GamepadButton::North, GamepadButton::North,
@ -189,10 +189,10 @@ fn setup(mut commands: Commands, meshes: Res<ButtonMeshes>, materials: Res<Butto
// D-Pad // D-Pad
commands commands
.spawn(SpatialBundle { .spawn((
transform: Transform::from_xyz(-BUTTONS_X, BUTTONS_Y, 0.), Transform::from_xyz(-BUTTONS_X, BUTTONS_Y, 0.),
..default() Visibility::default(),
}) ))
.with_children(|parent| { .with_children(|parent| {
parent.spawn(GamepadButtonBundle::new( parent.spawn(GamepadButtonBundle::new(
GamepadButton::DPadUp, GamepadButton::DPadUp,
@ -276,10 +276,7 @@ fn setup_sticks(
let mut spawn_stick = |x_pos, y_pos, x_axis, y_axis, button| { let mut spawn_stick = |x_pos, y_pos, x_axis, y_axis, button| {
commands commands
.spawn(SpatialBundle { .spawn((Transform::from_xyz(x_pos, y_pos, 0.), Visibility::default()))
transform: Transform::from_xyz(x_pos, y_pos, 0.),
..default()
})
.with_children(|parent| { .with_children(|parent| {
// full extent // full extent
parent.spawn(Sprite::from_color( parent.spawn(Sprite::from_color(