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`.
This commit is contained in:
parent
b20e23dd41
commit
0a9740c18f
@ -188,9 +188,12 @@ pub mod prelude {
|
||||
};
|
||||
}
|
||||
|
||||
/// An optional component that overrides default picking behavior for an entity, allowing you to
|
||||
/// make an entity non-hoverable, or allow items below it to be hovered. See the documentation on
|
||||
/// the fields for more details.
|
||||
/// An optional component that marks an entity as usable by a backend, and overrides default
|
||||
/// picking behavior for an entity.
|
||||
///
|
||||
/// This allows you to make an entity non-hoverable, or allow items below it to be hovered.
|
||||
///
|
||||
/// See the documentation on the fields for more details.
|
||||
#[derive(Component, Debug, Clone, Reflect, PartialEq, Eq)]
|
||||
#[reflect(Component, Default, Debug, PartialEq)]
|
||||
pub struct PickingBehavior {
|
||||
|
@ -15,8 +15,14 @@ use bevy_render::prelude::*;
|
||||
use bevy_transform::prelude::*;
|
||||
use bevy_window::PrimaryWindow;
|
||||
|
||||
/// A component that marks cameras that should be used in the [`SpritePickingPlugin`].
|
||||
#[derive(Debug, Clone, Default, Component, Reflect)]
|
||||
#[reflect(Debug, Default, Component)]
|
||||
pub struct SpritePickingCamera;
|
||||
|
||||
/// How should the [`SpritePickingPlugin`] handle picking and how should it handle transparent pixels
|
||||
#[derive(Debug, Clone, Copy, Reflect)]
|
||||
#[reflect(Debug)]
|
||||
pub enum SpritePickingMode {
|
||||
/// Even if a sprite is picked on a transparent pixel, it should still count within the backend.
|
||||
/// Only consider the rect of a given sprite.
|
||||
@ -30,6 +36,12 @@ pub enum SpritePickingMode {
|
||||
#[derive(Resource, Reflect)]
|
||||
#[reflect(Resource, Default)]
|
||||
pub struct SpritePickingSettings {
|
||||
/// When set to `true` sprite picking will only consider cameras marked with
|
||||
/// [`SpritePickingCamera`] and entities marked with [`PickingBehavior`]. `false` by default.
|
||||
///
|
||||
/// This setting is provided to give you fine-grained control over which cameras and entities
|
||||
/// should be used by the sprite picking backend at runtime.
|
||||
pub require_markers: bool,
|
||||
/// 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.
|
||||
///
|
||||
/// Defaults to an inclusive alpha threshold of 0.1
|
||||
@ -39,6 +51,7 @@ pub struct SpritePickingSettings {
|
||||
impl Default for SpritePickingSettings {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
require_markers: false,
|
||||
picking_mode: SpritePickingMode::AlphaThreshold(0.1),
|
||||
}
|
||||
}
|
||||
@ -50,13 +63,24 @@ pub struct SpritePickingPlugin;
|
||||
impl Plugin for SpritePickingPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.init_resource::<SpritePickingSettings>()
|
||||
.register_type::<(
|
||||
SpritePickingCamera,
|
||||
SpritePickingMode,
|
||||
SpritePickingSettings,
|
||||
)>()
|
||||
.add_systems(PreUpdate, sprite_picking.in_set(PickSet::Backend));
|
||||
}
|
||||
}
|
||||
|
||||
fn sprite_picking(
|
||||
pointers: Query<(&PointerId, &PointerLocation)>,
|
||||
cameras: Query<(Entity, &Camera, &GlobalTransform, &Projection)>,
|
||||
cameras: Query<(
|
||||
Entity,
|
||||
&Camera,
|
||||
&GlobalTransform,
|
||||
&Projection,
|
||||
Has<SpritePickingCamera>,
|
||||
)>,
|
||||
primary_window: Query<Entity, With<PrimaryWindow>>,
|
||||
images: Res<Assets<Image>>,
|
||||
texture_atlas_layout: Res<Assets<TextureAtlasLayout>>,
|
||||
@ -73,7 +97,8 @@ fn sprite_picking(
|
||||
let mut sorted_sprites: Vec<_> = sprite_query
|
||||
.iter()
|
||||
.filter_map(|(entity, sprite, transform, picking_behavior, vis)| {
|
||||
if !transform.affine().is_nan() && vis.get() {
|
||||
let marker_requirement = !settings.require_markers || picking_behavior.is_some();
|
||||
if !transform.affine().is_nan() && vis.get() && marker_requirement {
|
||||
Some((entity, sprite, transform, picking_behavior))
|
||||
} else {
|
||||
None
|
||||
@ -92,11 +117,14 @@ fn sprite_picking(
|
||||
pointer_location.location().map(|loc| (pointer, loc))
|
||||
}) {
|
||||
let mut blocked = false;
|
||||
let Some((cam_entity, camera, cam_transform, Projection::Orthographic(cam_ortho))) =
|
||||
let Some((cam_entity, camera, cam_transform, Projection::Orthographic(cam_ortho), _)) =
|
||||
cameras
|
||||
.iter()
|
||||
.filter(|(_, camera, _, _)| camera.is_active)
|
||||
.find(|(_, camera, _, _)| {
|
||||
.filter(|(_, camera, _, _, cam_can_pick)| {
|
||||
let marker_requirement = !settings.require_markers || *cam_can_pick;
|
||||
camera.is_active && marker_requirement
|
||||
})
|
||||
.find(|(_, camera, _, _, _)| {
|
||||
camera
|
||||
.target
|
||||
.normalize(primary_window)
|
||||
|
@ -55,7 +55,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
let i = (anchor_index % 3) as f32;
|
||||
let j = (anchor_index / 3) as f32;
|
||||
|
||||
// spawn black square behind sprite to show anchor point
|
||||
// Spawn black square behind sprite to show anchor point
|
||||
commands
|
||||
.spawn((
|
||||
Sprite::from_color(Color::BLACK, sprite_size),
|
||||
|
Loading…
Reference in New Issue
Block a user