1use bevy::{
9 camera_controller::free_camera::{FreeCamera, FreeCameraPlugin},
10 gizmos::transform_gizmo::{
11 TransformGizmoCamera, TransformGizmoFocus, TransformGizmoMode, TransformGizmoPlugin,
12 TransformGizmoSettings, TransformGizmoSpace,
13 },
14 picking::{pointer::PointerButton, Pickable},
15 prelude::*,
16};
17
18fn main() {
19 App::new()
20 .add_plugins((
21 DefaultPlugins,
22 FreeCameraPlugin,
23 MeshPickingPlugin,
24 TransformGizmoPlugin,
25 ))
26 .add_systems(Startup, setup)
27 .add_systems(Update, (gizmo_mode_keys, update_instructions))
28 .run();
29}
30
31fn setup(
32 mut commands: Commands,
33 mut meshes: ResMut<Assets<Mesh>>,
34 mut materials: ResMut<Assets<StandardMaterial>>,
35) {
36 commands.spawn((
38 Text::new(
39 "Click an object to select it\n1: Translate | 2: Rotate | 3: Scale | X: World/Local space",
40 ),
41 Node {
42 position_type: PositionType::Absolute,
43 top: px(12),
44 left: px(12),
45 ..default()
46 },
47 InstructionsText,
48 ));
49
50 commands.spawn((
52 Mesh3d(meshes.add(Plane3d::default().mesh().size(10.0, 10.0))),
53 MeshMaterial3d(materials.add(Color::srgb(0.3, 0.3, 0.3))),
54 Pickable::IGNORE,
55 ));
56
57 commands
60 .spawn((
61 Mesh3d(meshes.add(Cuboid::new(1.5, 0.15, 1.0))),
62 MeshMaterial3d(materials.add(Color::srgb(0.8, 0.3, 0.3))),
63 Transform::from_xyz(-2.0, 1.0, 0.0),
64 TransformGizmoFocus,
65 ))
66 .observe(on_click_select)
67 .with_children(|parent| {
68 parent.spawn((
70 Mesh3d(meshes.add(Cuboid::new(0.1, 0.85, 0.1))),
71 MeshMaterial3d(materials.add(Color::srgb(0.6, 0.2, 0.2))),
72 Transform::from_xyz(-0.6, -0.5, 0.4),
73 Pickable::IGNORE,
74 ));
75 parent.spawn((
76 Mesh3d(meshes.add(Cuboid::new(0.1, 0.85, 0.1))),
77 MeshMaterial3d(materials.add(Color::srgb(0.6, 0.2, 0.2))),
78 Transform::from_xyz(0.6, -0.5, 0.4),
79 Pickable::IGNORE,
80 ));
81 parent.spawn((
82 Mesh3d(meshes.add(Cuboid::new(0.1, 0.85, 0.1))),
83 MeshMaterial3d(materials.add(Color::srgb(0.6, 0.2, 0.2))),
84 Transform::from_xyz(-0.6, -0.5, -0.4),
85 Pickable::IGNORE,
86 ));
87 parent.spawn((
88 Mesh3d(meshes.add(Cuboid::new(0.1, 0.85, 0.1))),
89 MeshMaterial3d(materials.add(Color::srgb(0.6, 0.2, 0.2))),
90 Transform::from_xyz(0.6, -0.5, -0.4),
91 Pickable::IGNORE,
92 ));
93 });
94
95 commands
97 .spawn((
98 Mesh3d(meshes.add(Cuboid::new(1.0, 1.0, 1.0))),
99 MeshMaterial3d(materials.add(Color::srgb(0.3, 0.8, 0.3))),
100 Transform::from_xyz(2.0, 0.5, 0.0),
101 ))
102 .observe(on_click_select);
103
104 commands.spawn((
106 DirectionalLight {
107 shadow_maps_enabled: true,
108 ..default()
109 },
110 Transform::from_rotation(Quat::from_euler(EulerRot::XYZ, -0.8, 0.4, 0.0)),
111 ));
112
113 commands.spawn((
115 Camera3d::default(),
116 Transform::from_xyz(0.0, 4.0, 8.0).looking_at(Vec3::ZERO, Vec3::Y),
117 FreeCamera::default(),
118 TransformGizmoCamera,
119 ));
120}
121
122fn on_click_select(
123 click: On<Pointer<Click>>,
124 mut commands: Commands,
125 existing: Query<Entity, With<TransformGizmoFocus>>,
126) {
127 if click.button != PointerButton::Primary {
128 return;
129 }
130 for e in &existing {
132 commands.entity(e).remove::<TransformGizmoFocus>();
133 }
134 commands.entity(click.entity).insert(TransformGizmoFocus);
136}
137
138fn gizmo_mode_keys(
141 keyboard: Res<ButtonInput<KeyCode>>,
142 mut settings: ResMut<TransformGizmoSettings>,
143) {
144 if keyboard.just_pressed(KeyCode::Digit1) {
145 settings.mode = TransformGizmoMode::Translate;
146 }
147 if keyboard.just_pressed(KeyCode::Digit2) {
148 settings.mode = TransformGizmoMode::Rotate;
149 }
150 if keyboard.just_pressed(KeyCode::Digit3) {
151 settings.mode = TransformGizmoMode::Scale;
152 }
153 if keyboard.just_pressed(KeyCode::KeyX) {
154 settings.space = match settings.space {
155 TransformGizmoSpace::World => TransformGizmoSpace::Local,
156 TransformGizmoSpace::Local => TransformGizmoSpace::World,
157 };
158 }
159}
160
161#[derive(Component)]
162struct InstructionsText;
163
164fn update_instructions(
165 settings: Res<TransformGizmoSettings>,
166 mut text: Single<&mut Text, With<InstructionsText>>,
167) {
168 let mode_str = match settings.mode {
169 TransformGizmoMode::Translate => "Translate",
170 TransformGizmoMode::Rotate => "Rotate",
171 TransformGizmoMode::Scale => "Scale",
172 };
173 let space_str = match settings.space {
174 TransformGizmoSpace::World => "World",
175 TransformGizmoSpace::Local => "Local",
176 };
177 text.0 = format!(
178 "Click an object to select it\n1: Translate | 2: Rotate | 3: Scale | X: World/Local space\nMode: {mode_str} | Space: {space_str}"
179 );
180}