Skip to content

Commit 0a9740c

Browse files
authored
Make sprite picking opt-in (#17225)
# Objective Fixes #16903. ## Solution - Make sprite picking opt-in by requiring a new `SpritePickingCamera` component for cameras and usage of a new `Pickable` component for entities. - Update the `sprite_picking` example to reflect these changes. - Some reflection cleanup (I hope that's ok). ## Testing Ran the `sprite_picking` example ## Open Questions <del> <ul> <li>Is the name `SpritePickable` appropriate?</li> <li>Should `SpritePickable` be in `bevy_sprite::prelude?</li> </ul> </del> ## Migration Guide The sprite picking backend is now strictly opt-in using the `SpritePickingCamera` and `Pickable` components. You should add the `Pickable` component any entities that you want sprite picking to be enabled for, and mark their respective cameras with `SpritePickingCamera`.
1 parent b20e23d commit 0a9740c

File tree

3 files changed

+40
-9
lines changed

3 files changed

+40
-9
lines changed

crates/bevy_picking/src/lib.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,12 @@ pub mod prelude {
188188
};
189189
}
190190

191-
/// An optional component that overrides default picking behavior for an entity, allowing you to
192-
/// make an entity non-hoverable, or allow items below it to be hovered. See the documentation on
193-
/// the fields for more details.
191+
/// An optional component that marks an entity as usable by a backend, and overrides default
192+
/// picking behavior for an entity.
193+
///
194+
/// This allows you to make an entity non-hoverable, or allow items below it to be hovered.
195+
///
196+
/// See the documentation on the fields for more details.
194197
#[derive(Component, Debug, Clone, Reflect, PartialEq, Eq)]
195198
#[reflect(Component, Default, Debug, PartialEq)]
196199
pub struct PickingBehavior {

crates/bevy_sprite/src/picking_backend.rs

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@ use bevy_render::prelude::*;
1515
use bevy_transform::prelude::*;
1616
use bevy_window::PrimaryWindow;
1717

18+
/// A component that marks cameras that should be used in the [`SpritePickingPlugin`].
19+
#[derive(Debug, Clone, Default, Component, Reflect)]
20+
#[reflect(Debug, Default, Component)]
21+
pub struct SpritePickingCamera;
22+
1823
/// How should the [`SpritePickingPlugin`] handle picking and how should it handle transparent pixels
1924
#[derive(Debug, Clone, Copy, Reflect)]
25+
#[reflect(Debug)]
2026
pub enum SpritePickingMode {
2127
/// Even if a sprite is picked on a transparent pixel, it should still count within the backend.
2228
/// Only consider the rect of a given sprite.
@@ -30,6 +36,12 @@ pub enum SpritePickingMode {
3036
#[derive(Resource, Reflect)]
3137
#[reflect(Resource, Default)]
3238
pub struct SpritePickingSettings {
39+
/// When set to `true` sprite picking will only consider cameras marked with
40+
/// [`SpritePickingCamera`] and entities marked with [`PickingBehavior`]. `false` by default.
41+
///
42+
/// This setting is provided to give you fine-grained control over which cameras and entities
43+
/// should be used by the sprite picking backend at runtime.
44+
pub require_markers: bool,
3345
/// Should the backend count transparent pixels as part of the sprite for picking purposes or should it use the bounding box of the sprite alone.
3446
///
3547
/// Defaults to an inclusive alpha threshold of 0.1
@@ -39,6 +51,7 @@ pub struct SpritePickingSettings {
3951
impl Default for SpritePickingSettings {
4052
fn default() -> Self {
4153
Self {
54+
require_markers: false,
4255
picking_mode: SpritePickingMode::AlphaThreshold(0.1),
4356
}
4457
}
@@ -50,13 +63,24 @@ pub struct SpritePickingPlugin;
5063
impl Plugin for SpritePickingPlugin {
5164
fn build(&self, app: &mut App) {
5265
app.init_resource::<SpritePickingSettings>()
66+
.register_type::<(
67+
SpritePickingCamera,
68+
SpritePickingMode,
69+
SpritePickingSettings,
70+
)>()
5371
.add_systems(PreUpdate, sprite_picking.in_set(PickSet::Backend));
5472
}
5573
}
5674

5775
fn sprite_picking(
5876
pointers: Query<(&PointerId, &PointerLocation)>,
59-
cameras: Query<(Entity, &Camera, &GlobalTransform, &Projection)>,
77+
cameras: Query<(
78+
Entity,
79+
&Camera,
80+
&GlobalTransform,
81+
&Projection,
82+
Has<SpritePickingCamera>,
83+
)>,
6084
primary_window: Query<Entity, With<PrimaryWindow>>,
6185
images: Res<Assets<Image>>,
6286
texture_atlas_layout: Res<Assets<TextureAtlasLayout>>,
@@ -73,7 +97,8 @@ fn sprite_picking(
7397
let mut sorted_sprites: Vec<_> = sprite_query
7498
.iter()
7599
.filter_map(|(entity, sprite, transform, picking_behavior, vis)| {
76-
if !transform.affine().is_nan() && vis.get() {
100+
let marker_requirement = !settings.require_markers || picking_behavior.is_some();
101+
if !transform.affine().is_nan() && vis.get() && marker_requirement {
77102
Some((entity, sprite, transform, picking_behavior))
78103
} else {
79104
None
@@ -92,11 +117,14 @@ fn sprite_picking(
92117
pointer_location.location().map(|loc| (pointer, loc))
93118
}) {
94119
let mut blocked = false;
95-
let Some((cam_entity, camera, cam_transform, Projection::Orthographic(cam_ortho))) =
120+
let Some((cam_entity, camera, cam_transform, Projection::Orthographic(cam_ortho), _)) =
96121
cameras
97122
.iter()
98-
.filter(|(_, camera, _, _)| camera.is_active)
99-
.find(|(_, camera, _, _)| {
123+
.filter(|(_, camera, _, _, cam_can_pick)| {
124+
let marker_requirement = !settings.require_markers || *cam_can_pick;
125+
camera.is_active && marker_requirement
126+
})
127+
.find(|(_, camera, _, _, _)| {
100128
camera
101129
.target
102130
.normalize(primary_window)

examples/picking/sprite_picking.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
5555
let i = (anchor_index % 3) as f32;
5656
let j = (anchor_index / 3) as f32;
5757

58-
// spawn black square behind sprite to show anchor point
58+
// Spawn black square behind sprite to show anchor point
5959
commands
6060
.spawn((
6161
Sprite::from_color(Color::BLACK, sprite_size),

0 commit comments

Comments
 (0)