0

Working with bevy_mod_picking crate.

In the callback event when you pick a mesh the example code has:

  pub fn print_events(mut events: EventReader<PickingEvent>) {
  for event in events.iter() {
      match event {
          PickingEvent::Selection(e) => info!("selection  {:?}", e),
          PickingEvent::Hover(e) => info!("hover event {:?}", e),
          PickingEvent::Clicked(e) => info!("click {:?}", e),
        }
    }
  }

I need to access the Entity in all cases.
Clicked(e) is already an entity so I can modify it to use an Entity method:

PickingEvent::Clicked(e) => {
  info!("click {}", e.id());
},

The others are of type:

pub enum SelectionEvent {
    JustSelected(Entity),
    JustDeselected(Entity),
}

and

pub enum HoverEvent {
    JustEntered(Entity),
    JustLeft(Entity),
}

My question is two fold:

  1. When I run the program and select a mesh "selection JustSelected(1v0)" is printed.
    1 in this case is the Entity id but I don't understand the construction 1v0. What is v in this case? Is this some sort way of printing a tuple?

  2. Most importantly how do I modify the event handler to use the e argument of Selection(e)? As with Clicked(e) I would like to print the Entity id number of the selected mesh. Eg:

PickingEvent::Selection(e) => info!("selection  {}", e/magic grammar here/.id()),

EDIT - ADDED FULL CODE FOR CONTEXT

use bevy::{
  prelude::*,
  window::{PresentMode, RequestRedraw},
  winit::WinitSettings,
};

use bevy_mod_picking::*; // raycaster

fn main() {
  App::new()
  .insert_resource(Msaa { samples: 4 })
  .insert_resource(WinitSettings::desktop_app())
  .add_plugins(DefaultPlugins)
  .add_plugins(DefaultPickingPlugins)
  .add_plugin(DebugCursorPickingPlugin)
  .add_startup_system(setup)
  .add_system_to_stage(CoreStage::PostUpdate, print_events)
  .run();
}

pub fn print_events(mut events: EventReader<PickingEvent>) {
  for event in events.iter() {
      match event {
          PickingEvent::Selection(e) => info!("selection {:?}", e),
          PickingEvent::Hover(e) => info!("hover event {:?}", e),
          PickingEvent::Clicked(e) => {
            info!("click {}", e.id());
          },
      }
  }
}

fn setup(
  mut commands: Commands,
  asset_server: Res<AssetServer>,
  mut meshes: ResMut<Assets<Mesh>>,
  mut materials: ResMut<Assets<StandardMaterial>>,
) {
  let texture_handle = asset_server.load("Topo_small.png");
  let icosphere_handle = meshes.add(Mesh::from(shape::Icosphere { subdivisions: 8, radius: 2.0 }));
  let icosphere_material_handle = materials.add(StandardMaterial {
      base_color: Color::rgb(0.8, 0.7, 0.6),
      ..default()
  });

  // this material renders the texture normally
  let material_handle = materials.add(StandardMaterial {
    base_color_texture: Some(texture_handle.clone()),
    ..default()
  });

  // parent icosphere
  commands
      .spawn_bundle(PbrBundle {
          mesh: icosphere_handle.clone(),
          material: material_handle,
          transform: Transform::from_xyz(0.0, 0.0, 1.0),
          ..default()
      })
      .insert_bundle(PickableBundle::default());
    
  // light
  commands.spawn_bundle(PointLightBundle {
      transform: Transform::from_xyz(4.0, 5.0, -4.0),
      ..default()
  });
  // camera
  commands.spawn_bundle(PerspectiveCameraBundle {
      transform: Transform::from_xyz(5.0, 10.0, 10.0).looking_at(Vec3::ZERO, Vec3::Y),
      ..default()
  })
  .insert_bundle(PickingCameraBundle::default());
}
user2856949
  • 317
  • 2
  • 6
  • 2
    You can just [use a pattern assignment](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d92853fb778bb7ad97320b10d1b79a4a): `let (Selection(JustSelected(entity) | JustDeselected(entity)) | Hover(JustEntered(entity) | JustLeft(entity)) | Clicked(entity)) = event;` – eggyal May 16 '22 at 12:51

2 Answers2

0

Based on the comment I was actually able to get it by modifying the Selection match to:

  PickingEvent::Selection(e) => {
    if let SelectionEvent::JustSelected(e) = e { 
      info!("selection ID {}", e.id());
    }
    info!("selection {:?}", e)
  },
user2856949
  • 317
  • 2
  • 6
0

So I've run into the same problem and based on the proposed solution, I elaborated a bit more :

By using a Query, you can actually find the interactable entity (eg. hovered) and get its components from the Query:

pub fn select_and_change_color(
    mut events: EventReader<PickingEvent>,
    mut materials: ResMut<Assets<StandardMaterial>>,
    query: Query<(Entity, &Handle<StandardMaterial>)>,
) {
  for event in events.iter() {
      match event {
          PickingEvent::Selection(e) => {

              if let SelectionEvent::JustSelected(selected_entity) = e { 
                  
                  // retrieve the selected entity in the query
                  let (entity, material_handle) = query.get(*selected_entity).unwrap();
                  
                  // Now you have access to both the entity and one of its
                  // component: its material. You can for example change the color of it.
                  let material = materials.get_mut(material_handle).unwrap();
                  material.base_color = Color::rgb(0.9, 0.1, 0.9);
                  
              }
          },
          PickingEvent::Hover(e) => info!("hover event {:?}", e),
          PickingEvent::Clicked(e) => {
            info!("click {}", e.id());
          },
      }
  }
}

The parameter materials is a Unique mutable borrow of a resource and gives you a way to retrieve assets from the World.

Drusyc
  • 11
  • 5