-
Notifications
You must be signed in to change notification settings - Fork 34
Expand file tree
/
Copy pathpicking.rs
More file actions
147 lines (133 loc) · 4.71 KB
/
picking.rs
File metadata and controls
147 lines (133 loc) · 4.71 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use bevy::prelude::*;
use bevy_mod_outline::*;
/// Tag to track if an object is selected or not
#[derive(Component)]
struct Selected;
fn main() {
App::new()
.add_plugins((DefaultPlugins, MeshPickingPlugin, OutlinePlugin))
.add_systems(Startup, setup)
.add_systems(Update, rotate_selected)
.run();
}
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
mut window: Query<Entity, With<Window>>,
) {
let shapes = [
meshes.add(Cuboid::default()),
meshes.add(Torus::default()),
meshes.add(Capsule3d::default()),
meshes.add(Tetrahedron::default()),
];
let material = [
materials.add(StandardMaterial::from_color(Color::srgb_u8(255, 0, 0))),
materials.add(StandardMaterial::from_color(Color::srgb_u8(255, 255, 0))),
materials.add(StandardMaterial::from_color(Color::srgb_u8(0, 255, 0))),
materials.add(StandardMaterial::from_color(Color::srgb_u8(0, 0, 255))),
];
const DISTANCE: f32 = 1.5;
let positions = [
Vec3::new(-DISTANCE, DISTANCE, DISTANCE),
Vec3::new(DISTANCE, DISTANCE, DISTANCE),
Vec3::new(-DISTANCE, -DISTANCE, DISTANCE),
Vec3::new(DISTANCE, -DISTANCE, DISTANCE),
];
// Spawn shapes with outline and picking observer
for i in 0..shapes.len() {
commands
.spawn((
Mesh3d(shapes[i].clone()),
MeshMaterial3d(material[i].clone()),
Transform::from_translation(positions[i]),
OutlineVolume {
width: 5.0f32,
..default()
},
OutlineMode::FloodFlat,
Pickable::default(),
))
.observe(on_click);
}
// Add an observer to the window to respond to clicks that don't hit a mesh
if let Ok(entity) = window.single_mut() {
if let Ok(mut window) = commands.get_entity(entity) {
window.observe(on_click);
}
}
// Add ground
commands.spawn((
Mesh3d(shapes[0].clone()), // Reuse cuboid handle
MeshMaterial3d(materials.add(StandardMaterial::from_color(Color::WHITE))),
Transform::from_translation(Vec3::new(0.0, -5.0, 0.0))
.with_scale(Vec3::new(15.0, 1.0, 15.0)),
));
// Add a light source
commands.spawn((
PointLight {
color: Color::srgb_u8(255, 255, 192),
shadow_maps_enabled: true,
..default()
},
Transform::from_xyz(4.0, 8.0, 4.0),
));
// Add camera
commands.spawn((
Camera3d::default(),
Transform::from_xyz(0.0, 0.0, 15.0).looking_at(Vec3::ZERO, Vec3::Y),
));
}
/// Observer system that manages what pickable objects are selected
fn on_click(
mut event: On<Pointer<Click>>,
mut commands: Commands,
mut query: Query<(Entity, &mut OutlineVolume, Option<&Selected>)>,
keys: Res<ButtonInput<KeyCode>>,
) {
// Disable propagation to prevent observers other than the first in the queue from responding
event.propagate(false);
/// Helper function to deselect every selected entity
fn deselect_all(
commands: &mut Commands,
query: &mut Query<(Entity, &mut OutlineVolume, Option<&Selected>)>,
) {
for (entity, mut outline, selected) in query.iter_mut() {
if selected.is_some() {
if let Ok(mut entity) = commands.get_entity(entity) {
entity.remove::<Selected>();
outline.visible = false;
}
}
}
}
// Check if the user wants to select multiple objects
let multi_select = keys.pressed(KeyCode::ShiftLeft) || keys.pressed(KeyCode::ShiftRight);
// Deselect everything if the user does not want to select multiple objects
if !multi_select {
deselect_all(&mut commands, &mut query);
}
// Select a mesh
if let Ok((entity, mut outline, selected)) = query.get_mut(event.entity) {
if let Ok(mut entity) = commands.get_entity(entity) {
// When selecting multiple objects, allow clicking a selected object to deselect it.
if multi_select && selected.is_some() {
entity.remove::<Selected>();
outline.visible = false;
} else {
entity.insert(Selected);
outline.visible = true;
}
}
}
}
/// Rotate selected meshes
fn rotate_selected(mut query: Query<&mut Transform, With<Selected>>) {
const SPEED: f32 = 0.1;
for mut transform in query.iter_mut() {
transform.rotate_x(SPEED);
transform.rotate_y(SPEED * 1.5);
transform.rotate_z(SPEED * 0.5);
}
}