#[repr(C)]pub struct Vec2 {
pub x: f32,
pub y: f32,
}
Expand description
A 2-dimensional vector.
Fields§
§x: f32
§y: f32
Implementations§
Source§impl Vec2
impl Vec2
Sourcepub const NEG_INFINITY: Vec2
pub const NEG_INFINITY: Vec2
All f32::NEG_INFINITY
.
Sourcepub const fn new(x: f32, y: f32) -> Vec2
pub const fn new(x: f32, y: f32) -> Vec2
Creates a new vector.
Examples found in repository?
More examples
18const EXTENT: Vec2 = Vec2::new(1172.0, 520.0);
19const PLOT_SIZE: Vec2 = Vec2::splat(80.0);
20
21fn setup(mut commands: Commands) {
22 commands.spawn(Camera2d);
23
24 let text_font = TextFont {
25 font_size: 10.0,
26 ..default()
27 };
28
29 let chunks = [
30 // "In" row
31 EaseFunction::SineIn,
32 EaseFunction::QuadraticIn,
33 EaseFunction::CubicIn,
34 EaseFunction::QuarticIn,
35 EaseFunction::QuinticIn,
36 EaseFunction::SmoothStepIn,
37 EaseFunction::SmootherStepIn,
38 EaseFunction::CircularIn,
39 EaseFunction::ExponentialIn,
40 EaseFunction::ElasticIn,
41 EaseFunction::BackIn,
42 EaseFunction::BounceIn,
43 // "Out" row
44 EaseFunction::SineOut,
45 EaseFunction::QuadraticOut,
46 EaseFunction::CubicOut,
47 EaseFunction::QuarticOut,
48 EaseFunction::QuinticOut,
49 EaseFunction::SmoothStepOut,
50 EaseFunction::SmootherStepOut,
51 EaseFunction::CircularOut,
52 EaseFunction::ExponentialOut,
53 EaseFunction::ElasticOut,
54 EaseFunction::BackOut,
55 EaseFunction::BounceOut,
56 // "InOut" row
57 EaseFunction::SineInOut,
58 EaseFunction::QuadraticInOut,
59 EaseFunction::CubicInOut,
60 EaseFunction::QuarticInOut,
61 EaseFunction::QuinticInOut,
62 EaseFunction::SmoothStep,
63 EaseFunction::SmootherStep,
64 EaseFunction::CircularInOut,
65 EaseFunction::ExponentialInOut,
66 EaseFunction::ElasticInOut,
67 EaseFunction::BackInOut,
68 EaseFunction::BounceInOut,
69 // "Other" row
70 EaseFunction::Linear,
71 EaseFunction::Steps(4, JumpAt::End),
72 EaseFunction::Steps(4, JumpAt::Start),
73 EaseFunction::Steps(4, JumpAt::Both),
74 EaseFunction::Steps(4, JumpAt::None),
75 EaseFunction::Elastic(50.0),
76 ]
77 .chunks(COLS);
78
79 let max_rows = chunks.clone().count();
80
81 let half_extent = EXTENT / 2.;
82 let half_size = PLOT_SIZE / 2.;
83
84 for (row, functions) in chunks.enumerate() {
85 for (col, function) in functions.iter().enumerate() {
86 let color = Hsla::hsl(col as f32 / COLS as f32 * 360.0, 0.8, 0.75).into();
87 commands
88 .spawn((
89 EaseFunctionPlot(*function, color),
90 Transform::from_xyz(
91 -half_extent.x + EXTENT.x / (COLS - 1) as f32 * col as f32,
92 half_extent.y - EXTENT.y / (max_rows - 1) as f32 * row as f32,
93 0.0,
94 ),
95 ))
96 .with_children(|p| {
97 // Marks the y value on the right side of the plot
98 p.spawn((
99 Sprite::from_color(color, Vec2::splat(5.0)),
100 Transform::from_xyz(half_size.x + 5.0, -half_size.y, 0.0),
101 ));
102 // Marks the x and y value inside the plot
103 p.spawn((
104 Sprite::from_color(color, Vec2::splat(4.0)),
105 Transform::from_xyz(-half_size.x, -half_size.y, 0.0),
106 ));
107
108 // Label
109 p.spawn((
110 Text2d(format!("{:?}", function)),
111 text_font.clone(),
112 TextColor(color),
113 Transform::from_xyz(0.0, -half_size.y - 15.0, 0.0),
114 ));
115 });
116 }
117 }
118 commands.spawn((
119 Text::default(),
120 Node {
121 position_type: PositionType::Absolute,
122 top: Val::Px(12.0),
123 left: Val::Px(12.0),
124 ..default()
125 },
126 ));
127}
128
129fn display_curves(
130 mut gizmos: Gizmos,
131 ease_functions: Query<(&EaseFunctionPlot, &Transform, &Children)>,
132 mut transforms: Query<&mut Transform, Without<EaseFunctionPlot>>,
133 mut ui_text: Single<&mut Text>,
134 time: Res<Time>,
135) {
136 let samples = 100;
137 let duration = 2.5;
138 let time_margin = 0.5;
139
140 let now = ((time.elapsed_secs() % (duration + time_margin * 2.0) - time_margin) / duration)
141 .clamp(0.0, 1.0);
142
143 ui_text.0 = format!("Progress: {:.2}", now);
144
145 for (EaseFunctionPlot(function, color), transform, children) in &ease_functions {
146 let center = transform.translation.xy();
147 let half_size = PLOT_SIZE / 2.0;
148
149 // Draw a box around the curve
150 gizmos.linestrip_2d(
151 [
152 center + half_size,
153 center + half_size * Vec2::new(-1., 1.),
154 center + half_size * Vec2::new(-1., -1.),
155 center + half_size * Vec2::new(1., -1.),
156 center + half_size,
157 ],
158 color.darker(0.4),
159 );
160
161 // Draw the curve
162 let f = EasingCurve::new(0.0, 1.0, *function);
163 let drawn_curve = f
164 .by_ref()
165 .graph()
166 .map(|(x, y)| center - half_size + Vec2::new(x, y) * PLOT_SIZE);
167 gizmos.curve_2d(
168 &drawn_curve,
169 drawn_curve.domain().spaced_points(samples).unwrap(),
170 *color,
171 );
172
173 // Show progress along the curve for the current time
174 let y = f.sample(now).unwrap() * PLOT_SIZE.y;
175 transforms.get_mut(children[0]).unwrap().translation.y = -half_size.y + y;
176 transforms.get_mut(children[1]).unwrap().translation =
177 -half_size.extend(0.0) + Vec3::new(now * PLOT_SIZE.x, y, 0.0);
178
179 // Show horizontal bar at y value
180 gizmos.linestrip_2d(
181 [
182 center - half_size + Vec2::Y * y,
183 center - half_size + Vec2::new(PLOT_SIZE.x, y),
184 ],
185 color.darker(0.2),
186 );
187 }
188}
14const PADDLE_SIZE: Vec2 = Vec2::new(120.0, 20.0);
15const GAP_BETWEEN_PADDLE_AND_FLOOR: f32 = 60.0;
16const PADDLE_SPEED: f32 = 500.0;
17// How close can the paddle get to the wall
18const PADDLE_PADDING: f32 = 10.0;
19
20// We set the z-value of the ball to 1 so it renders on top in the case of overlapping sprites.
21const BALL_STARTING_POSITION: Vec3 = Vec3::new(0.0, -50.0, 1.0);
22const BALL_DIAMETER: f32 = 30.;
23const BALL_SPEED: f32 = 400.0;
24const INITIAL_BALL_DIRECTION: Vec2 = Vec2::new(0.5, -0.5);
25
26const WALL_THICKNESS: f32 = 10.0;
27// x coordinates
28const LEFT_WALL: f32 = -450.;
29const RIGHT_WALL: f32 = 450.;
30// y coordinates
31const BOTTOM_WALL: f32 = -300.;
32const TOP_WALL: f32 = 300.;
33
34const BRICK_SIZE: Vec2 = Vec2::new(100., 30.);
35// These values are exact
36const GAP_BETWEEN_PADDLE_AND_BRICKS: f32 = 270.0;
37const GAP_BETWEEN_BRICKS: f32 = 5.0;
38// These values are lower bounds, as the number of bricks is computed
39const GAP_BETWEEN_BRICKS_AND_CEILING: f32 = 20.0;
40const GAP_BETWEEN_BRICKS_AND_SIDES: f32 = 20.0;
41
42const SCOREBOARD_FONT_SIZE: f32 = 33.0;
43const SCOREBOARD_TEXT_PADDING: Val = Val::Px(5.0);
44
45const BACKGROUND_COLOR: Color = Color::srgb(0.9, 0.9, 0.9);
46const PADDLE_COLOR: Color = Color::srgb(0.3, 0.3, 0.7);
47const BALL_COLOR: Color = Color::srgb(1.0, 0.5, 0.5);
48const BRICK_COLOR: Color = Color::srgb(0.5, 0.5, 1.0);
49const WALL_COLOR: Color = Color::srgb(0.8, 0.8, 0.8);
50const TEXT_COLOR: Color = Color::srgb(0.5, 0.5, 1.0);
51const SCORE_COLOR: Color = Color::srgb(1.0, 0.5, 0.5);
52
53fn main() {
54 App::new()
55 .add_plugins(DefaultPlugins)
56 .add_plugins(
57 stepping::SteppingPlugin::default()
58 .add_schedule(Update)
59 .add_schedule(FixedUpdate)
60 .at(Val::Percent(35.0), Val::Percent(50.0)),
61 )
62 .insert_resource(Score(0))
63 .insert_resource(ClearColor(BACKGROUND_COLOR))
64 .add_event::<CollisionEvent>()
65 .add_systems(Startup, setup)
66 // Add our gameplay simulation systems to the fixed timestep schedule
67 // which runs at 64 Hz by default
68 .add_systems(
69 FixedUpdate,
70 (
71 apply_velocity,
72 move_paddle,
73 check_for_collisions,
74 play_collision_sound,
75 )
76 // `chain`ing systems together runs them in order
77 .chain(),
78 )
79 .add_systems(Update, update_scoreboard)
80 .run();
81}
82
83#[derive(Component)]
84struct Paddle;
85
86#[derive(Component)]
87struct Ball;
88
89#[derive(Component, Deref, DerefMut)]
90struct Velocity(Vec2);
91
92#[derive(Event, Default)]
93struct CollisionEvent;
94
95#[derive(Component)]
96struct Brick;
97
98#[derive(Resource, Deref)]
99struct CollisionSound(Handle<AudioSource>);
100
101// Default must be implemented to define this as a required component for the Wall component below
102#[derive(Component, Default)]
103struct Collider;
104
105// This is a collection of the components that define a "Wall" in our game
106#[derive(Component)]
107#[require(Sprite, Transform, Collider)]
108struct Wall;
109
110/// Which side of the arena is this wall located on?
111enum WallLocation {
112 Left,
113 Right,
114 Bottom,
115 Top,
116}
117
118impl WallLocation {
119 /// Location of the *center* of the wall, used in `transform.translation()`
120 fn position(&self) -> Vec2 {
121 match self {
122 WallLocation::Left => Vec2::new(LEFT_WALL, 0.),
123 WallLocation::Right => Vec2::new(RIGHT_WALL, 0.),
124 WallLocation::Bottom => Vec2::new(0., BOTTOM_WALL),
125 WallLocation::Top => Vec2::new(0., TOP_WALL),
126 }
127 }
128
129 /// (x, y) dimensions of the wall, used in `transform.scale()`
130 fn size(&self) -> Vec2 {
131 let arena_height = TOP_WALL - BOTTOM_WALL;
132 let arena_width = RIGHT_WALL - LEFT_WALL;
133 // Make sure we haven't messed up our constants
134 assert!(arena_height > 0.0);
135 assert!(arena_width > 0.0);
136
137 match self {
138 WallLocation::Left | WallLocation::Right => {
139 Vec2::new(WALL_THICKNESS, arena_height + WALL_THICKNESS)
140 }
141 WallLocation::Bottom | WallLocation::Top => {
142 Vec2::new(arena_width + WALL_THICKNESS, WALL_THICKNESS)
143 }
144 }
145 }
146}
147
148impl Wall {
149 // This "builder method" allows us to reuse logic across our wall entities,
150 // making our code easier to read and less prone to bugs when we change the logic
151 // Notice the use of Sprite and Transform alongside Wall, overwriting the default values defined for the required components
152 fn new(location: WallLocation) -> (Wall, Sprite, Transform) {
153 (
154 Wall,
155 Sprite::from_color(WALL_COLOR, Vec2::ONE),
156 Transform {
157 // We need to convert our Vec2 into a Vec3, by giving it a z-coordinate
158 // This is used to determine the order of our sprites
159 translation: location.position().extend(0.0),
160 // The z-scale of 2D objects must always be 1.0,
161 // or their ordering will be affected in surprising ways.
162 // See https://github.com/bevyengine/bevy/issues/4149
163 scale: location.size().extend(1.0),
164 ..default()
165 },
166 )
167 }
168}
169
170// This resource tracks the game's score
171#[derive(Resource, Deref, DerefMut)]
172struct Score(usize);
173
174#[derive(Component)]
175struct ScoreboardUi;
176
177// Add the game's entities to our world
178fn setup(
179 mut commands: Commands,
180 mut meshes: ResMut<Assets<Mesh>>,
181 mut materials: ResMut<Assets<ColorMaterial>>,
182 asset_server: Res<AssetServer>,
183) {
184 // Camera
185 commands.spawn(Camera2d);
186
187 // Sound
188 let ball_collision_sound = asset_server.load("sounds/breakout_collision.ogg");
189 commands.insert_resource(CollisionSound(ball_collision_sound));
190
191 // Paddle
192 let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
193
194 commands.spawn((
195 Sprite::from_color(PADDLE_COLOR, Vec2::ONE),
196 Transform {
197 translation: Vec3::new(0.0, paddle_y, 0.0),
198 scale: PADDLE_SIZE.extend(1.0),
199 ..default()
200 },
201 Paddle,
202 Collider,
203 ));
204
205 // Ball
206 commands.spawn((
207 Mesh2d(meshes.add(Circle::default())),
208 MeshMaterial2d(materials.add(BALL_COLOR)),
209 Transform::from_translation(BALL_STARTING_POSITION)
210 .with_scale(Vec2::splat(BALL_DIAMETER).extend(1.)),
211 Ball,
212 Velocity(INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED),
213 ));
214
215 // Scoreboard
216 commands.spawn((
217 Text::new("Score: "),
218 TextFont {
219 font_size: SCOREBOARD_FONT_SIZE,
220 ..default()
221 },
222 TextColor(TEXT_COLOR),
223 ScoreboardUi,
224 Node {
225 position_type: PositionType::Absolute,
226 top: SCOREBOARD_TEXT_PADDING,
227 left: SCOREBOARD_TEXT_PADDING,
228 ..default()
229 },
230 children![(
231 TextSpan::default(),
232 TextFont {
233 font_size: SCOREBOARD_FONT_SIZE,
234 ..default()
235 },
236 TextColor(SCORE_COLOR),
237 )],
238 ));
239
240 // Walls
241 commands.spawn(Wall::new(WallLocation::Left));
242 commands.spawn(Wall::new(WallLocation::Right));
243 commands.spawn(Wall::new(WallLocation::Bottom));
244 commands.spawn(Wall::new(WallLocation::Top));
245
246 // Bricks
247 let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES;
248 let bottom_edge_of_bricks = paddle_y + GAP_BETWEEN_PADDLE_AND_BRICKS;
249 let total_height_of_bricks = TOP_WALL - bottom_edge_of_bricks - GAP_BETWEEN_BRICKS_AND_CEILING;
250
251 assert!(total_width_of_bricks > 0.0);
252 assert!(total_height_of_bricks > 0.0);
253
254 // Given the space available, compute how many rows and columns of bricks we can fit
255 let n_columns = (total_width_of_bricks / (BRICK_SIZE.x + GAP_BETWEEN_BRICKS)).floor() as usize;
256 let n_rows = (total_height_of_bricks / (BRICK_SIZE.y + GAP_BETWEEN_BRICKS)).floor() as usize;
257 let n_vertical_gaps = n_columns - 1;
258
259 // Because we need to round the number of columns,
260 // the space on the top and sides of the bricks only captures a lower bound, not an exact value
261 let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0;
262 let left_edge_of_bricks = center_of_bricks
263 // Space taken up by the bricks
264 - (n_columns as f32 / 2.0 * BRICK_SIZE.x)
265 // Space taken up by the gaps
266 - n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS;
267
268 // In Bevy, the `translation` of an entity describes the center point,
269 // not its bottom-left corner
270 let offset_x = left_edge_of_bricks + BRICK_SIZE.x / 2.;
271 let offset_y = bottom_edge_of_bricks + BRICK_SIZE.y / 2.;
272
273 for row in 0..n_rows {
274 for column in 0..n_columns {
275 let brick_position = Vec2::new(
276 offset_x + column as f32 * (BRICK_SIZE.x + GAP_BETWEEN_BRICKS),
277 offset_y + row as f32 * (BRICK_SIZE.y + GAP_BETWEEN_BRICKS),
278 );
279
280 // brick
281 commands.spawn((
282 Sprite {
283 color: BRICK_COLOR,
284 ..default()
285 },
286 Transform {
287 translation: brick_position.extend(0.0),
288 scale: Vec3::new(BRICK_SIZE.x, BRICK_SIZE.y, 1.0),
289 ..default()
290 },
291 Brick,
292 Collider,
293 ));
294 }
295 }
296}
150const RECTANGLE: Rectangle = Rectangle {
151 half_size: Vec2::new(SMALL_2D, BIG_2D),
152};
153const CUBOID: Cuboid = Cuboid {
154 half_size: Vec3::new(BIG_3D, SMALL_3D, BIG_3D),
155};
156
157const CIRCLE: Circle = Circle { radius: BIG_2D };
158const SPHERE: Sphere = Sphere { radius: BIG_3D };
159
160const ELLIPSE: Ellipse = Ellipse {
161 half_size: Vec2::new(BIG_2D, SMALL_2D),
162};
163
164const TRIANGLE_2D: Triangle2d = Triangle2d {
165 vertices: [
166 Vec2::new(BIG_2D, 0.0),
167 Vec2::new(0.0, BIG_2D),
168 Vec2::new(-BIG_2D, 0.0),
169 ],
170};
171
172const TRIANGLE_3D: Triangle3d = Triangle3d {
173 vertices: [
174 Vec3::new(BIG_3D, 0.0, 0.0),
175 Vec3::new(0.0, BIG_3D, 0.0),
176 Vec3::new(-BIG_3D, 0.0, 0.0),
177 ],
178};
179
180const PLANE_2D: Plane2d = Plane2d { normal: Dir2::Y };
181const PLANE_3D: Plane3d = Plane3d {
182 normal: Dir3::Y,
183 half_size: Vec2::new(BIG_3D, BIG_3D),
184};
185
186const LINE2D: Line2d = Line2d { direction: Dir2::X };
187const LINE3D: Line3d = Line3d { direction: Dir3::X };
188
189const SEGMENT_2D: Segment2d = Segment2d {
190 vertices: [Vec2::new(-BIG_2D / 2., 0.), Vec2::new(BIG_2D / 2., 0.)],
191};
192
193const SEGMENT_3D: Segment3d = Segment3d {
194 vertices: [
195 Vec3::new(-BIG_3D / 2., 0., 0.),
196 Vec3::new(BIG_3D / 2., 0., 0.),
197 ],
198};
199
200const POLYLINE_2D: Polyline2d<4> = Polyline2d {
201 vertices: [
202 Vec2::new(-BIG_2D, -SMALL_2D),
203 Vec2::new(-SMALL_2D, SMALL_2D),
204 Vec2::new(SMALL_2D, -SMALL_2D),
205 Vec2::new(BIG_2D, SMALL_2D),
206 ],
207};
208const POLYLINE_3D: Polyline3d<4> = Polyline3d {
209 vertices: [
210 Vec3::new(-BIG_3D, -SMALL_3D, -SMALL_3D),
211 Vec3::new(SMALL_3D, SMALL_3D, 0.0),
212 Vec3::new(-SMALL_3D, -SMALL_3D, 0.0),
213 Vec3::new(BIG_3D, SMALL_3D, SMALL_3D),
214 ],
215};
216
217const POLYGON_2D: Polygon<5> = Polygon {
218 vertices: [
219 Vec2::new(-BIG_2D, -SMALL_2D),
220 Vec2::new(BIG_2D, -SMALL_2D),
221 Vec2::new(BIG_2D, SMALL_2D),
222 Vec2::new(0.0, 0.0),
223 Vec2::new(-BIG_2D, SMALL_2D),
224 ],
225};
226
227const REGULAR_POLYGON: RegularPolygon = RegularPolygon {
228 circumcircle: Circle { radius: BIG_2D },
229 sides: 5,
230};
231
232const CAPSULE_2D: Capsule2d = Capsule2d {
233 radius: SMALL_2D,
234 half_length: SMALL_2D,
235};
236const CAPSULE_3D: Capsule3d = Capsule3d {
237 radius: SMALL_3D,
238 half_length: SMALL_3D,
239};
240
241const CYLINDER: Cylinder = Cylinder {
242 radius: SMALL_3D,
243 half_height: SMALL_3D,
244};
245
246const CONE: Cone = Cone {
247 radius: BIG_3D,
248 height: BIG_3D,
249};
250
251const CONICAL_FRUSTUM: ConicalFrustum = ConicalFrustum {
252 radius_top: BIG_3D,
253 radius_bottom: SMALL_3D,
254 height: BIG_3D,
255};
256
257const ANNULUS: Annulus = Annulus {
258 inner_circle: Circle { radius: SMALL_2D },
259 outer_circle: Circle { radius: BIG_2D },
260};
261
262const TORUS: Torus = Torus {
263 minor_radius: SMALL_3D / 2.0,
264 major_radius: SMALL_3D * 1.5,
265};
266
267const TETRAHEDRON: Tetrahedron = Tetrahedron {
268 vertices: [
269 Vec3::new(-BIG_3D, 0.0, 0.0),
270 Vec3::new(BIG_3D, 0.0, 0.0),
271 Vec3::new(0.0, 0.0, -BIG_3D * 1.67),
272 Vec3::new(0.0, BIG_3D * 1.67, -BIG_3D * 0.5),
273 ],
274};
275
276const ARC: Arc2d = Arc2d {
277 radius: BIG_2D,
278 half_angle: std::f32::consts::FRAC_PI_4,
279};
280
281const CIRCULAR_SECTOR: CircularSector = CircularSector {
282 arc: Arc2d {
283 radius: BIG_2D,
284 half_angle: std::f32::consts::FRAC_PI_4,
285 },
286};
287
288const CIRCULAR_SEGMENT: CircularSegment = CircularSegment {
289 arc: Arc2d {
290 radius: BIG_2D,
291 half_angle: std::f32::consts::FRAC_PI_4,
292 },
293};
294
295fn setup_cameras(mut commands: Commands) {
296 let start_in_2d = true;
297 let make_camera = |is_active| Camera {
298 is_active,
299 ..Default::default()
300 };
301
302 commands.spawn((Camera2d, make_camera(start_in_2d)));
303
304 commands.spawn((
305 Camera3d::default(),
306 make_camera(!start_in_2d),
307 Transform::from_xyz(0.0, 10.0, 0.0).looking_at(Vec3::ZERO, Vec3::Z),
308 ));
309}
310
311fn setup_ambient_light(mut ambient_light: ResMut<AmbientLight>) {
312 ambient_light.brightness = 50.0;
313}
314
315fn setup_lights(mut commands: Commands) {
316 commands.spawn((
317 PointLight {
318 intensity: 5000.0,
319 ..default()
320 },
321 Transform::from_translation(Vec3::new(-LEFT_RIGHT_OFFSET_3D, 2.0, 0.0))
322 .looking_at(Vec3::new(-LEFT_RIGHT_OFFSET_3D, 0.0, 0.0), Vec3::Y),
323 ));
324}
325
326/// Marker component for header text
327#[derive(Debug, Clone, Component, Default, Reflect)]
328pub struct HeaderText;
329
330/// Marker component for header node
331#[derive(Debug, Clone, Component, Default, Reflect)]
332pub struct HeaderNode;
333
334fn update_active_cameras(
335 state: Res<State<CameraActive>>,
336 camera_2d: Single<(Entity, &mut Camera), With<Camera2d>>,
337 camera_3d: Single<(Entity, &mut Camera), (With<Camera3d>, Without<Camera2d>)>,
338 mut text: Query<&mut UiTargetCamera, With<HeaderNode>>,
339) {
340 let (entity_2d, mut cam_2d) = camera_2d.into_inner();
341 let (entity_3d, mut cam_3d) = camera_3d.into_inner();
342 let is_camera_2d_active = matches!(*state.get(), CameraActive::Dim2);
343
344 cam_2d.is_active = is_camera_2d_active;
345 cam_3d.is_active = !is_camera_2d_active;
346
347 let active_camera = if is_camera_2d_active {
348 entity_2d
349 } else {
350 entity_3d
351 };
352
353 text.iter_mut().for_each(|mut target_camera| {
354 *target_camera = UiTargetCamera(active_camera);
355 });
356}
357
358fn switch_cameras(current: Res<State<CameraActive>>, mut next: ResMut<NextState<CameraActive>>) {
359 let next_state = match current.get() {
360 CameraActive::Dim2 => CameraActive::Dim3,
361 CameraActive::Dim3 => CameraActive::Dim2,
362 };
363 next.set(next_state);
364}
365
366fn setup_text(mut commands: Commands, cameras: Query<(Entity, &Camera)>) {
367 let active_camera = cameras
368 .iter()
369 .find_map(|(entity, camera)| camera.is_active.then_some(entity))
370 .expect("run condition ensures existence");
371 commands.spawn((
372 HeaderNode,
373 Node {
374 justify_self: JustifySelf::Center,
375 top: Val::Px(5.0),
376 ..Default::default()
377 },
378 UiTargetCamera(active_camera),
379 children![(
380 Text::default(),
381 HeaderText,
382 TextLayout::new_with_justify(JustifyText::Center),
383 children![
384 TextSpan::new("Primitive: "),
385 TextSpan(format!("{text}", text = PrimitiveSelected::default())),
386 TextSpan::new("\n\n"),
387 TextSpan::new(
388 "Press 'C' to switch between 2D and 3D mode\n\
389 Press 'Up' or 'Down' to switch to the next/previous primitive",
390 ),
391 TextSpan::new("\n\n"),
392 TextSpan::new("(If nothing is displayed, there's no rendering support yet)",),
393 ]
394 )],
395 ));
396}
397
398fn update_text(
399 primitive_state: Res<State<PrimitiveSelected>>,
400 header: Query<Entity, With<HeaderText>>,
401 mut writer: TextUiWriter,
402) {
403 let new_text = format!("{text}", text = primitive_state.get());
404 header.iter().for_each(|header_text| {
405 if let Some(mut text) = writer.get_text(header_text, 2) {
406 (*text).clone_from(&new_text);
407 };
408 });
409}
410
411fn switch_to_next_primitive(
412 current: Res<State<PrimitiveSelected>>,
413 mut next: ResMut<NextState<PrimitiveSelected>>,
414) {
415 let next_state = current.get().next();
416 next.set(next_state);
417}
418
419fn switch_to_previous_primitive(
420 current: Res<State<PrimitiveSelected>>,
421 mut next: ResMut<NextState<PrimitiveSelected>>,
422) {
423 let next_state = current.get().previous();
424 next.set(next_state);
425}
426
427fn in_mode(active: CameraActive) -> impl Fn(Res<State<CameraActive>>) -> bool {
428 move |state| *state.get() == active
429}
430
431fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time: Res<Time>) {
432 const POSITION: Vec2 = Vec2::new(-LEFT_RIGHT_OFFSET_2D, 0.0);
71fn spawn_curve_sprite<T: CurveColor>(commands: &mut Commands, y: f32, points: [T; 4]) {
72 commands.spawn((
73 Sprite::sized(Vec2::new(75., 75.)),
74 Transform::from_xyz(0., y, 0.),
75 Curve(CubicBezier::new([points]).to_curve().unwrap()),
76 ));
77}
78
79fn spawn_mixed_sprite<T: MixedColor>(commands: &mut Commands, y: f32, colors: [T; 4]) {
80 commands.spawn((
81 Transform::from_xyz(0., y, 0.),
82 Sprite::sized(Vec2::new(75., 75.)),
83 Mixed(colors),
84 ));
85}
- examples/math/custom_primitives.rs
- examples/camera/2d_screen_shake.rs
- examples/window/window_resizing.rs
- examples/3d/motion_blur.rs
- tests/window/minimizing.rs
- tests/window/resizing.rs
- examples/camera/first_person_view_model.rs
- examples/ecs/parallel_query.rs
- examples/shader/compute_shader_game_of_life.rs
- examples/remote/server.rs
- examples/ecs/fallible_params.rs
- examples/2d/wireframe_2d.rs
- examples/stress_tests/many_sprites.rs
- examples/testbed/2d.rs
- examples/2d/2d_shapes.rs
- examples/math/bounding_2d.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/stress_tests/many_text2d.rs
- examples/2d/cpu_draw.rs
- examples/gizmos/2d_gizmos.rs
- examples/picking/sprite_picking.rs
- examples/asset/repeated_texture.rs
- examples/testbed/ui.rs
- examples/2d/sprite_slice.rs
- examples/2d/mesh2d_repeated_texture.rs
- examples/gizmos/3d_gizmos.rs
- examples/3d/auto_exposure.rs
- examples/stress_tests/many_cubes.rs
- examples/2d/text2d.rs
- examples/2d/sprite_scale.rs
- examples/ui/box_shadow.rs
- examples/3d/camera_sub_view.rs
Sourcepub const fn splat(v: f32) -> Vec2
pub const fn splat(v: f32) -> Vec2
Creates a vector with all elements set to v
.
Examples found in repository?
19const PLOT_SIZE: Vec2 = Vec2::splat(80.0);
20
21fn setup(mut commands: Commands) {
22 commands.spawn(Camera2d);
23
24 let text_font = TextFont {
25 font_size: 10.0,
26 ..default()
27 };
28
29 let chunks = [
30 // "In" row
31 EaseFunction::SineIn,
32 EaseFunction::QuadraticIn,
33 EaseFunction::CubicIn,
34 EaseFunction::QuarticIn,
35 EaseFunction::QuinticIn,
36 EaseFunction::SmoothStepIn,
37 EaseFunction::SmootherStepIn,
38 EaseFunction::CircularIn,
39 EaseFunction::ExponentialIn,
40 EaseFunction::ElasticIn,
41 EaseFunction::BackIn,
42 EaseFunction::BounceIn,
43 // "Out" row
44 EaseFunction::SineOut,
45 EaseFunction::QuadraticOut,
46 EaseFunction::CubicOut,
47 EaseFunction::QuarticOut,
48 EaseFunction::QuinticOut,
49 EaseFunction::SmoothStepOut,
50 EaseFunction::SmootherStepOut,
51 EaseFunction::CircularOut,
52 EaseFunction::ExponentialOut,
53 EaseFunction::ElasticOut,
54 EaseFunction::BackOut,
55 EaseFunction::BounceOut,
56 // "InOut" row
57 EaseFunction::SineInOut,
58 EaseFunction::QuadraticInOut,
59 EaseFunction::CubicInOut,
60 EaseFunction::QuarticInOut,
61 EaseFunction::QuinticInOut,
62 EaseFunction::SmoothStep,
63 EaseFunction::SmootherStep,
64 EaseFunction::CircularInOut,
65 EaseFunction::ExponentialInOut,
66 EaseFunction::ElasticInOut,
67 EaseFunction::BackInOut,
68 EaseFunction::BounceInOut,
69 // "Other" row
70 EaseFunction::Linear,
71 EaseFunction::Steps(4, JumpAt::End),
72 EaseFunction::Steps(4, JumpAt::Start),
73 EaseFunction::Steps(4, JumpAt::Both),
74 EaseFunction::Steps(4, JumpAt::None),
75 EaseFunction::Elastic(50.0),
76 ]
77 .chunks(COLS);
78
79 let max_rows = chunks.clone().count();
80
81 let half_extent = EXTENT / 2.;
82 let half_size = PLOT_SIZE / 2.;
83
84 for (row, functions) in chunks.enumerate() {
85 for (col, function) in functions.iter().enumerate() {
86 let color = Hsla::hsl(col as f32 / COLS as f32 * 360.0, 0.8, 0.75).into();
87 commands
88 .spawn((
89 EaseFunctionPlot(*function, color),
90 Transform::from_xyz(
91 -half_extent.x + EXTENT.x / (COLS - 1) as f32 * col as f32,
92 half_extent.y - EXTENT.y / (max_rows - 1) as f32 * row as f32,
93 0.0,
94 ),
95 ))
96 .with_children(|p| {
97 // Marks the y value on the right side of the plot
98 p.spawn((
99 Sprite::from_color(color, Vec2::splat(5.0)),
100 Transform::from_xyz(half_size.x + 5.0, -half_size.y, 0.0),
101 ));
102 // Marks the x and y value inside the plot
103 p.spawn((
104 Sprite::from_color(color, Vec2::splat(4.0)),
105 Transform::from_xyz(-half_size.x, -half_size.y, 0.0),
106 ));
107
108 // Label
109 p.spawn((
110 Text2d(format!("{:?}", function)),
111 text_font.clone(),
112 TextColor(color),
113 Transform::from_xyz(0.0, -half_size.y - 15.0, 0.0),
114 ));
115 });
116 }
117 }
118 commands.spawn((
119 Text::default(),
120 Node {
121 position_type: PositionType::Absolute,
122 top: Val::Px(12.0),
123 left: Val::Px(12.0),
124 ..default()
125 },
126 ));
127}
More examples
85static LIGHTMAPS: [(&str, Rect); 5] = [
86 (
87 "Plane",
88 uv_rect_opengl(Vec2::splat(0.026), Vec2::splat(0.710)),
89 ),
90 (
91 "SheenChair_fabric",
92 uv_rect_opengl(vec2(0.7864, 0.02377), vec2(0.1910, 0.1912)),
93 ),
94 (
95 "SheenChair_label",
96 uv_rect_opengl(vec2(0.275, -0.016), vec2(0.858, 0.486)),
97 ),
98 (
99 "SheenChair_metal",
100 uv_rect_opengl(vec2(0.998, 0.506), vec2(-0.029, -0.067)),
101 ),
102 (
103 "SheenChair_wood",
104 uv_rect_opengl(vec2(0.787, 0.257), vec2(0.179, 0.177)),
105 ),
106];
107
108static SPHERE_UV_RECT: Rect = uv_rect_opengl(vec2(0.788, 0.484), Vec2::splat(0.062));
221fn spawn_decals(commands: &mut Commands, asset_server: &AssetServer) {
222 let image = asset_server.load("branding/icon.png");
223
224 commands.spawn((
225 ClusteredDecal {
226 image: image.clone(),
227 // Tint with red.
228 tag: 1,
229 },
230 calculate_initial_decal_transform(vec3(1.0, 3.0, 5.0), Vec3::ZERO, Vec2::splat(1.1)),
231 Selection::DecalA,
232 ));
233
234 commands.spawn((
235 ClusteredDecal {
236 image: image.clone(),
237 // Tint with blue.
238 tag: 2,
239 },
240 calculate_initial_decal_transform(vec3(-2.0, -1.0, 4.0), Vec3::ZERO, Vec2::splat(2.0)),
241 Selection::DecalB,
242 ));
243}
10fn spawn_system(mut commands: Commands, asset_server: Res<AssetServer>) {
11 commands.spawn(Camera2d);
12 let texture = asset_server.load("branding/icon.png");
13
14 // We're seeding the PRNG here to make this example deterministic for testing purposes.
15 // This isn't strictly required in practical use unless you need your app to be deterministic.
16 let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
17 for z in 0..128 {
18 commands.spawn((
19 Sprite::from_image(texture.clone()),
20 Transform::from_scale(Vec3::splat(0.1))
21 .with_translation(Vec2::splat(0.0).extend(z as f32)),
22 Velocity(20.0 * Vec2::new(rng.r#gen::<f32>() - 0.5, rng.r#gen::<f32>() - 0.5)),
23 ));
24 }
25}
322fn aabb_cast_system(
323 mut gizmos: Gizmos,
324 time: Res<Time>,
325 mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
326) {
327 let ray_cast = get_and_draw_ray(&mut gizmos, &time);
328 let aabb_cast = AabbCast2d {
329 aabb: Aabb2d::new(Vec2::ZERO, Vec2::splat(15.)),
330 ray: ray_cast,
331 };
332
333 for (volume, mut intersects) in volumes.iter_mut() {
334 let toi = match *volume {
335 CurrentVolume::Aabb(a) => aabb_cast.aabb_collision_at(a),
336 CurrentVolume::Circle(_) => None,
337 };
338
339 **intersects = toi.is_some();
340 if let Some(toi) = toi {
341 gizmos.rect_2d(
342 aabb_cast.ray.ray.origin + *aabb_cast.ray.ray.direction * toi,
343 aabb_cast.aabb.half_size() * 2.,
344 LIME,
345 );
346 }
347 }
348}
349
350fn bounding_circle_cast_system(
351 mut gizmos: Gizmos,
352 time: Res<Time>,
353 mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
354) {
355 let ray_cast = get_and_draw_ray(&mut gizmos, &time);
356 let circle_cast = BoundingCircleCast {
357 circle: BoundingCircle::new(Vec2::ZERO, 15.),
358 ray: ray_cast,
359 };
360
361 for (volume, mut intersects) in volumes.iter_mut() {
362 let toi = match *volume {
363 CurrentVolume::Aabb(_) => None,
364 CurrentVolume::Circle(c) => circle_cast.circle_collision_at(c),
365 };
366
367 **intersects = toi.is_some();
368 if let Some(toi) = toi {
369 gizmos.circle_2d(
370 circle_cast.ray.ray.origin + *circle_cast.ray.ray.direction * toi,
371 circle_cast.circle.radius(),
372 LIME,
373 );
374 }
375 }
376}
377
378fn get_intersection_position(time: &Time) -> Vec2 {
379 let x = ops::cos(0.8 * time.elapsed_secs()) * 250.;
380 let y = ops::sin(0.4 * time.elapsed_secs()) * 100.;
381 Vec2::new(x, y)
382}
383
384fn aabb_intersection_system(
385 mut gizmos: Gizmos,
386 time: Res<Time>,
387 mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
388) {
389 let center = get_intersection_position(&time);
390 let aabb = Aabb2d::new(center, Vec2::splat(50.));
391 gizmos.rect_2d(center, aabb.half_size() * 2., YELLOW);
392
393 for (volume, mut intersects) in volumes.iter_mut() {
394 let hit = match volume {
395 CurrentVolume::Aabb(a) => aabb.intersects(a),
396 CurrentVolume::Circle(c) => aabb.intersects(c),
397 };
398
399 **intersects = hit;
400 }
401}
- examples/camera/first_person_view_model.rs
- examples/math/custom_primitives.rs
- examples/stress_tests/many_sprites.rs
- examples/audio/spatial_audio_2d.rs
- examples/games/contributors.rs
- examples/testbed/2d.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/stress_tests/many_text2d.rs
- examples/2d/bloom_2d.rs
- examples/3d/ssr.rs
- examples/time/virtual_time.rs
- examples/gizmos/2d_gizmos.rs
- examples/picking/sprite_picking.rs
- examples/2d/mesh2d_alpha_mode.rs
- examples/testbed/ui.rs
- examples/2d/sprite_slice.rs
- examples/gizmos/3d_gizmos.rs
- examples/stress_tests/many_cubes.rs
- examples/stress_tests/bevymark.rs
- examples/games/breakout.rs
- examples/games/desk_toy.rs
- examples/ui/box_shadow.rs
Sourcepub fn map<F>(self, f: F) -> Vec2
pub fn map<F>(self, f: F) -> Vec2
Returns a vector containing each element of self
modified by a mapping function f
.
Sourcepub fn select(mask: BVec2, if_true: Vec2, if_false: Vec2) -> Vec2
pub fn select(mask: BVec2, if_true: Vec2, if_false: Vec2) -> Vec2
Creates a vector from the elements in if_true
and if_false
, selecting which to use
for each element of self
.
A true element in the mask uses the corresponding element from if_true
, and false
uses the element from if_false
.
Sourcepub const fn from_array(a: [f32; 2]) -> Vec2
pub const fn from_array(a: [f32; 2]) -> Vec2
Creates a new vector from an array.
Sourcepub const fn from_slice(slice: &[f32]) -> Vec2
pub const fn from_slice(slice: &[f32]) -> Vec2
Creates a vector from the first 2 values in slice
.
§Panics
Panics if slice
is less than 2 elements long.
Sourcepub fn write_to_slice(self, slice: &mut [f32])
pub fn write_to_slice(self, slice: &mut [f32])
Writes the elements of self
to the first 2 elements in slice
.
§Panics
Panics if slice
is less than 2 elements long.
Sourcepub const fn extend(self, z: f32) -> Vec3
pub const fn extend(self, z: f32) -> Vec3
Creates a 3D vector from self
and the given z
value.
Examples found in repository?
More examples
296fn rotate_camera(
297 time: Res<Time>,
298 mut camera_query: Query<&mut Transform, With<Camera3d>>,
299 app_status: Res<AppStatus>,
300) {
301 if !app_status.rotating {
302 return;
303 }
304
305 for mut transform in camera_query.iter_mut() {
306 transform.translation = Vec2::from_angle(time.delta_secs() * PI / 5.0)
307 .rotate(transform.translation.xz())
308 .extend(transform.translation.y)
309 .xzy();
310 transform.look_at(Vec3::ZERO, Vec3::Y);
311 }
312}
350fn rotate_camera(
351 mut camera_query: Query<&mut Transform, With<Camera3d>>,
352 time: Res<Time>,
353 app_status: Res<AppStatus>,
354) {
355 if !app_status.rotating {
356 return;
357 }
358
359 for mut transform in camera_query.iter_mut() {
360 transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_secs())
361 .rotate(transform.translation.xz())
362 .extend(transform.translation.y)
363 .xzy();
364 transform.look_at(Vec3::ZERO, Vec3::Y);
365 }
366}
65fn system(config: Res<Config>, time: Res<Time>, mut draw: Gizmos) {
66 if !config.fancy {
67 for _ in 0..(config.line_count / SYSTEM_COUNT) {
68 draw.line(Vec3::NEG_Y, Vec3::Y, Color::BLACK);
69 }
70 } else {
71 for i in 0..(config.line_count / SYSTEM_COUNT) {
72 let angle = i as f32 / (config.line_count / SYSTEM_COUNT) as f32 * TAU;
73
74 let vector = Vec2::from(ops::sin_cos(angle)).extend(ops::sin(time.elapsed_secs()));
75 let start_color = LinearRgba::rgb(vector.x, vector.z, 0.5);
76 let end_color = LinearRgba::rgb(-vector.z, -vector.y, 0.5);
77
78 draw.line_gradient(vector, -vector, start_color, end_color);
79 }
80 }
81}
- examples/games/breakout.rs
- examples/ecs/parallel_query.rs
- examples/camera/2d_top_down_camera.rs
- examples/2d/rotation.rs
- examples/2d/2d_viewport_to_world.rs
- examples/movement/physics_in_fixed_timestep.rs
- examples/stress_tests/many_sprites.rs
- examples/testbed/2d.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/stress_tests/many_text2d.rs
- examples/animation/easing_functions.rs
- examples/time/virtual_time.rs
- examples/gizmos/3d_gizmos.rs
- examples/games/desk_toy.rs
- examples/2d/text2d.rs
Sourcepub fn dot(self, rhs: Vec2) -> f32
pub fn dot(self, rhs: Vec2) -> f32
Computes the dot product of self
and rhs
.
Examples found in repository?
195fn rotate_to_player_system(
196 time: Res<Time>,
197 mut query: Query<(&RotateToPlayer, &mut Transform), Without<Player>>,
198 player_transform: Single<&Transform, With<Player>>,
199) {
200 // Get the player translation in 2D
201 let player_translation = player_transform.translation.xy();
202
203 for (config, mut enemy_transform) in &mut query {
204 // Get the enemy ship forward vector in 2D (already unit length)
205 let enemy_forward = (enemy_transform.rotation * Vec3::Y).xy();
206
207 // Get the vector from the enemy ship to the player ship in 2D and normalize it.
208 let to_player = (player_translation - enemy_transform.translation.xy()).normalize();
209
210 // Get the dot product between the enemy forward vector and the direction to the player.
211 let forward_dot_player = enemy_forward.dot(to_player);
212
213 // If the dot product is approximately 1.0 then the enemy is already facing the player and
214 // we can early out.
215 if (forward_dot_player - 1.0).abs() < f32::EPSILON {
216 continue;
217 }
218
219 // Get the right vector of the enemy ship in 2D (already unit length)
220 let enemy_right = (enemy_transform.rotation * Vec3::X).xy();
221
222 // Get the dot product of the enemy right vector and the direction to the player ship.
223 // If the dot product is negative them we need to rotate counter clockwise, if it is
224 // positive we need to rotate clockwise. Note that `copysign` will still return 1.0 if the
225 // dot product is 0.0 (because the player is directly behind the enemy, so perpendicular
226 // with the right vector).
227 let right_dot_player = enemy_right.dot(to_player);
228
229 // Determine the sign of rotation from the right dot player. We need to negate the sign
230 // here as the 2D bevy co-ordinate system rotates around +Z, which is pointing out of the
231 // screen. Due to the right hand rule, positive rotation around +Z is counter clockwise and
232 // negative is clockwise.
233 let rotation_sign = -f32::copysign(1.0, right_dot_player);
234
235 // Limit rotation so we don't overshoot the target. We need to convert our dot product to
236 // an angle here so we can get an angle of rotation to clamp against.
237 let max_angle = ops::acos(forward_dot_player.clamp(-1.0, 1.0)); // Clamp acos for safety
238
239 // Calculate angle of rotation with limit
240 let rotation_angle =
241 rotation_sign * (config.rotation_speed * time.delta_secs()).min(max_angle);
242
243 // Rotate the enemy to face the player
244 enemy_transform.rotate_z(rotation_angle);
245 }
246}
Sourcepub fn dot_into_vec(self, rhs: Vec2) -> Vec2
pub fn dot_into_vec(self, rhs: Vec2) -> Vec2
Returns a vector where every component is the dot product of self
and rhs
.
Sourcepub fn min(self, rhs: Vec2) -> Vec2
pub fn min(self, rhs: Vec2) -> Vec2
Returns a vector containing the minimum values for each element of self
and rhs
.
In other words this computes [self.x.min(rhs.x), self.y.min(rhs.y), ..]
.
Examples found in repository?
323 fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
324 let isometry = isometry.into();
325
326 // The center of the circle at the center of the right wing of the heart
327 let circle_center = isometry.rotation * Vec2::new(self.radius, 0.0);
328 // The maximum X and Y positions of the two circles of the wings of the heart.
329 let max_circle = circle_center.abs() + Vec2::splat(self.radius);
330 // Since the two circles of the heart are mirrored around the origin, the minimum position is the negative of the maximum.
331 let min_circle = -max_circle;
332
333 // The position of the tip at the bottom of the heart
334 let tip_position = isometry.rotation * Vec2::new(0.0, -self.radius * (1. + SQRT_2));
335
336 Aabb2d {
337 min: isometry.translation + min_circle.min(tip_position),
338 max: isometry.translation + max_circle.max(tip_position),
339 }
340 }
Sourcepub fn max(self, rhs: Vec2) -> Vec2
pub fn max(self, rhs: Vec2) -> Vec2
Returns a vector containing the maximum values for each element of self
and rhs
.
In other words this computes [self.x.max(rhs.x), self.y.max(rhs.y), ..]
.
Examples found in repository?
323 fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
324 let isometry = isometry.into();
325
326 // The center of the circle at the center of the right wing of the heart
327 let circle_center = isometry.rotation * Vec2::new(self.radius, 0.0);
328 // The maximum X and Y positions of the two circles of the wings of the heart.
329 let max_circle = circle_center.abs() + Vec2::splat(self.radius);
330 // Since the two circles of the heart are mirrored around the origin, the minimum position is the negative of the maximum.
331 let min_circle = -max_circle;
332
333 // The position of the tip at the bottom of the heart
334 let tip_position = isometry.rotation * Vec2::new(0.0, -self.radius * (1. + SQRT_2));
335
336 Aabb2d {
337 min: isometry.translation + min_circle.min(tip_position),
338 max: isometry.translation + max_circle.max(tip_position),
339 }
340 }
Sourcepub fn clamp(self, min: Vec2, max: Vec2) -> Vec2
pub fn clamp(self, min: Vec2, max: Vec2) -> Vec2
Component-wise clamping of values, similar to f32::clamp
.
Each element in min
must be less-or-equal to the corresponding element in max
.
§Panics
Will panic if min
is greater than max
when glam_assert
is enabled.
Sourcepub fn min_element(self) -> f32
pub fn min_element(self) -> f32
Returns the horizontal minimum of self
.
In other words this computes min(x, y, ..)
.
Sourcepub fn max_element(self) -> f32
pub fn max_element(self) -> f32
Returns the horizontal maximum of self
.
In other words this computes max(x, y, ..)
.
Sourcepub fn element_sum(self) -> f32
pub fn element_sum(self) -> f32
Returns the sum of all elements of self
.
In other words, this computes self.x + self.y + ..
.
Sourcepub fn element_product(self) -> f32
pub fn element_product(self) -> f32
Returns the product of all elements of self
.
In other words, this computes self.x * self.y * ..
.
Sourcepub fn cmpeq(self, rhs: Vec2) -> BVec2
pub fn cmpeq(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a ==
comparison for each element of
self
and rhs
.
In other words, this computes [self.x == rhs.x, self.y == rhs.y, ..]
for all
elements.
Sourcepub fn cmpne(self, rhs: Vec2) -> BVec2
pub fn cmpne(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a !=
comparison for each element of
self
and rhs
.
In other words this computes [self.x != rhs.x, self.y != rhs.y, ..]
for all
elements.
Sourcepub fn cmpge(self, rhs: Vec2) -> BVec2
pub fn cmpge(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a >=
comparison for each element of
self
and rhs
.
In other words this computes [self.x >= rhs.x, self.y >= rhs.y, ..]
for all
elements.
Sourcepub fn cmpgt(self, rhs: Vec2) -> BVec2
pub fn cmpgt(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a >
comparison for each element of
self
and rhs
.
In other words this computes [self.x > rhs.x, self.y > rhs.y, ..]
for all
elements.
Sourcepub fn cmple(self, rhs: Vec2) -> BVec2
pub fn cmple(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a <=
comparison for each element of
self
and rhs
.
In other words this computes [self.x <= rhs.x, self.y <= rhs.y, ..]
for all
elements.
Sourcepub fn cmplt(self, rhs: Vec2) -> BVec2
pub fn cmplt(self, rhs: Vec2) -> BVec2
Returns a vector mask containing the result of a <
comparison for each element of
self
and rhs
.
In other words this computes [self.x < rhs.x, self.y < rhs.y, ..]
for all
elements.
Sourcepub fn abs(self) -> Vec2
pub fn abs(self) -> Vec2
Returns a vector containing the absolute value of each element of self
.
Examples found in repository?
323 fn aabb_2d(&self, isometry: impl Into<Isometry2d>) -> Aabb2d {
324 let isometry = isometry.into();
325
326 // The center of the circle at the center of the right wing of the heart
327 let circle_center = isometry.rotation * Vec2::new(self.radius, 0.0);
328 // The maximum X and Y positions of the two circles of the wings of the heart.
329 let max_circle = circle_center.abs() + Vec2::splat(self.radius);
330 // Since the two circles of the heart are mirrored around the origin, the minimum position is the negative of the maximum.
331 let min_circle = -max_circle;
332
333 // The position of the tip at the bottom of the heart
334 let tip_position = isometry.rotation * Vec2::new(0.0, -self.radius * (1. + SQRT_2));
335
336 Aabb2d {
337 min: isometry.translation + min_circle.min(tip_position),
338 max: isometry.translation + max_circle.max(tip_position),
339 }
340 }
Sourcepub fn signum(self) -> Vec2
pub fn signum(self) -> Vec2
Returns a vector with elements representing the sign of self
.
1.0
if the number is positive,+0.0
orINFINITY
-1.0
if the number is negative,-0.0
orNEG_INFINITY
NAN
if the number isNAN
Sourcepub fn copysign(self, rhs: Vec2) -> Vec2
pub fn copysign(self, rhs: Vec2) -> Vec2
Returns a vector with signs of rhs
and the magnitudes of self
.
Sourcepub fn is_negative_bitmask(self) -> u32
pub fn is_negative_bitmask(self) -> u32
Returns a bitmask with the lowest 2 bits set to the sign bits from the elements of self
.
A negative element results in a 1
bit and a positive element in a 0
bit. Element x
goes
into the first lowest bit, element y
into the second, etc.
Sourcepub fn is_finite(self) -> bool
pub fn is_finite(self) -> bool
Returns true
if, and only if, all elements are finite. If any element is either
NaN
, positive or negative infinity, this will return false
.
Sourcepub fn is_finite_mask(self) -> BVec2
pub fn is_finite_mask(self) -> BVec2
Performs is_finite
on each element of self, returning a vector mask of the results.
In other words, this computes [x.is_finite(), y.is_finite(), ...]
.
Sourcepub fn is_nan_mask(self) -> BVec2
pub fn is_nan_mask(self) -> BVec2
Performs is_nan
on each element of self, returning a vector mask of the results.
In other words, this computes [x.is_nan(), y.is_nan(), ...]
.
Sourcepub fn length(self) -> f32
pub fn length(self) -> f32
Computes the length of self
.
Examples found in repository?
245fn start_drag(
246 mut commands: Commands,
247 cursor_world_pos: Res<CursorWorldPos>,
248 bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
249) {
250 // If the cursor is not within the primary window skip this system
251 let Some(cursor_world_pos) = cursor_world_pos.0 else {
252 return;
253 };
254
255 // Get the offset from the cursor to the Bevy logo sprite
256 let drag_offset = bevy_logo_transform.translation.truncate() - cursor_world_pos;
257
258 // If the cursor is within the Bevy logo radius start the drag operation and remember the offset of the cursor from the origin
259 if drag_offset.length() < BEVY_LOGO_RADIUS {
260 commands.insert_resource(DragOperation(drag_offset));
261 }
262}
263
264/// Stop the current drag operation
265fn end_drag(mut commands: Commands) {
266 commands.remove_resource::<DragOperation>();
267}
268
269/// Drag the Bevy logo
270fn drag(
271 drag_offset: Res<DragOperation>,
272 cursor_world_pos: Res<CursorWorldPos>,
273 time: Res<Time>,
274 mut bevy_transform: Single<&mut Transform, With<BevyLogo>>,
275 mut q_pupils: Query<&mut Pupil>,
276) {
277 // If the cursor is not within the primary window skip this system
278 let Some(cursor_world_pos) = cursor_world_pos.0 else {
279 return;
280 };
281
282 // Calculate the new translation of the Bevy logo based on cursor and drag offset
283 let new_translation = cursor_world_pos + drag_offset.0;
284
285 // Calculate how fast we are dragging the Bevy logo (unit/second)
286 let drag_velocity =
287 (new_translation - bevy_transform.translation.truncate()) / time.delta_secs();
288
289 // Update the translation of Bevy logo transform to new translation
290 bevy_transform.translation = new_translation.extend(bevy_transform.translation.z);
291
292 // Add the cursor drag velocity in the opposite direction to each pupil.
293 // Remember pupils are using local coordinates to move. So when the Bevy logo moves right they need to move left to
294 // simulate inertia, otherwise they will move fixed to the parent.
295 for mut pupil in &mut q_pupils {
296 pupil.velocity -= drag_velocity;
297 }
298}
299
300/// Quit when the user right clicks the Bevy logo
301fn quit(
302 cursor_world_pos: Res<CursorWorldPos>,
303 mut app_exit: EventWriter<AppExit>,
304 bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
305) {
306 // If the cursor is not within the primary window skip this system
307 let Some(cursor_world_pos) = cursor_world_pos.0 else {
308 return;
309 };
310
311 // If the cursor is within the Bevy logo radius send the [`AppExit`] event to quit the app
312 if bevy_logo_transform
313 .translation
314 .truncate()
315 .distance(cursor_world_pos)
316 < BEVY_LOGO_RADIUS
317 {
318 app_exit.write(AppExit::Success);
319 }
320}
321
322/// Enable transparency for the window and make it on top
323fn toggle_transparency(
324 mut commands: Commands,
325 mut window_transparency: ResMut<WindowTransparency>,
326 mut q_instructions_text: Query<&mut Visibility, With<InstructionsText>>,
327 mut primary_window: Single<&mut Window, With<PrimaryWindow>>,
328) {
329 // Toggle the window transparency resource
330 window_transparency.0 = !window_transparency.0;
331
332 // Show or hide the instructions text
333 for mut visibility in &mut q_instructions_text {
334 *visibility = if window_transparency.0 {
335 Visibility::Hidden
336 } else {
337 Visibility::Visible
338 };
339 }
340
341 // Remove the primary window's decorations (e.g. borders), make it always on top of other desktop windows, and set the clear color to transparent
342 // only if window transparency is enabled
343 let clear_color;
344 (
345 primary_window.decorations,
346 primary_window.window_level,
347 clear_color,
348 ) = if window_transparency.0 {
349 (false, WindowLevel::AlwaysOnTop, Color::NONE)
350 } else {
351 (true, WindowLevel::Normal, WINDOW_CLEAR_COLOR)
352 };
353
354 // Set the clear color
355 commands.insert_resource(ClearColor(clear_color));
356}
357
358/// Move the pupils and bounce them around
359fn move_pupils(time: Res<Time>, mut q_pupils: Query<(&mut Pupil, &mut Transform)>) {
360 for (mut pupil, mut transform) in &mut q_pupils {
361 // The wiggle radius is how much the pupil can move within the eye
362 let wiggle_radius = pupil.eye_radius - pupil.pupil_radius;
363 // Store the Z component
364 let z = transform.translation.z;
365 // Truncate the Z component to make the calculations be on [`Vec2`]
366 let mut translation = transform.translation.truncate();
367 // Decay the pupil velocity
368 pupil.velocity *= ops::powf(0.04f32, time.delta_secs());
369 // Move the pupil
370 translation += pupil.velocity * time.delta_secs();
371 // If the pupil hit the outside border of the eye, limit the translation to be within the wiggle radius and invert the velocity.
372 // This is not physically accurate but it's good enough for the googly eyes effect.
373 if translation.length() > wiggle_radius {
374 translation = translation.normalize() * wiggle_radius;
375 // Invert and decrease the velocity of the pupil when it bounces
376 pupil.velocity *= -0.75;
377 }
378 // Update the entity transform with the new translation after reading the Z component
379 transform.translation = translation.extend(z);
380 }
381}
Sourcepub fn length_squared(self) -> f32
pub fn length_squared(self) -> f32
Computes the squared length of self
.
This is faster than length()
as it avoids a square root operation.
Sourcepub fn length_recip(self) -> f32
pub fn length_recip(self) -> f32
Computes 1.0 / length()
.
For valid results, self
must not be of length zero.
Examples found in repository?
394fn process_move_input(
395 mut selections: Query<(&mut Transform, &Selection)>,
396 mouse_buttons: Res<ButtonInput<MouseButton>>,
397 mouse_motion: Res<AccumulatedMouseMotion>,
398 app_status: Res<AppStatus>,
399) {
400 // Only process drags when movement is selected.
401 if !mouse_buttons.pressed(MouseButton::Left) || app_status.drag_mode != DragMode::Move {
402 return;
403 }
404
405 for (mut transform, selection) in &mut selections {
406 if app_status.selection != *selection {
407 continue;
408 }
409
410 let position = transform.translation;
411
412 // Convert to spherical coordinates.
413 let radius = position.length();
414 let mut theta = acos(position.y / radius);
415 let mut phi = position.z.signum() * acos(position.x * position.xz().length_recip());
416
417 // Camera movement is the inverse of object movement.
418 let (phi_factor, theta_factor) = match *selection {
419 Selection::Camera => (1.0, -1.0),
420 Selection::DecalA | Selection::DecalB => (-1.0, 1.0),
421 };
422
423 // Adjust the spherical coordinates. Clamp the inclination to (0, π).
424 phi += phi_factor * mouse_motion.delta.x * MOVE_SPEED;
425 theta = f32::clamp(
426 theta + theta_factor * mouse_motion.delta.y * MOVE_SPEED,
427 0.001,
428 PI - 0.001,
429 );
430
431 // Convert spherical coordinates back to Cartesian coordinates.
432 transform.translation =
433 radius * vec3(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
434
435 // Look at the center, but preserve the previous roll angle.
436 let roll = transform.rotation.to_euler(EulerRot::YXZ).2;
437 transform.look_at(Vec3::ZERO, Vec3::Y);
438 let (yaw, pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
439 transform.rotation = Quat::from_euler(EulerRot::YXZ, yaw, pitch, roll);
440 }
441}
Sourcepub fn distance(self, rhs: Vec2) -> f32
pub fn distance(self, rhs: Vec2) -> f32
Computes the Euclidean distance between two points in space.
Examples found in repository?
220fn update_cursor_hit_test(
221 cursor_world_pos: Res<CursorWorldPos>,
222 mut primary_window: Single<&mut Window, With<PrimaryWindow>>,
223 bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
224) {
225 // If the window has decorations (e.g. a border) then it should be clickable
226 if primary_window.decorations {
227 primary_window.cursor_options.hit_test = true;
228 return;
229 }
230
231 // If the cursor is not within the window we don't need to update whether the window is clickable or not
232 let Some(cursor_world_pos) = cursor_world_pos.0 else {
233 return;
234 };
235
236 // If the cursor is within the radius of the Bevy logo make the window clickable otherwise the window is not clickable
237 primary_window.cursor_options.hit_test = bevy_logo_transform
238 .translation
239 .truncate()
240 .distance(cursor_world_pos)
241 < BEVY_LOGO_RADIUS;
242}
243
244/// Start the drag operation and record the offset we started dragging from
245fn start_drag(
246 mut commands: Commands,
247 cursor_world_pos: Res<CursorWorldPos>,
248 bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
249) {
250 // If the cursor is not within the primary window skip this system
251 let Some(cursor_world_pos) = cursor_world_pos.0 else {
252 return;
253 };
254
255 // Get the offset from the cursor to the Bevy logo sprite
256 let drag_offset = bevy_logo_transform.translation.truncate() - cursor_world_pos;
257
258 // If the cursor is within the Bevy logo radius start the drag operation and remember the offset of the cursor from the origin
259 if drag_offset.length() < BEVY_LOGO_RADIUS {
260 commands.insert_resource(DragOperation(drag_offset));
261 }
262}
263
264/// Stop the current drag operation
265fn end_drag(mut commands: Commands) {
266 commands.remove_resource::<DragOperation>();
267}
268
269/// Drag the Bevy logo
270fn drag(
271 drag_offset: Res<DragOperation>,
272 cursor_world_pos: Res<CursorWorldPos>,
273 time: Res<Time>,
274 mut bevy_transform: Single<&mut Transform, With<BevyLogo>>,
275 mut q_pupils: Query<&mut Pupil>,
276) {
277 // If the cursor is not within the primary window skip this system
278 let Some(cursor_world_pos) = cursor_world_pos.0 else {
279 return;
280 };
281
282 // Calculate the new translation of the Bevy logo based on cursor and drag offset
283 let new_translation = cursor_world_pos + drag_offset.0;
284
285 // Calculate how fast we are dragging the Bevy logo (unit/second)
286 let drag_velocity =
287 (new_translation - bevy_transform.translation.truncate()) / time.delta_secs();
288
289 // Update the translation of Bevy logo transform to new translation
290 bevy_transform.translation = new_translation.extend(bevy_transform.translation.z);
291
292 // Add the cursor drag velocity in the opposite direction to each pupil.
293 // Remember pupils are using local coordinates to move. So when the Bevy logo moves right they need to move left to
294 // simulate inertia, otherwise they will move fixed to the parent.
295 for mut pupil in &mut q_pupils {
296 pupil.velocity -= drag_velocity;
297 }
298}
299
300/// Quit when the user right clicks the Bevy logo
301fn quit(
302 cursor_world_pos: Res<CursorWorldPos>,
303 mut app_exit: EventWriter<AppExit>,
304 bevy_logo_transform: Single<&Transform, With<BevyLogo>>,
305) {
306 // If the cursor is not within the primary window skip this system
307 let Some(cursor_world_pos) = cursor_world_pos.0 else {
308 return;
309 };
310
311 // If the cursor is within the Bevy logo radius send the [`AppExit`] event to quit the app
312 if bevy_logo_transform
313 .translation
314 .truncate()
315 .distance(cursor_world_pos)
316 < BEVY_LOGO_RADIUS
317 {
318 app_exit.write(AppExit::Success);
319 }
320}
More examples
10fn main() {
11 App::new()
12 .add_plugins(DefaultPlugins)
13 .init_resource::<SpatialIndex>()
14 .add_systems(Startup, setup)
15 .add_systems(Update, (draw_shapes, handle_click))
16 // Observers are systems that run when an event is "triggered". This observer runs whenever
17 // `ExplodeMines` is triggered.
18 .add_observer(
19 |trigger: Trigger<ExplodeMines>,
20 mines: Query<&Mine>,
21 index: Res<SpatialIndex>,
22 mut commands: Commands| {
23 // You can access the trigger data via the `Observer`
24 let event = trigger.event();
25 // Access resources
26 for e in index.get_nearby(event.pos) {
27 // Run queries
28 let mine = mines.get(e).unwrap();
29 if mine.pos.distance(event.pos) < mine.size + event.radius {
30 // And queue commands, including triggering additional events
31 // Here we trigger the `Explode` event for entity `e`
32 commands.trigger_targets(Explode, e);
33 }
34 }
35 },
36 )
37 // This observer runs whenever the `Mine` component is added to an entity, and places it in a simple spatial index.
38 .add_observer(on_add_mine)
39 // This observer runs whenever the `Mine` component is removed from an entity (including despawning it)
40 // and removes it from the spatial index.
41 .add_observer(on_remove_mine)
42 .run();
43}
40fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
41 commands.spawn(Camera2d);
42
43 // Create an image that we are going to draw into
44 let mut image = Image::new_fill(
45 // 2D image of size 256x256
46 Extent3d {
47 width: IMAGE_WIDTH,
48 height: IMAGE_HEIGHT,
49 depth_or_array_layers: 1,
50 },
51 TextureDimension::D2,
52 // Initialize it with a beige color
53 &(css::BEIGE.to_u8_array()),
54 // Use the same encoding as the color we set
55 TextureFormat::Rgba8UnormSrgb,
56 RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD,
57 );
58
59 // To make it extra fancy, we can set the Alpha of each pixel,
60 // so that it fades out in a circular fashion.
61 for y in 0..IMAGE_HEIGHT {
62 for x in 0..IMAGE_WIDTH {
63 let center = Vec2::new(IMAGE_WIDTH as f32 / 2.0, IMAGE_HEIGHT as f32 / 2.0);
64 let max_radius = IMAGE_HEIGHT.min(IMAGE_WIDTH) as f32 / 2.0;
65 let r = Vec2::new(x as f32, y as f32).distance(center);
66 let a = 1.0 - (r / max_radius).clamp(0.0, 1.0);
67
68 // Here we will set the A value by accessing the raw data bytes.
69 // (it is the 4th byte of each pixel, as per our `TextureFormat`)
70
71 // Find our pixel by its coordinates
72 let pixel_bytes = image.pixel_bytes_mut(UVec3::new(x, y, 0)).unwrap();
73 // Convert our f32 to u8
74 pixel_bytes[3] = (a * u8::MAX as f32) as u8;
75 }
76 }
77
78 // Add it to Bevy's assets, so it can be used for rendering
79 // this will give us a handle we can use
80 // (to display it in a sprite, or as part of UI, etc.)
81 let handle = images.add(image);
82
83 // Create a sprite entity using our image
84 commands.spawn(Sprite::from_image(handle.clone()));
85 commands.insert_resource(MyProcGenImage(handle));
86
87 // We're seeding the PRNG here to make this example deterministic for testing purposes.
88 // This isn't strictly required in practical use unless you need your app to be deterministic.
89 let seeded_rng = ChaCha8Rng::seed_from_u64(19878367467712);
90 commands.insert_resource(SeededRng(seeded_rng));
91}
Sourcepub fn distance_squared(self, rhs: Vec2) -> f32
pub fn distance_squared(self, rhs: Vec2) -> f32
Compute the squared euclidean distance between two points in space.
Sourcepub fn div_euclid(self, rhs: Vec2) -> Vec2
pub fn div_euclid(self, rhs: Vec2) -> Vec2
Returns the element-wise quotient of [Euclidean division] of self
by rhs
.
Sourcepub fn rem_euclid(self, rhs: Vec2) -> Vec2
pub fn rem_euclid(self, rhs: Vec2) -> Vec2
Returns the element-wise remainder of Euclidean division of self
by rhs
.
Sourcepub fn normalize(self) -> Vec2
pub fn normalize(self) -> Vec2
Returns self
normalized to length 1.0.
For valid results, self
must be finite and not of length zero, nor very close to zero.
See also Self::try_normalize()
and Self::normalize_or_zero()
.
Panics
Will panic if the resulting normalized vector is not finite when glam_assert
is enabled.
Examples found in repository?
154fn snap_to_player_system(
155 mut query: Query<&mut Transform, (With<SnapToPlayer>, Without<Player>)>,
156 player_transform: Single<&Transform, With<Player>>,
157) {
158 // Get the player translation in 2D
159 let player_translation = player_transform.translation.xy();
160
161 for mut enemy_transform in &mut query {
162 // Get the vector from the enemy ship to the player ship in 2D and normalize it.
163 let to_player = (player_translation - enemy_transform.translation.xy()).normalize();
164
165 // Get the quaternion to rotate from the initial enemy facing direction to the direction
166 // facing the player
167 let rotate_to_player = Quat::from_rotation_arc(Vec3::Y, to_player.extend(0.));
168
169 // Rotate the enemy to face the player
170 enemy_transform.rotation = rotate_to_player;
171 }
172}
173
174/// Demonstrates rotating an enemy ship to face the player ship at a given rotation speed.
175///
176/// This method uses the vector dot product to determine if the enemy is facing the player and
177/// if not, which way to rotate to face the player. The dot product on two unit length vectors
178/// will return a value between -1.0 and +1.0 which tells us the following about the two vectors:
179///
180/// * If the result is 1.0 the vectors are pointing in the same direction, the angle between them is
181/// 0 degrees.
182/// * If the result is 0.0 the vectors are perpendicular, the angle between them is 90 degrees.
183/// * If the result is -1.0 the vectors are parallel but pointing in opposite directions, the angle
184/// between them is 180 degrees.
185/// * If the result is positive the vectors are pointing in roughly the same direction, the angle
186/// between them is greater than 0 and less than 90 degrees.
187/// * If the result is negative the vectors are pointing in roughly opposite directions, the angle
188/// between them is greater than 90 and less than 180 degrees.
189///
190/// It is possible to get the angle by taking the arc cosine (`acos`) of the dot product. It is
191/// often unnecessary to do this though. Beware than `acos` will return `NaN` if the input is less
192/// than -1.0 or greater than 1.0. This can happen even when working with unit vectors due to
193/// floating point precision loss, so it pays to clamp your dot product value before calling
194/// `acos`.
195fn rotate_to_player_system(
196 time: Res<Time>,
197 mut query: Query<(&RotateToPlayer, &mut Transform), Without<Player>>,
198 player_transform: Single<&Transform, With<Player>>,
199) {
200 // Get the player translation in 2D
201 let player_translation = player_transform.translation.xy();
202
203 for (config, mut enemy_transform) in &mut query {
204 // Get the enemy ship forward vector in 2D (already unit length)
205 let enemy_forward = (enemy_transform.rotation * Vec3::Y).xy();
206
207 // Get the vector from the enemy ship to the player ship in 2D and normalize it.
208 let to_player = (player_translation - enemy_transform.translation.xy()).normalize();
209
210 // Get the dot product between the enemy forward vector and the direction to the player.
211 let forward_dot_player = enemy_forward.dot(to_player);
212
213 // If the dot product is approximately 1.0 then the enemy is already facing the player and
214 // we can early out.
215 if (forward_dot_player - 1.0).abs() < f32::EPSILON {
216 continue;
217 }
218
219 // Get the right vector of the enemy ship in 2D (already unit length)
220 let enemy_right = (enemy_transform.rotation * Vec3::X).xy();
221
222 // Get the dot product of the enemy right vector and the direction to the player ship.
223 // If the dot product is negative them we need to rotate counter clockwise, if it is
224 // positive we need to rotate clockwise. Note that `copysign` will still return 1.0 if the
225 // dot product is 0.0 (because the player is directly behind the enemy, so perpendicular
226 // with the right vector).
227 let right_dot_player = enemy_right.dot(to_player);
228
229 // Determine the sign of rotation from the right dot player. We need to negate the sign
230 // here as the 2D bevy co-ordinate system rotates around +Z, which is pointing out of the
231 // screen. Due to the right hand rule, positive rotation around +Z is counter clockwise and
232 // negative is clockwise.
233 let rotation_sign = -f32::copysign(1.0, right_dot_player);
234
235 // Limit rotation so we don't overshoot the target. We need to convert our dot product to
236 // an angle here so we can get an angle of rotation to clamp against.
237 let max_angle = ops::acos(forward_dot_player.clamp(-1.0, 1.0)); // Clamp acos for safety
238
239 // Calculate angle of rotation with limit
240 let rotation_angle =
241 rotation_sign * (config.rotation_speed * time.delta_secs()).min(max_angle);
242
243 // Rotate the enemy to face the player
244 enemy_transform.rotate_z(rotation_angle);
245 }
246}
More examples
458 fn perimeter(&self) -> Vec<PerimeterSegment> {
459 let resolution = self.resolution as u32;
460 vec![
461 // The left wing of the heart
462 PerimeterSegment::Smooth {
463 // The normals of the first and last vertices of smooth segments have to be specified manually.
464 first_normal: Vec2::X,
465 last_normal: Vec2::new(-1.0, -1.0).normalize(),
466 // These indices are used to index into the `ATTRIBUTE_POSITION` vec of your 2D mesh.
467 indices: (0..resolution).collect(),
468 },
469 // The bottom tip of the heart
470 PerimeterSegment::Flat {
471 indices: vec![resolution - 1, resolution, resolution + 1],
472 },
473 // The right wing of the heart
474 PerimeterSegment::Smooth {
475 first_normal: Vec2::new(1.0, -1.0).normalize(),
476 last_normal: Vec2::NEG_X,
477 indices: (resolution + 1..2 * resolution).chain([0]).collect(),
478 },
479 ]
480 }
359fn move_pupils(time: Res<Time>, mut q_pupils: Query<(&mut Pupil, &mut Transform)>) {
360 for (mut pupil, mut transform) in &mut q_pupils {
361 // The wiggle radius is how much the pupil can move within the eye
362 let wiggle_radius = pupil.eye_radius - pupil.pupil_radius;
363 // Store the Z component
364 let z = transform.translation.z;
365 // Truncate the Z component to make the calculations be on [`Vec2`]
366 let mut translation = transform.translation.truncate();
367 // Decay the pupil velocity
368 pupil.velocity *= ops::powf(0.04f32, time.delta_secs());
369 // Move the pupil
370 translation += pupil.velocity * time.delta_secs();
371 // If the pupil hit the outside border of the eye, limit the translation to be within the wiggle radius and invert the velocity.
372 // This is not physically accurate but it's good enough for the googly eyes effect.
373 if translation.length() > wiggle_radius {
374 translation = translation.normalize() * wiggle_radius;
375 // Invert and decrease the velocity of the pupil when it bounces
376 pupil.velocity *= -0.75;
377 }
378 // Update the entity transform with the new translation after reading the Z component
379 transform.translation = translation.extend(z);
380 }
381}
178fn setup(
179 mut commands: Commands,
180 mut meshes: ResMut<Assets<Mesh>>,
181 mut materials: ResMut<Assets<ColorMaterial>>,
182 asset_server: Res<AssetServer>,
183) {
184 // Camera
185 commands.spawn(Camera2d);
186
187 // Sound
188 let ball_collision_sound = asset_server.load("sounds/breakout_collision.ogg");
189 commands.insert_resource(CollisionSound(ball_collision_sound));
190
191 // Paddle
192 let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
193
194 commands.spawn((
195 Sprite::from_color(PADDLE_COLOR, Vec2::ONE),
196 Transform {
197 translation: Vec3::new(0.0, paddle_y, 0.0),
198 scale: PADDLE_SIZE.extend(1.0),
199 ..default()
200 },
201 Paddle,
202 Collider,
203 ));
204
205 // Ball
206 commands.spawn((
207 Mesh2d(meshes.add(Circle::default())),
208 MeshMaterial2d(materials.add(BALL_COLOR)),
209 Transform::from_translation(BALL_STARTING_POSITION)
210 .with_scale(Vec2::splat(BALL_DIAMETER).extend(1.)),
211 Ball,
212 Velocity(INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED),
213 ));
214
215 // Scoreboard
216 commands.spawn((
217 Text::new("Score: "),
218 TextFont {
219 font_size: SCOREBOARD_FONT_SIZE,
220 ..default()
221 },
222 TextColor(TEXT_COLOR),
223 ScoreboardUi,
224 Node {
225 position_type: PositionType::Absolute,
226 top: SCOREBOARD_TEXT_PADDING,
227 left: SCOREBOARD_TEXT_PADDING,
228 ..default()
229 },
230 children![(
231 TextSpan::default(),
232 TextFont {
233 font_size: SCOREBOARD_FONT_SIZE,
234 ..default()
235 },
236 TextColor(SCORE_COLOR),
237 )],
238 ));
239
240 // Walls
241 commands.spawn(Wall::new(WallLocation::Left));
242 commands.spawn(Wall::new(WallLocation::Right));
243 commands.spawn(Wall::new(WallLocation::Bottom));
244 commands.spawn(Wall::new(WallLocation::Top));
245
246 // Bricks
247 let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES;
248 let bottom_edge_of_bricks = paddle_y + GAP_BETWEEN_PADDLE_AND_BRICKS;
249 let total_height_of_bricks = TOP_WALL - bottom_edge_of_bricks - GAP_BETWEEN_BRICKS_AND_CEILING;
250
251 assert!(total_width_of_bricks > 0.0);
252 assert!(total_height_of_bricks > 0.0);
253
254 // Given the space available, compute how many rows and columns of bricks we can fit
255 let n_columns = (total_width_of_bricks / (BRICK_SIZE.x + GAP_BETWEEN_BRICKS)).floor() as usize;
256 let n_rows = (total_height_of_bricks / (BRICK_SIZE.y + GAP_BETWEEN_BRICKS)).floor() as usize;
257 let n_vertical_gaps = n_columns - 1;
258
259 // Because we need to round the number of columns,
260 // the space on the top and sides of the bricks only captures a lower bound, not an exact value
261 let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0;
262 let left_edge_of_bricks = center_of_bricks
263 // Space taken up by the bricks
264 - (n_columns as f32 / 2.0 * BRICK_SIZE.x)
265 // Space taken up by the gaps
266 - n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS;
267
268 // In Bevy, the `translation` of an entity describes the center point,
269 // not its bottom-left corner
270 let offset_x = left_edge_of_bricks + BRICK_SIZE.x / 2.;
271 let offset_y = bottom_edge_of_bricks + BRICK_SIZE.y / 2.;
272
273 for row in 0..n_rows {
274 for column in 0..n_columns {
275 let brick_position = Vec2::new(
276 offset_x + column as f32 * (BRICK_SIZE.x + GAP_BETWEEN_BRICKS),
277 offset_y + row as f32 * (BRICK_SIZE.y + GAP_BETWEEN_BRICKS),
278 );
279
280 // brick
281 commands.spawn((
282 Sprite {
283 color: BRICK_COLOR,
284 ..default()
285 },
286 Transform {
287 translation: brick_position.extend(0.0),
288 scale: Vec3::new(BRICK_SIZE.x, BRICK_SIZE.y, 1.0),
289 ..default()
290 },
291 Brick,
292 Collider,
293 ));
294 }
295 }
296}
Sourcepub fn try_normalize(self) -> Option<Vec2>
pub fn try_normalize(self) -> Option<Vec2>
Returns self
normalized to length 1.0 if possible, else returns None
.
In particular, if the input is zero (or very close to zero), or non-finite,
the result of this operation will be None
.
See also Self::normalize_or_zero()
.
Sourcepub fn normalize_or(self, fallback: Vec2) -> Vec2
pub fn normalize_or(self, fallback: Vec2) -> Vec2
Returns self
normalized to length 1.0 if possible, else returns a
fallback value.
In particular, if the input is zero (or very close to zero), or non-finite, the result of this operation will be the fallback value.
See also Self::try_normalize()
.
Sourcepub fn normalize_or_zero(self) -> Vec2
pub fn normalize_or_zero(self) -> Vec2
Returns self
normalized to length 1.0 if possible, else returns zero.
In particular, if the input is zero (or very close to zero), or non-finite, the result of this operation will be zero.
See also Self::try_normalize()
.
Examples found in repository?
95fn move_player(
96 mut player: Single<&mut Transform, With<Player>>,
97 time: Res<Time>,
98 kb_input: Res<ButtonInput<KeyCode>>,
99) {
100 let mut direction = Vec2::ZERO;
101
102 if kb_input.pressed(KeyCode::KeyW) {
103 direction.y += 1.;
104 }
105
106 if kb_input.pressed(KeyCode::KeyS) {
107 direction.y -= 1.;
108 }
109
110 if kb_input.pressed(KeyCode::KeyA) {
111 direction.x -= 1.;
112 }
113
114 if kb_input.pressed(KeyCode::KeyD) {
115 direction.x += 1.;
116 }
117
118 // Progressively update the player's position over time. Normalize the
119 // direction vector to prevent it from exceeding a magnitude of 1 when
120 // moving diagonally.
121 let move_delta = direction.normalize_or_zero() * PLAYER_SPEED * time.delta_secs();
122 player.translation += move_delta.extend(0.);
123}
More examples
222fn resize_image(
223 image_mesh: Query<(&MeshMaterial3d<StandardMaterial>, &Mesh3d), With<HDRViewer>>,
224 materials: Res<Assets<StandardMaterial>>,
225 mut meshes: ResMut<Assets<Mesh>>,
226 images: Res<Assets<Image>>,
227 mut image_events: EventReader<AssetEvent<Image>>,
228) {
229 for event in image_events.read() {
230 let (AssetEvent::Added { id } | AssetEvent::Modified { id }) = event else {
231 continue;
232 };
233
234 for (mat_h, mesh_h) in &image_mesh {
235 let Some(mat) = materials.get(mat_h) else {
236 continue;
237 };
238
239 let Some(ref base_color_texture) = mat.base_color_texture else {
240 continue;
241 };
242
243 if *id != base_color_texture.id() {
244 continue;
245 };
246
247 let Some(image_changed) = images.get(*id) else {
248 continue;
249 };
250
251 let size = image_changed.size_f32().normalize_or_zero() * 1.4;
252 // Resize Mesh
253 let quad = Mesh::from(Rectangle::from_size(size));
254 meshes.insert(mesh_h, quad);
255 }
256 }
257}
Sourcepub fn is_normalized(self) -> bool
pub fn is_normalized(self) -> bool
Returns whether self
is length 1.0
or not.
Uses a precision threshold of approximately 1e-4
.
Sourcepub fn project_onto(self, rhs: Vec2) -> Vec2
pub fn project_onto(self, rhs: Vec2) -> Vec2
Returns the vector projection of self
onto rhs
.
rhs
must be of non-zero length.
§Panics
Will panic if rhs
is zero length when glam_assert
is enabled.
Sourcepub fn reject_from(self, rhs: Vec2) -> Vec2
pub fn reject_from(self, rhs: Vec2) -> Vec2
Returns the vector rejection of self
from rhs
.
The vector rejection is the vector perpendicular to the projection of self
onto
rhs
, in rhs words the result of self - self.project_onto(rhs)
.
rhs
must be of non-zero length.
§Panics
Will panic if rhs
has a length of zero when glam_assert
is enabled.
Sourcepub fn project_onto_normalized(self, rhs: Vec2) -> Vec2
pub fn project_onto_normalized(self, rhs: Vec2) -> Vec2
Returns the vector projection of self
onto rhs
.
rhs
must be normalized.
§Panics
Will panic if rhs
is not normalized when glam_assert
is enabled.
Sourcepub fn reject_from_normalized(self, rhs: Vec2) -> Vec2
pub fn reject_from_normalized(self, rhs: Vec2) -> Vec2
Returns the vector rejection of self
from rhs
.
The vector rejection is the vector perpendicular to the projection of self
onto
rhs
, in rhs words the result of self - self.project_onto(rhs)
.
rhs
must be normalized.
§Panics
Will panic if rhs
is not normalized when glam_assert
is enabled.
Sourcepub fn round(self) -> Vec2
pub fn round(self) -> Vec2
Returns a vector containing the nearest integer to a number for each element of self
.
Round half-way cases away from 0.0.
Sourcepub fn floor(self) -> Vec2
pub fn floor(self) -> Vec2
Returns a vector containing the largest integer less than or equal to a number for each
element of self
.
Sourcepub fn ceil(self) -> Vec2
pub fn ceil(self) -> Vec2
Returns a vector containing the smallest integer greater than or equal to a number for
each element of self
.
Sourcepub fn trunc(self) -> Vec2
pub fn trunc(self) -> Vec2
Returns a vector containing the integer part each element of self
. This means numbers are
always truncated towards zero.
Sourcepub fn fract(self) -> Vec2
pub fn fract(self) -> Vec2
Returns a vector containing the fractional part of the vector as self - self.trunc()
.
Note that this differs from the GLSL implementation of fract
which returns
self - self.floor()
.
Note that this is fast but not precise for large numbers.
Sourcepub fn fract_gl(self) -> Vec2
pub fn fract_gl(self) -> Vec2
Returns a vector containing the fractional part of the vector as self - self.floor()
.
Note that this differs from the Rust implementation of fract
which returns
self - self.trunc()
.
Note that this is fast but not precise for large numbers.
Sourcepub fn exp(self) -> Vec2
pub fn exp(self) -> Vec2
Returns a vector containing e^self
(the exponential function) for each element of
self
.
Sourcepub fn powf(self, n: f32) -> Vec2
pub fn powf(self, n: f32) -> Vec2
Returns a vector containing each element of self
raised to the power of n
.
Sourcepub fn recip(self) -> Vec2
pub fn recip(self) -> Vec2
Returns a vector containing the reciprocal 1.0/n
of each element of self
.
Sourcepub fn lerp(self, rhs: Vec2, s: f32) -> Vec2
pub fn lerp(self, rhs: Vec2, s: f32) -> Vec2
Performs a linear interpolation between self
and rhs
based on the value s
.
When s
is 0.0
, the result will be equal to self
. When s
is 1.0
, the result
will be equal to rhs
. When s
is outside of range [0, 1]
, the result is linearly
extrapolated.
Sourcepub fn move_towards(&self, rhs: Vec2, d: f32) -> Vec2
pub fn move_towards(&self, rhs: Vec2, d: f32) -> Vec2
Moves towards rhs
based on the value d
.
When d
is 0.0
, the result will be equal to self
. When d
is equal to
self.distance(rhs)
, the result will be equal to rhs
. Will not go past rhs
.
Sourcepub fn midpoint(self, rhs: Vec2) -> Vec2
pub fn midpoint(self, rhs: Vec2) -> Vec2
Calculates the midpoint between self
and rhs
.
The midpoint is the average of, or halfway point between, two vectors.
a.midpoint(b)
should yield the same result as a.lerp(b, 0.5)
while being slightly cheaper to compute.
Sourcepub fn abs_diff_eq(self, rhs: Vec2, max_abs_diff: f32) -> bool
pub fn abs_diff_eq(self, rhs: Vec2, max_abs_diff: f32) -> bool
Returns true if the absolute difference of all elements between self
and rhs
is
less than or equal to max_abs_diff
.
This can be used to compare if two vectors contain similar elements. It works best when
comparing with a known value. The max_abs_diff
that should be used used depends on
the values being compared against.
For more see comparing floating point numbers.
Sourcepub fn clamp_length(self, min: f32, max: f32) -> Vec2
pub fn clamp_length(self, min: f32, max: f32) -> Vec2
Returns a vector with a length no less than min
and no more than max
.
§Panics
Will panic if min
is greater than max
, or if either min
or max
is negative, when glam_assert
is enabled.
Sourcepub fn clamp_length_max(self, max: f32) -> Vec2
pub fn clamp_length_max(self, max: f32) -> Vec2
Returns a vector with a length no more than max
.
§Panics
Will panic if max
is negative when glam_assert
is enabled.
Sourcepub fn clamp_length_min(self, min: f32) -> Vec2
pub fn clamp_length_min(self, min: f32) -> Vec2
Returns a vector with a length no less than min
.
§Panics
Will panic if min
is negative when glam_assert
is enabled.
Sourcepub fn mul_add(self, a: Vec2, b: Vec2) -> Vec2
pub fn mul_add(self, a: Vec2, b: Vec2) -> Vec2
Fused multiply-add. Computes (self * a) + b
element-wise with only one rounding
error, yielding a more accurate result than an unfused multiply-add.
Using mul_add
may be more performant than an unfused multiply-add if the target
architecture has a dedicated fma CPU instruction. However, this is not always true,
and will be heavily dependant on designing algorithms with specific target hardware in
mind.
Sourcepub fn reflect(self, normal: Vec2) -> Vec2
pub fn reflect(self, normal: Vec2) -> Vec2
Returns the reflection vector for a given incident vector self
and surface normal
normal
.
normal
must be normalized.
§Panics
Will panic if normal
is not normalized when glam_assert
is enabled.
Sourcepub fn refract(self, normal: Vec2, eta: f32) -> Vec2
pub fn refract(self, normal: Vec2, eta: f32) -> Vec2
Returns the refraction direction for a given incident vector self
, surface normal
normal
and ratio of indices of refraction, eta
. When total internal reflection occurs,
a zero vector will be returned.
self
and normal
must be normalized.
§Panics
Will panic if self
or normal
is not normalized when glam_assert
is enabled.
Sourcepub fn from_angle(angle: f32) -> Vec2
pub fn from_angle(angle: f32) -> Vec2
Creates a 2D vector containing [angle.cos(), angle.sin()]
. This can be used in
conjunction with the rotate()
method, e.g.
Vec2::from_angle(PI).rotate(Vec2::Y)
will create the vector [-1, 0]
and rotate Vec2::Y
around it returning -Vec2::Y
.
Examples found in repository?
296fn rotate_camera(
297 time: Res<Time>,
298 mut camera_query: Query<&mut Transform, With<Camera3d>>,
299 app_status: Res<AppStatus>,
300) {
301 if !app_status.rotating {
302 return;
303 }
304
305 for mut transform in camera_query.iter_mut() {
306 transform.translation = Vec2::from_angle(time.delta_secs() * PI / 5.0)
307 .rotate(transform.translation.xz())
308 .extend(transform.translation.y)
309 .xzy();
310 transform.look_at(Vec3::ZERO, Vec3::Y);
311 }
312}
More examples
350fn rotate_camera(
351 mut camera_query: Query<&mut Transform, With<Camera3d>>,
352 time: Res<Time>,
353 app_status: Res<AppStatus>,
354) {
355 if !app_status.rotating {
356 return;
357 }
358
359 for mut transform in camera_query.iter_mut() {
360 transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_secs())
361 .rotate(transform.translation.xz())
362 .extend(transform.translation.y)
363 .xzy();
364 transform.look_at(Vec3::ZERO, Vec3::Y);
365 }
366}
94fn draw(
95 my_handle: Res<MyProcGenImage>,
96 mut images: ResMut<Assets<Image>>,
97 // Used to keep track of where we are
98 mut i: Local<u32>,
99 mut draw_color: Local<Color>,
100 mut seeded_rng: ResMut<SeededRng>,
101) {
102 if *i == 0 {
103 // Generate a random color on first run.
104 *draw_color = Color::linear_rgb(
105 seeded_rng.0.r#gen(),
106 seeded_rng.0.r#gen(),
107 seeded_rng.0.r#gen(),
108 );
109 }
110
111 // Get the image from Bevy's asset storage.
112 let image = images.get_mut(&my_handle.0).expect("Image not found");
113
114 // Compute the position of the pixel to draw.
115
116 let center = Vec2::new(IMAGE_WIDTH as f32 / 2.0, IMAGE_HEIGHT as f32 / 2.0);
117 let max_radius = IMAGE_HEIGHT.min(IMAGE_WIDTH) as f32 / 2.0;
118 let rot_speed = 0.0123;
119 let period = 0.12345;
120
121 let r = ops::sin(*i as f32 * period) * max_radius;
122 let xy = Vec2::from_angle(*i as f32 * rot_speed) * r + center;
123 let (x, y) = (xy.x as u32, xy.y as u32);
124
125 // Get the old color of that pixel.
126 let old_color = image.get_color_at(x, y).unwrap();
127
128 // If the old color is our current color, change our drawing color.
129 let tolerance = 1.0 / 255.0;
130 if old_color.distance(&draw_color) <= tolerance {
131 *draw_color = Color::linear_rgb(
132 seeded_rng.0.r#gen(),
133 seeded_rng.0.r#gen(),
134 seeded_rng.0.r#gen(),
135 );
136 }
137
138 // Set the new color, but keep old alpha value from image.
139 image
140 .set_color_at(x, y, draw_color.with_alpha(old_color.alpha()))
141 .unwrap();
142
143 *i += 1;
144}
40fn draw_example_collection(
41 mut gizmos: Gizmos,
42 mut my_gizmos: Gizmos<MyRoundGizmos>,
43 time: Res<Time>,
44) {
45 let sin_t_scaled = ops::sin(time.elapsed_secs()) * 50.;
46 gizmos.line_2d(Vec2::Y * -sin_t_scaled, Vec2::splat(-80.), RED);
47 gizmos.ray_2d(Vec2::Y * sin_t_scaled, Vec2::splat(80.), LIME);
48
49 gizmos
50 .grid_2d(
51 Isometry2d::IDENTITY,
52 UVec2::new(16, 9),
53 Vec2::new(80., 80.),
54 // Dark gray
55 LinearRgba::gray(0.05),
56 )
57 .outer_edges();
58
59 // Triangle
60 gizmos.linestrip_gradient_2d([
61 (Vec2::Y * 300., BLUE),
62 (Vec2::new(-255., -155.), RED),
63 (Vec2::new(255., -155.), LIME),
64 (Vec2::Y * 300., BLUE),
65 ]);
66
67 gizmos.rect_2d(Isometry2d::IDENTITY, Vec2::splat(650.), BLACK);
68
69 gizmos.cross_2d(Vec2::new(-160., 120.), 12., FUCHSIA);
70
71 let domain = Interval::EVERYWHERE;
72 let curve = FunctionCurve::new(domain, |t| Vec2::new(t, ops::sin(t / 25.0) * 100.0));
73 let resolution = ((ops::sin(time.elapsed_secs()) + 1.0) * 50.0) as usize;
74 let times_and_colors = (0..=resolution)
75 .map(|n| n as f32 / resolution as f32)
76 .map(|t| (t - 0.5) * 600.0)
77 .map(|t| (t, TEAL.mix(&HOT_PINK, (t + 300.0) / 600.0)));
78 gizmos.curve_gradient_2d(curve, times_and_colors);
79
80 my_gizmos
81 .rounded_rect_2d(Isometry2d::IDENTITY, Vec2::splat(630.), BLACK)
82 .corner_radius(ops::cos(time.elapsed_secs() / 3.) * 100.);
83
84 // Circles have 32 line-segments by default.
85 // You may want to increase this for larger circles.
86 my_gizmos
87 .circle_2d(Isometry2d::IDENTITY, 300., NAVY)
88 .resolution(64);
89
90 my_gizmos.ellipse_2d(
91 Rot2::radians(time.elapsed_secs() % TAU),
92 Vec2::new(100., 200.),
93 YELLOW_GREEN,
94 );
95
96 // Arcs default resolution is linearly interpolated between
97 // 1 and 32, using the arc length as scalar.
98 my_gizmos.arc_2d(
99 Rot2::radians(sin_t_scaled / 10.),
100 FRAC_PI_2,
101 310.,
102 ORANGE_RED,
103 );
104 my_gizmos.arc_2d(Isometry2d::IDENTITY, FRAC_PI_2, 80.0, ORANGE_RED);
105 my_gizmos.long_arc_2d_between(Vec2::ZERO, Vec2::X * 20.0, Vec2::Y * 20.0, ORANGE_RED);
106 my_gizmos.short_arc_2d_between(Vec2::ZERO, Vec2::X * 40.0, Vec2::Y * 40.0, ORANGE_RED);
107
108 gizmos.arrow_2d(
109 Vec2::ZERO,
110 Vec2::from_angle(sin_t_scaled / -10. + PI / 2.) * 50.,
111 YELLOW,
112 );
113
114 // You can create more complex arrows using the arrow builder.
115 gizmos
116 .arrow_2d(
117 Vec2::ZERO,
118 Vec2::from_angle(sin_t_scaled / -10.) * 50.,
119 GREEN,
120 )
121 .with_double_end()
122 .with_tip_length(10.);
123}
Sourcepub fn to_angle(self) -> f32
pub fn to_angle(self) -> f32
Returns the angle (in radians) of this vector in the range [-π, +π]
.
The input does not need to be a unit vector however it must be non-zero.
pub fn angle_between(self, rhs: Vec2) -> f32
Sourcepub fn angle_to(self, rhs: Vec2) -> f32
pub fn angle_to(self, rhs: Vec2) -> f32
Returns the angle of rotation (in radians) from self
to rhs
in the range [-π, +π]
.
The inputs do not need to be unit vectors however they must be non-zero.
Sourcepub fn perp_dot(self, rhs: Vec2) -> f32
pub fn perp_dot(self, rhs: Vec2) -> f32
The perpendicular dot product of self
and rhs
.
Also known as the wedge product, 2D cross product, and determinant.
Sourcepub fn rotate(self, rhs: Vec2) -> Vec2
pub fn rotate(self, rhs: Vec2) -> Vec2
Returns rhs
rotated by the angle of self
. If self
is normalized,
then this just rotation. This is what you usually want. Otherwise,
it will be like a rotation with a multiplication by self
’s length.
Examples found in repository?
296fn rotate_camera(
297 time: Res<Time>,
298 mut camera_query: Query<&mut Transform, With<Camera3d>>,
299 app_status: Res<AppStatus>,
300) {
301 if !app_status.rotating {
302 return;
303 }
304
305 for mut transform in camera_query.iter_mut() {
306 transform.translation = Vec2::from_angle(time.delta_secs() * PI / 5.0)
307 .rotate(transform.translation.xz())
308 .extend(transform.translation.y)
309 .xzy();
310 transform.look_at(Vec3::ZERO, Vec3::Y);
311 }
312}
More examples
350fn rotate_camera(
351 mut camera_query: Query<&mut Transform, With<Camera3d>>,
352 time: Res<Time>,
353 app_status: Res<AppStatus>,
354) {
355 if !app_status.rotating {
356 return;
357 }
358
359 for mut transform in camera_query.iter_mut() {
360 transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_secs())
361 .rotate(transform.translation.xz())
362 .extend(transform.translation.y)
363 .xzy();
364 transform.look_at(Vec3::ZERO, Vec3::Y);
365 }
366}
Sourcepub fn rotate_towards(&self, rhs: Vec2, max_angle: f32) -> Vec2
pub fn rotate_towards(&self, rhs: Vec2, max_angle: f32) -> Vec2
Rotates towards rhs
up to max_angle
(in radians).
When max_angle
is 0.0
, the result will be equal to self
. When max_angle
is equal to
self.angle_between(rhs)
, the result will be equal to rhs
. If max_angle
is negative,
rotates towards the exact opposite of rhs
. Will not go past the target.
Sourcepub fn as_i16vec2(&self) -> I16Vec2
pub fn as_i16vec2(&self) -> I16Vec2
Casts all elements of self
to i16
.
Sourcepub fn as_u16vec2(&self) -> U16Vec2
pub fn as_u16vec2(&self) -> U16Vec2
Casts all elements of self
to u16
.
Sourcepub fn as_uvec2(&self) -> UVec2
pub fn as_uvec2(&self) -> UVec2
Casts all elements of self
to u32
.
Examples found in repository?
141fn setup(
142 mut commands: Commands,
143 mut meshes: ResMut<Assets<Mesh>>,
144 mut materials: ResMut<Assets<ColorMaterial>>,
145 window: Single<&Window>,
146) {
147 let window_size = window.resolution.physical_size().as_vec2();
148
149 // Initialize centered, non-window-filling viewport
150 commands.spawn((
151 Camera2d,
152 Camera {
153 viewport: Some(Viewport {
154 physical_position: (window_size * 0.125).as_uvec2(),
155 physical_size: (window_size * 0.75).as_uvec2(),
156 ..default()
157 }),
158 ..default()
159 },
160 ));
161
162 // Create a minimal UI explaining how to interact with the example
163 commands.spawn((
164 Text::new(
165 "Move the mouse to see the circle follow your cursor.\n\
166 Use the arrow keys to move the camera.\n\
167 Use the comma and period keys to zoom in and out.\n\
168 Use the WASD keys to move the viewport.\n\
169 Use the IJKL keys to resize the viewport.",
170 ),
171 Node {
172 position_type: PositionType::Absolute,
173 top: Val::Px(12.0),
174 left: Val::Px(12.0),
175 ..default()
176 },
177 ));
178
179 // Add mesh to make camera movement visible
180 commands.spawn((
181 Mesh2d(meshes.add(Rectangle::new(40.0, 20.0))),
182 MeshMaterial2d(materials.add(Color::from(GREEN))),
183 ));
184
185 // Add background to visualize viewport bounds
186 commands.spawn((
187 Mesh2d(meshes.add(Rectangle::new(50000.0, 50000.0))),
188 MeshMaterial2d(materials.add(Color::linear_rgb(0.01, 0.01, 0.01))),
189 Transform::from_translation(Vec3::new(0.0, 0.0, -200.0)),
190 ));
191}
Sourcepub fn as_i64vec2(&self) -> I64Vec2
pub fn as_i64vec2(&self) -> I64Vec2
Casts all elements of self
to i64
.
Sourcepub fn as_u64vec2(&self) -> U64Vec2
pub fn as_u64vec2(&self) -> U64Vec2
Casts all elements of self
to u64
.
Trait Implementations§
Source§impl AddAssign<&Vec2> for Vec2
impl AddAssign<&Vec2> for Vec2
Source§fn add_assign(&mut self, rhs: &Vec2)
fn add_assign(&mut self, rhs: &Vec2)
+=
operation. Read moreSource§impl AddAssign<&f32> for Vec2
impl AddAssign<&f32> for Vec2
Source§fn add_assign(&mut self, rhs: &f32)
fn add_assign(&mut self, rhs: &f32)
+=
operation. Read moreSource§impl AddAssign<f32> for Vec2
impl AddAssign<f32> for Vec2
Source§fn add_assign(&mut self, rhs: f32)
fn add_assign(&mut self, rhs: f32)
+=
operation. Read moreSource§impl AddAssign for Vec2
impl AddAssign for Vec2
Source§fn add_assign(&mut self, rhs: Vec2)
fn add_assign(&mut self, rhs: Vec2)
+=
operation. Read moreSource§impl Animatable for Vec2
impl Animatable for Vec2
Source§impl AsMutVectorParts<f32, 2> for Vec2
impl AsMutVectorParts<f32, 2> for Vec2
fn as_mut_parts(&mut self) -> &mut [f32; 2]
Source§impl AsRefVectorParts<f32, 2> for Vec2
impl AsRefVectorParts<f32, 2> for Vec2
fn as_ref_parts(&self) -> &[f32; 2]
Source§impl CreateFrom for Vec2
impl CreateFrom for Vec2
Source§impl<'de> Deserialize<'de> for Vec2
Deserialize expects a sequence of 2 values.
impl<'de> Deserialize<'de> for Vec2
Deserialize expects a sequence of 2 values.
Source§fn deserialize<D>(
deserializer: D,
) -> Result<Vec2, <D as Deserializer<'de>>::Error>where
D: Deserializer<'de>,
fn deserialize<D>(
deserializer: D,
) -> Result<Vec2, <D as Deserializer<'de>>::Error>where
D: Deserializer<'de>,
Source§impl DivAssign<&Vec2> for Vec2
impl DivAssign<&Vec2> for Vec2
Source§fn div_assign(&mut self, rhs: &Vec2)
fn div_assign(&mut self, rhs: &Vec2)
/=
operation. Read moreSource§impl DivAssign<&f32> for Vec2
impl DivAssign<&f32> for Vec2
Source§fn div_assign(&mut self, rhs: &f32)
fn div_assign(&mut self, rhs: &f32)
/=
operation. Read moreSource§impl DivAssign<f32> for Vec2
impl DivAssign<f32> for Vec2
Source§fn div_assign(&mut self, rhs: f32)
fn div_assign(&mut self, rhs: f32)
/=
operation. Read moreSource§impl DivAssign for Vec2
impl DivAssign for Vec2
Source§fn div_assign(&mut self, rhs: Vec2)
fn div_assign(&mut self, rhs: Vec2)
/=
operation. Read moreSource§impl From<&ScrollPosition> for Vec2
impl From<&ScrollPosition> for Vec2
Source§fn from(scroll_pos: &ScrollPosition) -> Vec2
fn from(scroll_pos: &ScrollPosition) -> Vec2
Source§impl From<Vec2> for Isometry2d
impl From<Vec2> for Isometry2d
Source§fn from(translation: Vec2) -> Isometry2d
fn from(translation: Vec2) -> Isometry2d
Source§impl From<Vec2> for ScrollPosition
impl From<Vec2> for ScrollPosition
Source§fn from(vec: Vec2) -> ScrollPosition
fn from(vec: Vec2) -> ScrollPosition
Source§impl From<Vec2> for TextBounds
impl From<Vec2> for TextBounds
Source§fn from(v: Vec2) -> TextBounds
fn from(v: Vec2) -> TextBounds
Source§impl From<Vec2> for WindowResolution
impl From<Vec2> for WindowResolution
Source§fn from(res: Vec2) -> WindowResolution
fn from(res: Vec2) -> WindowResolution
Source§impl FromIterator<Vec2> for BoxedPolygon
impl FromIterator<Vec2> for BoxedPolygon
Source§fn from_iter<I>(iter: I) -> BoxedPolygonwhere
I: IntoIterator<Item = Vec2>,
fn from_iter<I>(iter: I) -> BoxedPolygonwhere
I: IntoIterator<Item = Vec2>,
Source§impl FromIterator<Vec2> for BoxedPolyline2d
impl FromIterator<Vec2> for BoxedPolyline2d
Source§fn from_iter<I>(iter: I) -> BoxedPolyline2dwhere
I: IntoIterator<Item = Vec2>,
fn from_iter<I>(iter: I) -> BoxedPolyline2dwhere
I: IntoIterator<Item = Vec2>,
Source§impl<const N: usize> FromIterator<Vec2> for Polyline2d<N>
impl<const N: usize> FromIterator<Vec2> for Polyline2d<N>
Source§fn from_iter<I>(iter: I) -> Polyline2d<N>where
I: IntoIterator<Item = Vec2>,
fn from_iter<I>(iter: I) -> Polyline2d<N>where
I: IntoIterator<Item = Vec2>,
Source§impl FromReflect for Vec2
impl FromReflect for Vec2
Source§fn from_reflect(reflect: &(dyn PartialReflect + 'static)) -> Option<Vec2>
fn from_reflect(reflect: &(dyn PartialReflect + 'static)) -> Option<Vec2>
Self
from a reflected value.Source§fn take_from_reflect(
reflect: Box<dyn PartialReflect>,
) -> Result<Self, Box<dyn PartialReflect>>
fn take_from_reflect( reflect: Box<dyn PartialReflect>, ) -> Result<Self, Box<dyn PartialReflect>>
Self
using,
constructing the value using from_reflect
if that fails. Read moreSource§impl FromVectorParts<f32, 2> for Vec2
impl FromVectorParts<f32, 2> for Vec2
Source§impl GetOwnership for &Vec2
impl GetOwnership for &Vec2
Source§impl GetOwnership for &mut Vec2
impl GetOwnership for &mut Vec2
Source§impl GetOwnership for Vec2
impl GetOwnership for Vec2
Source§impl GetTypeRegistration for Vec2
impl GetTypeRegistration for Vec2
Source§fn get_type_registration() -> TypeRegistration
fn get_type_registration() -> TypeRegistration
TypeRegistration
for this type.Source§fn register_type_dependencies(registry: &mut TypeRegistry)
fn register_type_dependencies(registry: &mut TypeRegistry)
Source§impl IntoReturn for &Vec2
impl IntoReturn for &Vec2
Source§impl IntoReturn for &mut Vec2
impl IntoReturn for &mut Vec2
Source§impl IntoReturn for Vec2
impl IntoReturn for Vec2
Source§impl Mul<Vec2> for Isometry2d
impl Mul<Vec2> for Isometry2d
Source§impl MulAssign<&Vec2> for Vec2
impl MulAssign<&Vec2> for Vec2
Source§fn mul_assign(&mut self, rhs: &Vec2)
fn mul_assign(&mut self, rhs: &Vec2)
*=
operation. Read moreSource§impl MulAssign<&f32> for Vec2
impl MulAssign<&f32> for Vec2
Source§fn mul_assign(&mut self, rhs: &f32)
fn mul_assign(&mut self, rhs: &f32)
*=
operation. Read moreSource§impl MulAssign<f32> for Vec2
impl MulAssign<f32> for Vec2
Source§fn mul_assign(&mut self, rhs: f32)
fn mul_assign(&mut self, rhs: f32)
*=
operation. Read moreSource§impl MulAssign for Vec2
impl MulAssign for Vec2
Source§fn mul_assign(&mut self, rhs: Vec2)
fn mul_assign(&mut self, rhs: Vec2)
*=
operation. Read moreSource§impl NormedVectorSpace for Vec2
impl NormedVectorSpace for Vec2
Source§fn norm_squared(self) -> f32
fn norm_squared(self) -> f32
NormedVectorSpace::norm
.Source§fn distance(self, rhs: Self) -> f32
fn distance(self, rhs: Self) -> f32
Source§fn distance_squared(self, rhs: Self) -> f32
fn distance_squared(self, rhs: Self) -> f32
NormedVectorSpace::distance
.Source§impl PartialReflect for Vec2
impl PartialReflect for Vec2
Source§fn get_represented_type_info(&self) -> Option<&'static TypeInfo>
fn get_represented_type_info(&self) -> Option<&'static TypeInfo>
Source§fn try_apply(
&mut self,
value: &(dyn PartialReflect + 'static),
) -> Result<(), ApplyError>
fn try_apply( &mut self, value: &(dyn PartialReflect + 'static), ) -> Result<(), ApplyError>
Source§fn reflect_kind(&self) -> ReflectKind
fn reflect_kind(&self) -> ReflectKind
Source§fn reflect_ref(&self) -> ReflectRef<'_>
fn reflect_ref(&self) -> ReflectRef<'_>
Source§fn reflect_mut(&mut self) -> ReflectMut<'_>
fn reflect_mut(&mut self) -> ReflectMut<'_>
Source§fn reflect_owned(self: Box<Vec2>) -> ReflectOwned
fn reflect_owned(self: Box<Vec2>) -> ReflectOwned
Source§fn try_into_reflect(
self: Box<Vec2>,
) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>
fn try_into_reflect( self: Box<Vec2>, ) -> Result<Box<dyn Reflect>, Box<dyn PartialReflect>>
Source§fn try_as_reflect(&self) -> Option<&(dyn Reflect + 'static)>
fn try_as_reflect(&self) -> Option<&(dyn Reflect + 'static)>
Source§fn try_as_reflect_mut(&mut self) -> Option<&mut (dyn Reflect + 'static)>
fn try_as_reflect_mut(&mut self) -> Option<&mut (dyn Reflect + 'static)>
Source§fn into_partial_reflect(self: Box<Vec2>) -> Box<dyn PartialReflect>
fn into_partial_reflect(self: Box<Vec2>) -> Box<dyn PartialReflect>
Source§fn as_partial_reflect(&self) -> &(dyn PartialReflect + 'static)
fn as_partial_reflect(&self) -> &(dyn PartialReflect + 'static)
Source§fn as_partial_reflect_mut(&mut self) -> &mut (dyn PartialReflect + 'static)
fn as_partial_reflect_mut(&mut self) -> &mut (dyn PartialReflect + 'static)
Source§fn reflect_partial_eq(
&self,
value: &(dyn PartialReflect + 'static),
) -> Option<bool>
fn reflect_partial_eq( &self, value: &(dyn PartialReflect + 'static), ) -> Option<bool>
Source§fn debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>
fn debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>
Source§fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError>
fn reflect_clone(&self) -> Result<Box<dyn Reflect>, ReflectCloneError>
Self
using reflection. Read moreSource§fn apply(&mut self, value: &(dyn PartialReflect + 'static))
fn apply(&mut self, value: &(dyn PartialReflect + 'static))
Source§fn clone_value(&self) -> Box<dyn PartialReflect>
fn clone_value(&self) -> Box<dyn PartialReflect>
reflect_clone
. To convert reflected values to dynamic ones, use to_dynamic
.Self
into its dynamic representation. Read moreSource§fn to_dynamic(&self) -> Box<dyn PartialReflect>
fn to_dynamic(&self) -> Box<dyn PartialReflect>
Source§fn reflect_hash(&self) -> Option<u64>
fn reflect_hash(&self) -> Option<u64>
Source§fn is_dynamic(&self) -> bool
fn is_dynamic(&self) -> bool
Source§impl Reflect for Vec2
impl Reflect for Vec2
Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut dyn Any
. Read moreSource§fn into_reflect(self: Box<Vec2>) -> Box<dyn Reflect>
fn into_reflect(self: Box<Vec2>) -> Box<dyn Reflect>
Source§fn as_reflect(&self) -> &(dyn Reflect + 'static)
fn as_reflect(&self) -> &(dyn Reflect + 'static)
Source§fn as_reflect_mut(&mut self) -> &mut (dyn Reflect + 'static)
fn as_reflect_mut(&mut self) -> &mut (dyn Reflect + 'static)
Source§impl RemAssign<&Vec2> for Vec2
impl RemAssign<&Vec2> for Vec2
Source§fn rem_assign(&mut self, rhs: &Vec2)
fn rem_assign(&mut self, rhs: &Vec2)
%=
operation. Read moreSource§impl RemAssign<&f32> for Vec2
impl RemAssign<&f32> for Vec2
Source§fn rem_assign(&mut self, rhs: &f32)
fn rem_assign(&mut self, rhs: &f32)
%=
operation. Read moreSource§impl RemAssign<f32> for Vec2
impl RemAssign<f32> for Vec2
Source§fn rem_assign(&mut self, rhs: f32)
fn rem_assign(&mut self, rhs: f32)
%=
operation. Read moreSource§impl RemAssign for Vec2
impl RemAssign for Vec2
Source§fn rem_assign(&mut self, rhs: Vec2)
fn rem_assign(&mut self, rhs: Vec2)
%=
operation. Read moreSource§impl Serialize for Vec2
Serialize as a sequence of 2 values.
impl Serialize for Vec2
Serialize as a sequence of 2 values.
Source§fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
fn serialize<S>(
&self,
serializer: S,
) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error>where
S: Serializer,
Source§impl ShaderSize for Vec2where
f32: ShaderSize,
impl ShaderSize for Vec2where
f32: ShaderSize,
Source§const SHADER_SIZE: NonZero<u64> = _
const SHADER_SIZE: NonZero<u64> = _
ShaderType::min_size
)Source§impl ShaderType for Vec2where
f32: ShaderSize,
impl ShaderType for Vec2where
f32: ShaderSize,
Source§fn assert_uniform_compat()
fn assert_uniform_compat()
Self
meets the requirements of the
uniform address space restrictions on stored values and the
uniform address space layout constraints Read moreSource§impl Struct for Vec2
impl Struct for Vec2
Source§fn field(&self, name: &str) -> Option<&(dyn PartialReflect + 'static)>
fn field(&self, name: &str) -> Option<&(dyn PartialReflect + 'static)>
name
as a &dyn PartialReflect
.Source§fn field_mut(
&mut self,
name: &str,
) -> Option<&mut (dyn PartialReflect + 'static)>
fn field_mut( &mut self, name: &str, ) -> Option<&mut (dyn PartialReflect + 'static)>
name
as a
&mut dyn PartialReflect
.Source§fn field_at(&self, index: usize) -> Option<&(dyn PartialReflect + 'static)>
fn field_at(&self, index: usize) -> Option<&(dyn PartialReflect + 'static)>
index
as a
&dyn PartialReflect
.Source§fn field_at_mut(
&mut self,
index: usize,
) -> Option<&mut (dyn PartialReflect + 'static)>
fn field_at_mut( &mut self, index: usize, ) -> Option<&mut (dyn PartialReflect + 'static)>
index
as a &mut dyn PartialReflect
.Source§fn name_at(&self, index: usize) -> Option<&str>
fn name_at(&self, index: usize) -> Option<&str>
index
.Source§fn iter_fields(&self) -> FieldIter<'_> ⓘ
fn iter_fields(&self) -> FieldIter<'_> ⓘ
fn to_dynamic_struct(&self) -> DynamicStruct
Source§fn clone_dynamic(&self) -> DynamicStruct
fn clone_dynamic(&self) -> DynamicStruct
to_dynamic_struct
insteadDynamicStruct
.Source§fn get_represented_struct_info(&self) -> Option<&'static StructInfo>
fn get_represented_struct_info(&self) -> Option<&'static StructInfo>
None
if TypeInfo
is not available.Source§impl SubAssign<&Vec2> for Vec2
impl SubAssign<&Vec2> for Vec2
Source§fn sub_assign(&mut self, rhs: &Vec2)
fn sub_assign(&mut self, rhs: &Vec2)
-=
operation. Read moreSource§impl SubAssign<&f32> for Vec2
impl SubAssign<&f32> for Vec2
Source§fn sub_assign(&mut self, rhs: &f32)
fn sub_assign(&mut self, rhs: &f32)
-=
operation. Read moreSource§impl SubAssign<f32> for Vec2
impl SubAssign<f32> for Vec2
Source§fn sub_assign(&mut self, rhs: f32)
fn sub_assign(&mut self, rhs: f32)
-=
operation. Read moreSource§impl SubAssign for Vec2
impl SubAssign for Vec2
Source§fn sub_assign(&mut self, rhs: Vec2)
fn sub_assign(&mut self, rhs: Vec2)
-=
operation. Read moreSource§impl TryFrom<Vec2> for AspectRatio
impl TryFrom<Vec2> for AspectRatio
Source§impl TypePath for Vec2
impl TypePath for Vec2
Source§fn type_path() -> &'static str
fn type_path() -> &'static str
Source§fn short_type_path() -> &'static str
fn short_type_path() -> &'static str
Source§fn type_ident() -> Option<&'static str>
fn type_ident() -> Option<&'static str>
Source§fn crate_name() -> Option<&'static str>
fn crate_name() -> Option<&'static str>
Source§impl Vec2Swizzles for Vec2
impl Vec2Swizzles for Vec2
type Vec3 = Vec3
type Vec4 = Vec4
fn xx(self) -> Vec2
fn yx(self) -> Vec2
fn yy(self) -> Vec2
fn xxx(self) -> Vec3
fn xxy(self) -> Vec3
fn xyx(self) -> Vec3
fn xyy(self) -> Vec3
fn yxx(self) -> Vec3
fn yxy(self) -> Vec3
fn yyx(self) -> Vec3
fn yyy(self) -> Vec3
fn xxxx(self) -> Vec4
fn xxxy(self) -> Vec4
fn xxyx(self) -> Vec4
fn xxyy(self) -> Vec4
fn xyxx(self) -> Vec4
fn xyxy(self) -> Vec4
fn xyyx(self) -> Vec4
fn xyyy(self) -> Vec4
fn yxxx(self) -> Vec4
fn yxxy(self) -> Vec4
fn yxyx(self) -> Vec4
fn yxyy(self) -> Vec4
fn yyxx(self) -> Vec4
fn yyxy(self) -> Vec4
fn yyyx(self) -> Vec4
fn yyyy(self) -> Vec4
fn xy(self) -> Self
Source§impl VectorSpace for Vec2
impl VectorSpace for Vec2
Source§impl WriteInto for Vec2
impl WriteInto for Vec2
fn write_into<B>(&self, writer: &mut Writer<B>)where
B: BufferMut,
impl Copy for Vec2
impl Pod for Vec2
impl StructuralPartialEq for Vec2
Auto Trait Implementations§
impl Freeze for Vec2
impl RefUnwindSafe for Vec2
impl Send for Vec2
impl Sync for Vec2
impl Unpin for Vec2
impl UnwindSafe for Vec2
Blanket Implementations§
Source§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
Source§fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U
T
ShaderType
for self
. When used in AsBindGroup
derives, it is safe to assume that all images in self
exist.Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
Source§type Bits = T
type Bits = T
Self
must have the same layout as the specified Bits
except for
the possible invalid bit patterns being checked during
is_valid_bit_pattern
.Source§fn is_valid_bit_pattern(_bits: &T) -> bool
fn is_valid_bit_pattern(_bits: &T) -> bool
bits
as &Self
.Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
, which can then be
downcast
into Box<dyn ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
, which can then be further
downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait>
(where Trait: Downcast
) to Box<dyn Any>
. Box<dyn Any>
can
then be further downcast
into Box<ConcreteType>
where ConcreteType
implements Trait
.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait>
(where Trait: Downcast
) to Rc<Any>
. Rc<Any>
can then be
further downcast
into Rc<ConcreteType>
where ConcreteType
implements Trait
.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &Any
’s vtable from &Trait
’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait
(where Trait: Downcast
) to &Any
. This is needed since Rust cannot
generate &mut Any
’s vtable from &mut Trait
’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> DynamicTypePath for Twhere
T: TypePath,
impl<T> DynamicTypePath for Twhere
T: TypePath,
Source§fn reflect_type_path(&self) -> &str
fn reflect_type_path(&self) -> &str
TypePath::type_path
.Source§fn reflect_short_type_path(&self) -> &str
fn reflect_short_type_path(&self) -> &str
Source§fn reflect_type_ident(&self) -> Option<&str>
fn reflect_type_ident(&self) -> Option<&str>
TypePath::type_ident
.Source§fn reflect_crate_name(&self) -> Option<&str>
fn reflect_crate_name(&self) -> Option<&str>
TypePath::crate_name
.Source§fn reflect_module_path(&self) -> Option<&str>
fn reflect_module_path(&self) -> Option<&str>
Source§impl<T> DynamicTyped for Twhere
T: Typed,
impl<T> DynamicTyped for Twhere
T: Typed,
Source§fn reflect_type_info(&self) -> &'static TypeInfo
fn reflect_type_info(&self) -> &'static TypeInfo
Typed::type_info
.Source§impl<V> Ease for Vwhere
V: VectorSpace,
impl<V> Ease for Vwhere
V: VectorSpace,
Source§fn interpolating_curve_unbounded(start: V, end: V) -> impl Curve<V>
fn interpolating_curve_unbounded(start: V, end: V) -> impl Curve<V>
Source§impl<T> FmtForward for T
impl<T> FmtForward for T
Source§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self
to use its Binary
implementation when Debug
-formatted.Source§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self
to use its Display
implementation when
Debug
-formatted.Source§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self
to use its LowerExp
implementation when
Debug
-formatted.Source§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self
to use its LowerHex
implementation when
Debug
-formatted.Source§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self
to use its Octal
implementation when Debug
-formatted.Source§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self
to use its Pointer
implementation when
Debug
-formatted.Source§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self
to use its UpperExp
implementation when
Debug
-formatted.Source§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self
to use its UpperHex
implementation when
Debug
-formatted.Source§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
Source§fn from_world(_world: &mut World) -> T
fn from_world(_world: &mut World) -> T
Creates Self
using default()
.
Source§impl<S> GetField for Swhere
S: Struct,
impl<S> GetField for Swhere
S: Struct,
Source§impl<T> GetPath for T
impl<T> GetPath for T
Source§fn reflect_path<'p>(
&self,
path: impl ReflectPath<'p>,
) -> Result<&(dyn PartialReflect + 'static), ReflectPathError<'p>>
fn reflect_path<'p>( &self, path: impl ReflectPath<'p>, ) -> Result<&(dyn PartialReflect + 'static), ReflectPathError<'p>>
path
. Read moreSource§fn reflect_path_mut<'p>(
&mut self,
path: impl ReflectPath<'p>,
) -> Result<&mut (dyn PartialReflect + 'static), ReflectPathError<'p>>
fn reflect_path_mut<'p>( &mut self, path: impl ReflectPath<'p>, ) -> Result<&mut (dyn PartialReflect + 'static), ReflectPathError<'p>>
path
. Read moreSource§fn path<'p, T>(
&self,
path: impl ReflectPath<'p>,
) -> Result<&T, ReflectPathError<'p>>where
T: Reflect,
fn path<'p, T>(
&self,
path: impl ReflectPath<'p>,
) -> Result<&T, ReflectPathError<'p>>where
T: Reflect,
path
. Read moreSource§fn path_mut<'p, T>(
&mut self,
path: impl ReflectPath<'p>,
) -> Result<&mut T, ReflectPathError<'p>>where
T: Reflect,
fn path_mut<'p, T>(
&mut self,
path: impl ReflectPath<'p>,
) -> Result<&mut T, ReflectPathError<'p>>where
T: Reflect,
path
. Read moreSource§impl<V> HasTangent for Vwhere
V: VectorSpace,
impl<V> HasTangent for Vwhere
V: VectorSpace,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
Source§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
Source§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
Source§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self
and passes that borrow into the pipe function. Read moreSource§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
Source§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
Source§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self
, then passes self.as_ref()
into the pipe function.Source§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self
, then passes self.as_mut()
into the pipe
function.Source§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self
, then passes self.deref()
into the pipe function.Source§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<R, P> ReadPrimitive<R> for P
impl<R, P> ReadPrimitive<R> for P
Source§fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
fn read_from_little_endian(read: &mut R) -> Result<Self, Error>
ReadEndian::read_from_little_endian()
.Source§impl<T> Serialize for T
impl<T> Serialize for T
fn erased_serialize(&self, serializer: &mut dyn Serializer) -> Result<(), Error>
fn do_erased_serialize( &self, serializer: &mut dyn Serializer, ) -> Result<(), ErrorImpl>
Source§impl<V> StableInterpolate for Vwhere
V: NormedVectorSpace,
impl<V> StableInterpolate for Vwhere
V: NormedVectorSpace,
Source§fn interpolate_stable(&self, other: &V, t: f32) -> V
fn interpolate_stable(&self, other: &V, t: f32) -> V
other
given value using the parameter t
. At
t = 0.0
, a value equivalent to self
is recovered, while t = 1.0
recovers a value
equivalent to other
, with intermediate values interpolating between the two.
See the trait-level documentation for details.Source§fn interpolate_stable_assign(&mut self, other: &Self, t: f32)
fn interpolate_stable_assign(&mut self, other: &Self, t: f32)
interpolate_stable
that assigns the result to self
for convenience.Source§fn smooth_nudge(&mut self, target: &Self, decay_rate: f32, delta: f32)
fn smooth_nudge(&mut self, target: &Self, decay_rate: f32, delta: f32)
target
at a given decay rate. The decay_rate
parameter controls how fast the distance between self
and target
decays relative to
the units of delta
; the intended usage is for decay_rate
to generally remain fixed,
while delta
is something like delta_time
from an updating system. This produces a
smooth following of the target that is independent of framerate. Read moreSource§impl<T> Tap for T
impl<T> Tap for T
Source§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B>
of a value. Read moreSource§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B>
of a value. Read moreSource§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R>
view of a value. Read moreSource§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R>
view of a value. Read moreSource§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target
of a value. Read moreSource§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap()
only in debug builds, and is erased in release builds.Source§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow()
only in debug builds, and is erased in release
builds.Source§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref()
only in debug builds, and is erased in release
builds.Source§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut()
only in debug builds, and is erased in release
builds.Source§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref()
only in debug builds, and is erased in release
builds.