Skip to content

Commit d99053c

Browse files
Update AABB when Sprite component changes in calculate_bounds_2d() (#11016)
# Objective - Fixes #10587, where the `Aabb` component of entities with `Sprite` and `Handle<Image>` components was not automatically updated when `Sprite::custom_size` changed. ## Solution - In the query for entities with `Sprite` components in `calculate_bounds_2d`, use the `Changed` filter to detect for `Sprites` that changed as well as sprites that do not have `Aabb` components. As noted in the issue, this will cause the `Aabb` to be recalculated when other fields of the `Sprite` component change, but calculating the `Aabb` for sprites is trivial. --- ## Changelog - Modified query for entities with `Sprite` components in `calculate_bounds_2d`, so that entities with `Sprite` components that changed will also have their AABB recalculated.
1 parent 2c7eab1 commit d99053c

File tree

1 file changed

+118
-3
lines changed

1 file changed

+118
-3
lines changed

crates/bevy_sprite/src/lib.rs

Lines changed: 118 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,12 @@ pub fn calculate_bounds_2d(
120120
images: Res<Assets<Image>>,
121121
atlases: Res<Assets<TextureAtlas>>,
122122
meshes_without_aabb: Query<(Entity, &Mesh2dHandle), (Without<Aabb>, Without<NoFrustumCulling>)>,
123-
sprites_without_aabb: Query<
123+
sprites_to_recalculate_aabb: Query<
124124
(Entity, &Sprite, &Handle<Image>),
125-
(Without<Aabb>, Without<NoFrustumCulling>),
125+
(
126+
Or<(Without<Aabb>, Changed<Sprite>)>,
127+
Without<NoFrustumCulling>,
128+
),
126129
>,
127130
atlases_without_aabb: Query<
128131
(Entity, &TextureAtlasSprite, &Handle<TextureAtlas>),
@@ -136,7 +139,7 @@ pub fn calculate_bounds_2d(
136139
}
137140
}
138141
}
139-
for (entity, sprite, texture_handle) in &sprites_without_aabb {
142+
for (entity, sprite, texture_handle) in &sprites_to_recalculate_aabb {
140143
if let Some(size) = sprite
141144
.custom_size
142145
.or_else(|| images.get(texture_handle).map(|image| image.size_f32()))
@@ -163,3 +166,115 @@ pub fn calculate_bounds_2d(
163166
}
164167
}
165168
}
169+
170+
#[cfg(test)]
171+
mod test {
172+
173+
use bevy_math::Vec2;
174+
use bevy_utils::default;
175+
176+
use super::*;
177+
178+
#[test]
179+
fn calculate_bounds_2d_create_aabb_for_image_sprite_entity() {
180+
// Setup app
181+
let mut app = App::new();
182+
183+
// Add resources and get handle to image
184+
let mut image_assets = Assets::<Image>::default();
185+
let image_handle = image_assets.add(Image::default());
186+
app.insert_resource(image_assets);
187+
let mesh_assets = Assets::<Mesh>::default();
188+
app.insert_resource(mesh_assets);
189+
let texture_atlas_assets = Assets::<TextureAtlas>::default();
190+
app.insert_resource(texture_atlas_assets);
191+
192+
// Add system
193+
app.add_systems(Update, calculate_bounds_2d);
194+
195+
// Add entites
196+
let entity = app.world.spawn((Sprite::default(), image_handle)).id();
197+
198+
// Verify that the entity does not have an AABB
199+
assert!(!app
200+
.world
201+
.get_entity(entity)
202+
.expect("Could not find entity")
203+
.contains::<Aabb>());
204+
205+
// Run system
206+
app.update();
207+
208+
// Verify the AABB exists
209+
assert!(app
210+
.world
211+
.get_entity(entity)
212+
.expect("Could not find entity")
213+
.contains::<Aabb>());
214+
}
215+
216+
#[test]
217+
fn calculate_bounds_2d_update_aabb_when_sprite_custom_size_changes_to_some() {
218+
// Setup app
219+
let mut app = App::new();
220+
221+
// Add resources and get handle to image
222+
let mut image_assets = Assets::<Image>::default();
223+
let image_handle = image_assets.add(Image::default());
224+
app.insert_resource(image_assets);
225+
let mesh_assets = Assets::<Mesh>::default();
226+
app.insert_resource(mesh_assets);
227+
let texture_atlas_assets = Assets::<TextureAtlas>::default();
228+
app.insert_resource(texture_atlas_assets);
229+
230+
// Add system
231+
app.add_systems(Update, calculate_bounds_2d);
232+
233+
// Add entites
234+
let entity = app
235+
.world
236+
.spawn((
237+
Sprite {
238+
custom_size: Some(Vec2::ZERO),
239+
..default()
240+
},
241+
image_handle,
242+
))
243+
.id();
244+
245+
// Create initial AABB
246+
app.update();
247+
248+
// Get the initial AABB
249+
let first_aabb = *app
250+
.world
251+
.get_entity(entity)
252+
.expect("Could not find entity")
253+
.get::<Aabb>()
254+
.expect("Could not find initial AABB");
255+
256+
// Change `custom_size` of sprite
257+
let mut binding = app
258+
.world
259+
.get_entity_mut(entity)
260+
.expect("Could not find entity");
261+
let mut sprite = binding
262+
.get_mut::<Sprite>()
263+
.expect("Could not find sprite component of entity");
264+
sprite.custom_size = Some(Vec2::ONE);
265+
266+
// Re-run the `calculate_bounds_2d` system to get the new AABB
267+
app.update();
268+
269+
// Get the re-calculated AABB
270+
let second_aabb = *app
271+
.world
272+
.get_entity(entity)
273+
.expect("Could not find entity")
274+
.get::<Aabb>()
275+
.expect("Could not find second AABB");
276+
277+
// Check that the AABBs are not equal
278+
assert_ne!(first_aabb, second_aabb);
279+
}
280+
}

0 commit comments

Comments
 (0)