Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/examples/ui/ui_transform.rs
6595 views
1
//! An example demonstrating how to translate, rotate and scale UI elements.
2
use bevy::color::palettes::css::DARK_GRAY;
3
use bevy::color::palettes::css::RED;
4
use bevy::color::palettes::css::YELLOW;
5
use bevy::prelude::*;
6
use core::f32::consts::FRAC_PI_8;
7
8
fn main() {
9
App::new()
10
.add_plugins(DefaultPlugins)
11
.add_systems(Startup, setup)
12
.add_systems(Update, button_system)
13
.add_systems(Update, translation_system)
14
.run();
15
}
16
17
const NORMAL_BUTTON: Color = Color::WHITE;
18
const HOVERED_BUTTON: Color = Color::Srgba(YELLOW);
19
const PRESSED_BUTTON: Color = Color::Srgba(RED);
20
21
/// A button that rotates the target node
22
#[derive(Component)]
23
pub struct RotateButton(pub Rot2);
24
25
/// A button that scales the target node
26
#[derive(Component)]
27
pub struct ScaleButton(pub f32);
28
29
/// Marker component so the systems know which entities to translate, rotate and scale
30
#[derive(Component)]
31
pub struct TargetNode;
32
33
/// Handles button interactions
34
fn button_system(
35
mut interaction_query: Query<
36
(
37
&Interaction,
38
&mut BackgroundColor,
39
Option<&RotateButton>,
40
Option<&ScaleButton>,
41
),
42
(Changed<Interaction>, With<Button>),
43
>,
44
mut rotator_query: Query<&mut UiTransform, With<TargetNode>>,
45
) {
46
for (interaction, mut color, maybe_rotate, maybe_scale) in &mut interaction_query {
47
match *interaction {
48
Interaction::Pressed => {
49
*color = PRESSED_BUTTON.into();
50
if let Some(step) = maybe_rotate {
51
for mut transform in rotator_query.iter_mut() {
52
transform.rotation *= step.0;
53
}
54
}
55
if let Some(step) = maybe_scale {
56
for mut transform in rotator_query.iter_mut() {
57
transform.scale += step.0;
58
transform.scale =
59
transform.scale.clamp(Vec2::splat(0.25), Vec2::splat(3.0));
60
}
61
}
62
}
63
Interaction::Hovered => {
64
*color = HOVERED_BUTTON.into();
65
}
66
Interaction::None => {
67
*color = NORMAL_BUTTON.into();
68
}
69
}
70
}
71
}
72
73
// move the rotating panel when the arrow keys are pressed
74
fn translation_system(
75
time: Res<Time>,
76
input: Res<ButtonInput<KeyCode>>,
77
mut translation_query: Query<&mut UiTransform, With<TargetNode>>,
78
) {
79
let controls = [
80
(KeyCode::ArrowLeft, -Vec2::X),
81
(KeyCode::ArrowRight, Vec2::X),
82
(KeyCode::ArrowUp, -Vec2::Y),
83
(KeyCode::ArrowDown, Vec2::Y),
84
];
85
for &(key_code, direction) in &controls {
86
if input.pressed(key_code) {
87
for mut transform in translation_query.iter_mut() {
88
let d = direction * 50.0 * time.delta_secs();
89
let (Val::Px(x), Val::Px(y)) = (transform.translation.x, transform.translation.y)
90
else {
91
continue;
92
};
93
let x = (x + d.x).clamp(-150., 150.);
94
let y = (y + d.y).clamp(-150., 150.);
95
96
transform.translation = Val2::px(x, y);
97
}
98
}
99
}
100
}
101
102
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
103
// UI camera
104
commands.spawn(Camera2d);
105
106
// Root node filling the whole screen
107
commands.spawn((
108
Node {
109
width: percent(100),
110
height: percent(100),
111
align_items: AlignItems::Center,
112
justify_content: JustifyContent::Center,
113
..default()
114
},
115
BackgroundColor(Color::BLACK),
116
children![(
117
Node {
118
align_items: AlignItems::Center,
119
justify_content: JustifyContent::SpaceEvenly,
120
column_gap: px(25),
121
row_gap: px(25),
122
..default()
123
},
124
BackgroundColor(Color::BLACK),
125
children![
126
(
127
Node {
128
flex_direction: FlexDirection::Column,
129
justify_content: JustifyContent::Center,
130
row_gap: px(10),
131
column_gap: px(10),
132
padding: UiRect::all(px(10)),
133
..default()
134
},
135
BackgroundColor(Color::BLACK),
136
GlobalZIndex(1),
137
children![
138
(
139
Button,
140
Node {
141
height: px(50),
142
width: px(50),
143
align_items: AlignItems::Center,
144
justify_content: JustifyContent::Center,
145
..default()
146
},
147
BackgroundColor(Color::WHITE),
148
RotateButton(Rot2::radians(-FRAC_PI_8)),
149
children![(Text::new("<--"), TextColor(Color::BLACK),)]
150
),
151
(
152
Button,
153
Node {
154
height: px(50),
155
width: px(50),
156
align_items: AlignItems::Center,
157
justify_content: JustifyContent::Center,
158
..default()
159
},
160
BackgroundColor(Color::WHITE),
161
ScaleButton(-0.25),
162
children![(Text::new("-"), TextColor(Color::BLACK),)]
163
),
164
]
165
),
166
// Target node with its own set of buttons
167
(
168
Node {
169
flex_direction: FlexDirection::Column,
170
justify_content: JustifyContent::SpaceBetween,
171
align_items: AlignItems::Center,
172
width: px(300),
173
height: px(300),
174
..default()
175
},
176
BackgroundColor(DARK_GRAY.into()),
177
TargetNode,
178
children![
179
(
180
Button,
181
Node {
182
width: px(80),
183
height: px(80),
184
align_items: AlignItems::Center,
185
justify_content: JustifyContent::Center,
186
..default()
187
},
188
BackgroundColor(Color::WHITE),
189
children![(Text::new("Top"), TextColor(Color::BLACK))]
190
),
191
(
192
Node {
193
align_self: AlignSelf::Stretch,
194
justify_content: JustifyContent::SpaceBetween,
195
align_items: AlignItems::Center,
196
..default()
197
},
198
children![
199
(
200
Button,
201
Node {
202
width: px(80),
203
height: px(80),
204
align_items: AlignItems::Center,
205
justify_content: JustifyContent::Center,
206
..default()
207
},
208
BackgroundColor(Color::WHITE),
209
UiTransform::from_rotation(Rot2::radians(
210
-std::f32::consts::FRAC_PI_2
211
)),
212
children![(Text::new("Left"), TextColor(Color::BLACK),)]
213
),
214
(
215
Node {
216
width: px(100),
217
height: px(100),
218
..Default::default()
219
},
220
ImageNode {
221
image: asset_server.load("branding/icon.png"),
222
image_mode: NodeImageMode::Stretch,
223
..default()
224
}
225
),
226
(
227
Button,
228
Node {
229
width: px(80),
230
height: px(80),
231
align_items: AlignItems::Center,
232
justify_content: JustifyContent::Center,
233
..default()
234
},
235
UiTransform::from_rotation(Rot2::radians(
236
core::f32::consts::FRAC_PI_2
237
)),
238
BackgroundColor(Color::WHITE),
239
children![(Text::new("Right"), TextColor(Color::BLACK))]
240
),
241
]
242
),
243
(
244
Button,
245
Node {
246
width: px(80),
247
height: px(80),
248
align_items: AlignItems::Center,
249
justify_content: JustifyContent::Center,
250
..default()
251
},
252
BackgroundColor(Color::WHITE),
253
UiTransform::from_rotation(Rot2::radians(std::f32::consts::PI)),
254
children![(Text::new("Bottom"), TextColor(Color::BLACK),)]
255
),
256
]
257
),
258
// Right column of controls
259
(
260
Node {
261
flex_direction: FlexDirection::Column,
262
justify_content: JustifyContent::Center,
263
row_gap: px(10),
264
column_gap: px(10),
265
padding: UiRect::all(px(10)),
266
..default()
267
},
268
BackgroundColor(Color::BLACK),
269
GlobalZIndex(1),
270
children![
271
(
272
Button,
273
Node {
274
height: px(50),
275
width: px(50),
276
align_items: AlignItems::Center,
277
justify_content: JustifyContent::Center,
278
..default()
279
},
280
BackgroundColor(Color::WHITE),
281
RotateButton(Rot2::radians(FRAC_PI_8)),
282
children![(Text::new("-->"), TextColor(Color::BLACK),)]
283
),
284
(
285
Button,
286
Node {
287
height: px(50),
288
width: px(50),
289
align_items: AlignItems::Center,
290
justify_content: JustifyContent::Center,
291
..default()
292
},
293
BackgroundColor(Color::WHITE),
294
ScaleButton(0.25),
295
children![(Text::new("+"), TextColor(Color::BLACK),)]
296
),
297
]
298
)
299
]
300
)],
301
));
302
}
303
304