#[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
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
const INITIAL_BALL_DIRECTION: Vec2 = Vec2::new(0.5, -0.5);
const WALL_THICKNESS: f32 = 10.0;
// x coordinates
const LEFT_WALL: f32 = -450.;
const RIGHT_WALL: f32 = 450.;
// y coordinates
const BOTTOM_WALL: f32 = -300.;
const TOP_WALL: f32 = 300.;
const BRICK_SIZE: Vec2 = Vec2::new(100., 30.);
// These values are exact
const GAP_BETWEEN_PADDLE_AND_BRICKS: f32 = 270.0;
const GAP_BETWEEN_BRICKS: f32 = 5.0;
// These values are lower bounds, as the number of bricks is computed
const GAP_BETWEEN_BRICKS_AND_CEILING: f32 = 20.0;
const GAP_BETWEEN_BRICKS_AND_SIDES: f32 = 20.0;
const SCOREBOARD_FONT_SIZE: f32 = 40.0;
const SCOREBOARD_TEXT_PADDING: Val = Val::Px(5.0);
const BACKGROUND_COLOR: Color = Color::rgb(0.9, 0.9, 0.9);
const PADDLE_COLOR: Color = Color::rgb(0.3, 0.3, 0.7);
const BALL_COLOR: Color = Color::rgb(1.0, 0.5, 0.5);
const BRICK_COLOR: Color = Color::rgb(0.5, 0.5, 1.0);
const WALL_COLOR: Color = Color::rgb(0.8, 0.8, 0.8);
const TEXT_COLOR: Color = Color::rgb(0.5, 0.5, 1.0);
const SCORE_COLOR: Color = Color::rgb(1.0, 0.5, 0.5);
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(
stepping::SteppingPlugin::default()
.add_schedule(Update)
.add_schedule(FixedUpdate)
.at(Val::Percent(35.0), Val::Percent(50.0)),
)
.insert_resource(Scoreboard { score: 0 })
.insert_resource(ClearColor(BACKGROUND_COLOR))
.add_event::<CollisionEvent>()
.add_systems(Startup, setup)
// Add our gameplay simulation systems to the fixed timestep schedule
// which runs at 64 Hz by default
.add_systems(
FixedUpdate,
(
apply_velocity,
move_paddle,
check_for_collisions,
play_collision_sound,
)
// `chain`ing systems together runs them in order
.chain(),
)
.add_systems(Update, (update_scoreboard, bevy::window::close_on_esc))
.run();
}
#[derive(Component)]
struct Paddle;
#[derive(Component)]
struct Ball;
#[derive(Component, Deref, DerefMut)]
struct Velocity(Vec2);
#[derive(Component)]
struct Collider;
#[derive(Event, Default)]
struct CollisionEvent;
#[derive(Component)]
struct Brick;
#[derive(Resource)]
struct CollisionSound(Handle<AudioSource>);
// This bundle is a collection of the components that define a "wall" in our game
#[derive(Bundle)]
struct WallBundle {
// You can nest bundles inside of other bundles like this
// Allowing you to compose their functionality
sprite_bundle: SpriteBundle,
collider: Collider,
}
/// Which side of the arena is this wall located on?
enum WallLocation {
Left,
Right,
Bottom,
Top,
}
impl WallLocation {
fn position(&self) -> Vec2 {
match self {
WallLocation::Left => Vec2::new(LEFT_WALL, 0.),
WallLocation::Right => Vec2::new(RIGHT_WALL, 0.),
WallLocation::Bottom => Vec2::new(0., BOTTOM_WALL),
WallLocation::Top => Vec2::new(0., TOP_WALL),
}
}
fn size(&self) -> Vec2 {
let arena_height = TOP_WALL - BOTTOM_WALL;
let arena_width = RIGHT_WALL - LEFT_WALL;
// Make sure we haven't messed up our constants
assert!(arena_height > 0.0);
assert!(arena_width > 0.0);
match self {
WallLocation::Left | WallLocation::Right => {
Vec2::new(WALL_THICKNESS, arena_height + WALL_THICKNESS)
}
WallLocation::Bottom | WallLocation::Top => {
Vec2::new(arena_width + WALL_THICKNESS, WALL_THICKNESS)
}
}
}
}
impl WallBundle {
// This "builder method" allows us to reuse logic across our wall entities,
// making our code easier to read and less prone to bugs when we change the logic
fn new(location: WallLocation) -> WallBundle {
WallBundle {
sprite_bundle: SpriteBundle {
transform: Transform {
// We need to convert our Vec2 into a Vec3, by giving it a z-coordinate
// This is used to determine the order of our sprites
translation: location.position().extend(0.0),
// The z-scale of 2D objects must always be 1.0,
// or their ordering will be affected in surprising ways.
// See https://github.com/bevyengine/bevy/issues/4149
scale: location.size().extend(1.0),
..default()
},
sprite: Sprite {
color: WALL_COLOR,
..default()
},
..default()
},
collider: Collider,
}
}
}
// This resource tracks the game's score
#[derive(Resource)]
struct Scoreboard {
score: usize,
}
#[derive(Component)]
struct ScoreboardUi;
// Add the game's entities to our world
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
asset_server: Res<AssetServer>,
) {
// Camera
commands.spawn(Camera2dBundle::default());
// Sound
let ball_collision_sound = asset_server.load("sounds/breakout_collision.ogg");
commands.insert_resource(CollisionSound(ball_collision_sound));
// Paddle
let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
commands.spawn((
SpriteBundle {
transform: Transform {
translation: Vec3::new(0.0, paddle_y, 0.0),
scale: PADDLE_SIZE,
..default()
},
sprite: Sprite {
color: PADDLE_COLOR,
..default()
},
..default()
},
Paddle,
Collider,
));
// Ball
commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(Circle::default()).into(),
material: materials.add(BALL_COLOR),
transform: Transform::from_translation(BALL_STARTING_POSITION)
.with_scale(Vec2::splat(BALL_DIAMETER).extend(1.)),
..default()
},
Ball,
Velocity(INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED),
));
// Scoreboard
commands.spawn((
ScoreboardUi,
TextBundle::from_sections([
TextSection::new(
"Score: ",
TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: TEXT_COLOR,
..default()
},
),
TextSection::from_style(TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: SCORE_COLOR,
..default()
}),
])
.with_style(Style {
position_type: PositionType::Absolute,
top: SCOREBOARD_TEXT_PADDING,
left: SCOREBOARD_TEXT_PADDING,
..default()
}),
));
// Walls
commands.spawn(WallBundle::new(WallLocation::Left));
commands.spawn(WallBundle::new(WallLocation::Right));
commands.spawn(WallBundle::new(WallLocation::Bottom));
commands.spawn(WallBundle::new(WallLocation::Top));
// Bricks
let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES;
let bottom_edge_of_bricks = paddle_y + GAP_BETWEEN_PADDLE_AND_BRICKS;
let total_height_of_bricks = TOP_WALL - bottom_edge_of_bricks - GAP_BETWEEN_BRICKS_AND_CEILING;
assert!(total_width_of_bricks > 0.0);
assert!(total_height_of_bricks > 0.0);
// Given the space available, compute how many rows and columns of bricks we can fit
let n_columns = (total_width_of_bricks / (BRICK_SIZE.x + GAP_BETWEEN_BRICKS)).floor() as usize;
let n_rows = (total_height_of_bricks / (BRICK_SIZE.y + GAP_BETWEEN_BRICKS)).floor() as usize;
let n_vertical_gaps = n_columns - 1;
// Because we need to round the number of columns,
// the space on the top and sides of the bricks only captures a lower bound, not an exact value
let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0;
let left_edge_of_bricks = center_of_bricks
// Space taken up by the bricks
- (n_columns as f32 / 2.0 * BRICK_SIZE.x)
// Space taken up by the gaps
- n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS;
// In Bevy, the `translation` of an entity describes the center point,
// not its bottom-left corner
let offset_x = left_edge_of_bricks + BRICK_SIZE.x / 2.;
let offset_y = bottom_edge_of_bricks + BRICK_SIZE.y / 2.;
for row in 0..n_rows {
for column in 0..n_columns {
let brick_position = Vec2::new(
offset_x + column as f32 * (BRICK_SIZE.x + GAP_BETWEEN_BRICKS),
offset_y + row as f32 * (BRICK_SIZE.y + GAP_BETWEEN_BRICKS),
);
// brick
commands.spawn((
SpriteBundle {
sprite: Sprite {
color: BRICK_COLOR,
..default()
},
transform: Transform {
translation: brick_position.extend(0.0),
scale: Vec3::new(BRICK_SIZE.x, BRICK_SIZE.y, 1.0),
..default()
},
..default()
},
Brick,
Collider,
));
}
}
}
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413
const RECTANGLE: Rectangle = Rectangle {
half_size: Vec2::new(SMALL_2D, BIG_2D),
};
const CUBOID: Cuboid = Cuboid {
half_size: Vec3::new(BIG_3D, SMALL_3D, BIG_3D),
};
const CIRCLE: Circle = Circle { radius: BIG_2D };
const SPHERE: Sphere = Sphere { radius: BIG_3D };
const ELLIPSE: Ellipse = Ellipse {
half_size: Vec2::new(BIG_2D, SMALL_2D),
};
const TRIANGLE: Triangle2d = Triangle2d {
vertices: [
Vec2::new(SMALL_2D, 0.0),
Vec2::new(0.0, SMALL_2D),
Vec2::new(-SMALL_2D, 0.0),
],
};
const PLANE_2D: Plane2d = Plane2d {
normal: Direction2d::Y,
};
const PLANE_3D: Plane3d = Plane3d {
normal: Direction3d::Y,
};
const LINE2D: Line2d = Line2d {
direction: Direction2d::X,
};
const LINE3D: Line3d = Line3d {
direction: Direction3d::X,
};
const SEGMENT_2D: Segment2d = Segment2d {
direction: Direction2d::X,
half_length: BIG_2D,
};
const SEGMENT_3D: Segment3d = Segment3d {
direction: Direction3d::X,
half_length: BIG_3D,
};
const POLYLINE_2D: Polyline2d<4> = Polyline2d {
vertices: [
Vec2::new(-BIG_2D, -SMALL_2D),
Vec2::new(-SMALL_2D, SMALL_2D),
Vec2::new(SMALL_2D, -SMALL_2D),
Vec2::new(BIG_2D, SMALL_2D),
],
};
const POLYLINE_3D: Polyline3d<4> = Polyline3d {
vertices: [
Vec3::new(-BIG_3D, -SMALL_3D, -SMALL_3D),
Vec3::new(SMALL_3D, SMALL_3D, 0.0),
Vec3::new(-SMALL_3D, -SMALL_3D, 0.0),
Vec3::new(BIG_3D, SMALL_3D, SMALL_3D),
],
};
const POLYGON_2D: Polygon<5> = Polygon {
vertices: [
Vec2::new(-BIG_2D, -SMALL_2D),
Vec2::new(BIG_2D, -SMALL_2D),
Vec2::new(BIG_2D, SMALL_2D),
Vec2::new(0.0, 0.0),
Vec2::new(-BIG_2D, SMALL_2D),
],
};
const REGULAR_POLYGON: RegularPolygon = RegularPolygon {
circumcircle: Circle { radius: BIG_2D },
sides: 5,
};
const CAPSULE_2D: Capsule2d = Capsule2d {
radius: SMALL_2D,
half_length: SMALL_2D,
};
const CAPSULE_3D: Capsule3d = Capsule3d {
radius: SMALL_3D,
half_length: SMALL_3D,
};
const CYLINDER: Cylinder = Cylinder {
radius: SMALL_3D,
half_height: SMALL_3D,
};
const CONE: Cone = Cone {
radius: BIG_3D,
height: BIG_3D,
};
const CONICAL_FRUSTRUM: ConicalFrustum = ConicalFrustum {
radius_top: BIG_3D,
radius_bottom: SMALL_3D,
height: BIG_3D,
};
const TORUS: Torus = Torus {
minor_radius: SMALL_3D / 2.0,
major_radius: SMALL_3D * 1.5,
};
fn setup_cameras(mut commands: Commands) {
let start_in_2d = true;
let make_camera = |is_active| Camera {
is_active,
..Default::default()
};
commands.spawn(Camera2dBundle {
camera: make_camera(start_in_2d),
..Default::default()
});
commands.spawn(Camera3dBundle {
camera: make_camera(!start_in_2d),
transform: Transform::from_xyz(0.0, 10.0, 0.0).looking_at(Vec3::ZERO, Vec3::Z),
..Default::default()
});
}
fn setup_ambient_light(mut ambient_light: ResMut<AmbientLight>) {
ambient_light.brightness = 50.0;
}
fn setup_lights(mut commands: Commands) {
commands.spawn(PointLightBundle {
point_light: PointLight {
intensity: 5000.0,
..default()
},
transform: Transform::from_translation(Vec3::new(-LEFT_RIGHT_OFFSET_3D, 2.0, 0.0))
.looking_at(Vec3::new(-LEFT_RIGHT_OFFSET_3D, 0.0, 0.0), Vec3::Y),
..default()
});
}
/// Marker component for header text
#[derive(Debug, Clone, Component, Default, Reflect)]
pub struct HeaderText;
/// Marker component for header node
#[derive(Debug, Clone, Component, Default, Reflect)]
pub struct HeaderNode;
fn update_active_cameras(
state: Res<State<CameraActive>>,
mut camera_2d: Query<(Entity, &mut Camera), With<Camera2d>>,
mut camera_3d: Query<(Entity, &mut Camera), (With<Camera3d>, Without<Camera2d>)>,
mut text: Query<&mut TargetCamera, With<HeaderNode>>,
) {
let (entity_2d, mut cam_2d) = camera_2d.single_mut();
let (entity_3d, mut cam_3d) = camera_3d.single_mut();
let is_camera_2d_active = matches!(*state.get(), CameraActive::Dim2);
cam_2d.is_active = is_camera_2d_active;
cam_3d.is_active = !is_camera_2d_active;
let active_camera = if is_camera_2d_active {
entity_2d
} else {
entity_3d
};
text.iter_mut().for_each(|mut target_camera| {
*target_camera = TargetCamera(active_camera);
});
}
fn switch_cameras(current: Res<State<CameraActive>>, mut next: ResMut<NextState<CameraActive>>) {
let next_state = match current.get() {
CameraActive::Dim2 => CameraActive::Dim3,
CameraActive::Dim3 => CameraActive::Dim2,
};
next.set(next_state);
}
fn setup_text(
mut commands: Commands,
asset_server: Res<AssetServer>,
cameras: Query<(Entity, &Camera)>,
) {
let active_camera = cameras
.iter()
.find_map(|(entity, camera)| camera.is_active.then_some(entity))
.expect("run condition ensures existence");
let text = format!("{text}", text = PrimitiveSelected::default());
let font_size = 24.0;
let font: Handle<Font> = asset_server.load("fonts/FiraMono-Medium.ttf");
let style = TextStyle {
font,
font_size,
color: Color::WHITE,
};
let instructions = "Press 'C' to switch between 2D and 3D mode\n\
Press 'Up' or 'Down' to switch to the next/previous primitive";
let text = [
TextSection::new("Primitive: ", style.clone()),
TextSection::new(text, style.clone()),
TextSection::new("\n\n", style.clone()),
TextSection::new(instructions, style.clone()),
TextSection::new("\n\n", style.clone()),
TextSection::new(
"(If nothing is displayed, there's no rendering support yet)",
style.clone(),
),
];
commands
.spawn((
HeaderNode,
NodeBundle {
style: Style {
justify_self: JustifySelf::Center,
top: Val::Px(5.0),
..Default::default()
},
..Default::default()
},
TargetCamera(active_camera),
))
.with_children(|parent| {
parent.spawn((
HeaderText,
TextBundle::from_sections(text).with_text_justify(JustifyText::Center),
));
});
}
fn update_text(
primitive_state: Res<State<PrimitiveSelected>>,
mut header: Query<&mut Text, With<HeaderText>>,
) {
let new_text = format!("{text}", text = primitive_state.get());
header.iter_mut().for_each(|mut header_text| {
if let Some(kind) = header_text.sections.get_mut(1) {
kind.value = new_text.clone();
};
});
}
fn switch_to_next_primitive(
current: Res<State<PrimitiveSelected>>,
mut next: ResMut<NextState<PrimitiveSelected>>,
) {
let next_state = current.get().next();
next.set(next_state);
}
fn switch_to_previous_primitive(
current: Res<State<PrimitiveSelected>>,
mut next: ResMut<NextState<PrimitiveSelected>>,
) {
let next_state = current.get().previous();
next.set(next_state);
}
fn in_mode(active: CameraActive) -> impl Fn(Res<State<CameraActive>>) -> bool {
move |state| *state.get() == active
}
fn draw_gizmos_2d(mut gizmos: Gizmos, state: Res<State<PrimitiveSelected>>, time: Res<Time>) {
const POSITION: Vec2 = Vec2::new(-LEFT_RIGHT_OFFSET_2D, 0.0);
4 5 6 7 8 9 10 11 12 13 14 15
fn main() {
App::new()
.insert_resource(ResolutionSettings {
large: Vec2::new(1920.0, 1080.0),
medium: Vec2::new(800.0, 600.0),
small: Vec2::new(640.0, 360.0),
})
.add_plugins(DefaultPlugins)
.add_systems(Startup, (setup_camera, setup_ui))
.add_systems(Update, (on_resize_system, toggle_resolution))
.run();
}
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
fn setup_2d(mut commands: Commands) {
commands.spawn(Camera2dBundle {
camera: Camera {
// render the 2d camera after the 3d camera
order: 1,
// do not use a clear color
clear_color: ClearColorConfig::None,
..default()
},
..default()
});
commands.spawn(SpriteBundle {
sprite: Sprite {
color: Color::rgb(0.25, 0.25, 0.75),
custom_size: Some(Vec2::new(50.0, 50.0)),
..default()
},
..default()
});
}
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
fn setup_2d(mut commands: Commands) {
commands.spawn(Camera2dBundle {
camera: Camera {
// render the 2d camera after the 3d camera
order: 1,
// do not use a clear color
clear_color: ClearColorConfig::None,
..default()
},
..default()
});
commands.spawn(SpriteBundle {
sprite: Sprite {
color: Color::rgb(0.25, 0.25, 0.75),
custom_size: Some(Vec2::new(50.0, 50.0)),
..default()
},
..default()
});
}
- examples/ecs/parallel_query.rs
- examples/shader/compute_shader_game_of_life.rs
- examples/2d/sprite_sheet.rs
- examples/2d/2d_shapes.rs
- examples/stress_tests/many_glyphs.rs
- examples/2d/2d_gizmos.rs
- examples/stress_tests/many_sprites.rs
- examples/ui/ui_texture_atlas.rs
- examples/stress_tests/many_animated_sprites.rs
- examples/games/contributors.rs
- examples/2d/bounding_2d.rs
- examples/2d/sprite_slice.rs
- examples/stress_tests/bevymark.rs
- examples/2d/text2d.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?
More examples
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425
fn aabb_cast_system(
mut gizmos: Gizmos,
time: Res<Time>,
mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
) {
let ray_cast = get_and_draw_ray(&mut gizmos, &time);
let aabb_cast = AabbCast2d {
aabb: Aabb2d::new(Vec2::ZERO, Vec2::splat(15.)),
ray: ray_cast,
};
for (volume, mut intersects) in volumes.iter_mut() {
let toi = match *volume {
CurrentVolume::Aabb(a) => aabb_cast.aabb_collision_at(a),
CurrentVolume::Circle(_) => None,
};
**intersects = toi.is_some();
if let Some(toi) = toi {
gizmos.rect_2d(
aabb_cast.ray.ray.origin
+ *aabb_cast.ray.ray.direction * toi
+ aabb_cast.aabb.center(),
0.,
aabb_cast.aabb.half_size() * 2.,
Color::GREEN,
);
}
}
}
fn bounding_circle_cast_system(
mut gizmos: Gizmos,
time: Res<Time>,
mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
) {
let ray_cast = get_and_draw_ray(&mut gizmos, &time);
let circle_cast = BoundingCircleCast {
circle: BoundingCircle::new(Vec2::ZERO, 15.),
ray: ray_cast,
};
for (volume, mut intersects) in volumes.iter_mut() {
let toi = match *volume {
CurrentVolume::Aabb(_) => None,
CurrentVolume::Circle(c) => circle_cast.circle_collision_at(c),
};
**intersects = toi.is_some();
if let Some(toi) = toi {
gizmos.circle_2d(
circle_cast.ray.ray.origin
+ *circle_cast.ray.ray.direction * toi
+ circle_cast.circle.center(),
circle_cast.circle.radius(),
Color::GREEN,
);
}
}
}
fn get_intersection_position(time: &Time) -> Vec2 {
let x = (0.8 * time.elapsed_seconds()).cos() * 250.;
let y = (0.4 * time.elapsed_seconds()).sin() * 100.;
Vec2::new(x, y)
}
fn aabb_intersection_system(
mut gizmos: Gizmos,
time: Res<Time>,
mut volumes: Query<(&CurrentVolume, &mut Intersects)>,
) {
let center = get_intersection_position(&time);
let aabb = Aabb2d::new(center, Vec2::splat(50.));
gizmos.rect_2d(center, 0., aabb.half_size() * 2., Color::YELLOW);
for (volume, mut intersects) in volumes.iter_mut() {
let hit = match volume {
CurrentVolume::Aabb(a) => aabb.intersects(a),
CurrentVolume::Circle(c) => aabb.intersects(c),
};
**intersects = hit;
}
}
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
fn draw_example_collection(
mut gizmos: Gizmos,
mut my_gizmos: Gizmos<MyRoundGizmos>,
time: Res<Time>,
) {
gizmos.cuboid(
Transform::from_translation(Vec3::Y * 0.5).with_scale(Vec3::splat(1.25)),
Color::BLACK,
);
gizmos.rect(
Vec3::new(time.elapsed_seconds().cos() * 2.5, 1., 0.),
Quat::from_rotation_y(PI / 2.),
Vec2::splat(2.),
Color::GREEN,
);
my_gizmos.sphere(Vec3::new(1., 0.5, 0.), Quat::IDENTITY, 0.5, Color::RED);
for y in [0., 0.5, 1.] {
gizmos.ray(
Vec3::new(1., y, 0.),
Vec3::new(-3., (time.elapsed_seconds() * 3.).sin(), 0.),
Color::BLUE,
);
}
my_gizmos
.arc_3d(
180.0_f32.to_radians(),
0.2,
Vec3::ONE,
Quat::from_rotation_arc(Vec3::Y, Vec3::ONE.normalize()),
Color::ORANGE,
)
.segments(10);
// Circles have 32 line-segments by default.
my_gizmos.circle(Vec3::ZERO, Direction3d::Y, 3., Color::BLACK);
// You may want to increase this for larger circles or spheres.
my_gizmos
.circle(Vec3::ZERO, Direction3d::Y, 3.1, Color::NAVY)
.segments(64);
my_gizmos
.sphere(Vec3::ZERO, Quat::IDENTITY, 3.2, Color::BLACK)
.circle_segments(64);
gizmos.arrow(Vec3::ZERO, Vec3::ONE * 1.5, Color::YELLOW);
}
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
fn draw_example_collection(
mut gizmos: Gizmos,
mut my_gizmos: Gizmos<MyRoundGizmos>,
time: Res<Time>,
) {
let sin = time.elapsed_seconds().sin() * 50.;
gizmos.line_2d(Vec2::Y * -sin, Vec2::splat(-80.), Color::RED);
gizmos.ray_2d(Vec2::Y * sin, Vec2::splat(80.), Color::GREEN);
// Triangle
gizmos.linestrip_gradient_2d([
(Vec2::Y * 300., Color::BLUE),
(Vec2::new(-255., -155.), Color::RED),
(Vec2::new(255., -155.), Color::GREEN),
(Vec2::Y * 300., Color::BLUE),
]);
gizmos.rect_2d(
Vec2::ZERO,
time.elapsed_seconds() / 3.,
Vec2::splat(300.),
Color::BLACK,
);
// The circles have 32 line-segments by default.
my_gizmos.circle_2d(Vec2::ZERO, 120., Color::BLACK);
my_gizmos.ellipse_2d(
Vec2::ZERO,
time.elapsed_seconds() % TAU,
Vec2::new(100., 200.),
Color::YELLOW_GREEN,
);
// You may want to increase this for larger circles.
my_gizmos
.circle_2d(Vec2::ZERO, 300., Color::NAVY)
.segments(64);
// Arcs default amount of segments is linearly interpolated between
// 1 and 32, using the arc length as scalar.
my_gizmos.arc_2d(Vec2::ZERO, sin / 10., PI / 2., 350., Color::ORANGE_RED);
gizmos.arrow_2d(
Vec2::ZERO,
Vec2::from_angle(sin / -10. + PI / 2.) * 50.,
Color::YELLOW,
);
}
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
fn setup(mut commands: Commands, assets: Res<AssetServer>, color_tint: Res<ColorTint>) {
warn!(include_str!("warning_string.txt"));
let mut rng = rand::thread_rng();
let tile_size = Vec2::splat(64.0);
let map_size = Vec2::splat(320.0);
let half_x = (map_size.x / 2.0) as i32;
let half_y = (map_size.y / 2.0) as i32;
let sprite_handle = assets.load("branding/icon.png");
// Spawns the camera
commands.spawn(Camera2dBundle::default());
// Builds and spawns the sprites
let mut sprites = vec![];
for y in -half_y..half_y {
for x in -half_x..half_x {
let position = Vec2::new(x as f32, y as f32);
let translation = (position * tile_size).extend(rng.gen::<f32>());
let rotation = Quat::from_rotation_z(rng.gen::<f32>());
let scale = Vec3::splat(rng.gen::<f32>() * 2.0);
sprites.push(SpriteBundle {
texture: sprite_handle.clone(),
transform: Transform {
translation,
rotation,
scale,
},
sprite: Sprite {
custom_size: Some(tile_size),
color: if color_tint.0 {
COLORS[rng.gen_range(0..3)]
} else {
Color::WHITE
},
..default()
},
..default()
});
}
}
commands.spawn_batch(sprites);
}
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
fn setup(
mut commands: Commands,
assets: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlasLayout>>,
) {
warn!(include_str!("warning_string.txt"));
let mut rng = rand::thread_rng();
let tile_size = Vec2::splat(64.0);
let map_size = Vec2::splat(320.0);
let half_x = (map_size.x / 2.0) as i32;
let half_y = (map_size.y / 2.0) as i32;
let texture_handle = assets.load("textures/rpg/chars/gabe/gabe-idle-run.png");
let texture_atlas = TextureAtlasLayout::from_grid(Vec2::new(24.0, 24.0), 7, 1, None, None);
let texture_atlas_handle = texture_atlases.add(texture_atlas);
// Spawns the camera
commands.spawn(Camera2dBundle::default());
// Builds and spawns the sprites
for y in -half_y..half_y {
for x in -half_x..half_x {
let position = Vec2::new(x as f32, y as f32);
let translation = (position * tile_size).extend(rng.gen::<f32>());
let rotation = Quat::from_rotation_z(rng.gen::<f32>());
let scale = Vec3::splat(rng.gen::<f32>() * 2.0);
let mut timer = Timer::from_seconds(0.1, TimerMode::Repeating);
timer.set_elapsed(Duration::from_secs_f32(rng.gen::<f32>()));
commands.spawn((
SpriteSheetBundle {
texture: texture_handle.clone(),
atlas: TextureAtlas {
layout: texture_atlas_handle.clone(),
..Default::default()
},
transform: Transform {
translation,
rotation,
scale,
},
sprite: Sprite {
custom_size: Some(tile_size),
..default()
},
..default()
},
AnimationTimer(timer),
));
}
}
}
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?
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
fn rotate_camera(
mut camera_query: Query<&mut Transform, With<Camera3d>>,
app_status: Res<AppStatus>,
) {
if !app_status.rotating {
return;
}
for mut transform in camera_query.iter_mut() {
transform.translation = Vec2::from_angle(ROTATION_SPEED)
.rotate(transform.translation.xz())
.extend(transform.translation.y)
.xzy();
transform.look_at(Vec3::ZERO, Vec3::Y);
}
}
More examples
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
fn rotate_camera(
mut camera_query: Query<&mut Transform, With<Camera3d>>,
time: Res<Time>,
app_status: Res<AppStatus>,
) {
if !app_status.rotating {
return;
}
for mut transform in camera_query.iter_mut() {
transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_seconds())
.rotate(transform.translation.xz())
.extend(transform.translation.y)
.xzy();
transform.look_at(Vec3::ZERO, Vec3::Y);
}
}
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
fn move_system(mut sprites: Query<(&mut Transform, &Velocity)>) {
// Compute the new location of each sprite in parallel on the
// ComputeTaskPool
//
// This example is only for demonstrative purposes. Using a
// ParallelIterator for an inexpensive operation like addition on only 128
// elements will not typically be faster than just using a normal Iterator.
// See the ParallelIterator documentation for more information on when
// to use or not use ParallelIterator over a normal Iterator.
sprites
.par_iter_mut()
.for_each(|(mut transform, velocity)| {
transform.translation += velocity.extend(0.0);
});
}
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
fn system(config: Res<Config>, time: Res<Time>, mut draw: Gizmos) {
if !config.fancy {
for _ in 0..(config.line_count / SYSTEM_COUNT) {
draw.line(Vec3::NEG_Y, Vec3::Y, Color::BLACK);
}
} else {
for i in 0..(config.line_count / SYSTEM_COUNT) {
let angle = i as f32 / (config.line_count / SYSTEM_COUNT) as f32 * TAU;
let vector = Vec2::from(angle.sin_cos()).extend(time.elapsed_seconds().sin());
let start_color = Color::rgb(vector.x, vector.z, 0.5);
let end_color = Color::rgb(-vector.z, -vector.y, 0.5);
draw.line_gradient(vector, -vector, start_color, end_color);
}
}
}
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
fn snap_to_player_system(
mut query: Query<&mut Transform, (With<SnapToPlayer>, Without<Player>)>,
player_query: Query<&Transform, With<Player>>,
) {
let player_transform = player_query.single();
// get the player translation in 2D
let player_translation = player_transform.translation.xy();
for mut enemy_transform in &mut query {
// get the vector from the enemy ship to the player ship in 2D and normalize it.
let to_player = (player_translation - enemy_transform.translation.xy()).normalize();
// get the quaternion to rotate from the initial enemy facing direction to the direction
// facing the player
let rotate_to_player = Quat::from_rotation_arc(Vec3::Y, to_player.extend(0.));
// rotate the enemy to face the player
enemy_transform.rotation = rotate_to_player;
}
}
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
fn new(location: WallLocation) -> WallBundle {
WallBundle {
sprite_bundle: SpriteBundle {
transform: Transform {
// We need to convert our Vec2 into a Vec3, by giving it a z-coordinate
// This is used to determine the order of our sprites
translation: location.position().extend(0.0),
// The z-scale of 2D objects must always be 1.0,
// or their ordering will be affected in surprising ways.
// See https://github.com/bevyengine/bevy/issues/4149
scale: location.size().extend(1.0),
..default()
},
sprite: Sprite {
color: WALL_COLOR,
..default()
},
..default()
},
collider: Collider,
}
}
}
// This resource tracks the game's score
#[derive(Resource)]
struct Scoreboard {
score: usize,
}
#[derive(Component)]
struct ScoreboardUi;
// Add the game's entities to our world
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
asset_server: Res<AssetServer>,
) {
// Camera
commands.spawn(Camera2dBundle::default());
// Sound
let ball_collision_sound = asset_server.load("sounds/breakout_collision.ogg");
commands.insert_resource(CollisionSound(ball_collision_sound));
// Paddle
let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
commands.spawn((
SpriteBundle {
transform: Transform {
translation: Vec3::new(0.0, paddle_y, 0.0),
scale: PADDLE_SIZE,
..default()
},
sprite: Sprite {
color: PADDLE_COLOR,
..default()
},
..default()
},
Paddle,
Collider,
));
// Ball
commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(Circle::default()).into(),
material: materials.add(BALL_COLOR),
transform: Transform::from_translation(BALL_STARTING_POSITION)
.with_scale(Vec2::splat(BALL_DIAMETER).extend(1.)),
..default()
},
Ball,
Velocity(INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED),
));
// Scoreboard
commands.spawn((
ScoreboardUi,
TextBundle::from_sections([
TextSection::new(
"Score: ",
TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: TEXT_COLOR,
..default()
},
),
TextSection::from_style(TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: SCORE_COLOR,
..default()
}),
])
.with_style(Style {
position_type: PositionType::Absolute,
top: SCOREBOARD_TEXT_PADDING,
left: SCOREBOARD_TEXT_PADDING,
..default()
}),
));
// Walls
commands.spawn(WallBundle::new(WallLocation::Left));
commands.spawn(WallBundle::new(WallLocation::Right));
commands.spawn(WallBundle::new(WallLocation::Bottom));
commands.spawn(WallBundle::new(WallLocation::Top));
// Bricks
let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES;
let bottom_edge_of_bricks = paddle_y + GAP_BETWEEN_PADDLE_AND_BRICKS;
let total_height_of_bricks = TOP_WALL - bottom_edge_of_bricks - GAP_BETWEEN_BRICKS_AND_CEILING;
assert!(total_width_of_bricks > 0.0);
assert!(total_height_of_bricks > 0.0);
// Given the space available, compute how many rows and columns of bricks we can fit
let n_columns = (total_width_of_bricks / (BRICK_SIZE.x + GAP_BETWEEN_BRICKS)).floor() as usize;
let n_rows = (total_height_of_bricks / (BRICK_SIZE.y + GAP_BETWEEN_BRICKS)).floor() as usize;
let n_vertical_gaps = n_columns - 1;
// Because we need to round the number of columns,
// the space on the top and sides of the bricks only captures a lower bound, not an exact value
let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0;
let left_edge_of_bricks = center_of_bricks
// Space taken up by the bricks
- (n_columns as f32 / 2.0 * BRICK_SIZE.x)
// Space taken up by the gaps
- n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS;
// In Bevy, the `translation` of an entity describes the center point,
// not its bottom-left corner
let offset_x = left_edge_of_bricks + BRICK_SIZE.x / 2.;
let offset_y = bottom_edge_of_bricks + BRICK_SIZE.y / 2.;
for row in 0..n_rows {
for column in 0..n_columns {
let brick_position = Vec2::new(
offset_x + column as f32 * (BRICK_SIZE.x + GAP_BETWEEN_BRICKS),
offset_y + row as f32 * (BRICK_SIZE.y + GAP_BETWEEN_BRICKS),
);
// brick
commands.spawn((
SpriteBundle {
sprite: Sprite {
color: BRICK_COLOR,
..default()
},
transform: Transform {
translation: brick_position.extend(0.0),
scale: Vec3::new(BRICK_SIZE.x, BRICK_SIZE.y, 1.0),
..default()
},
..default()
},
Brick,
Collider,
));
}
}
}
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?
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
fn rotate_to_player_system(
time: Res<Time>,
mut query: Query<(&RotateToPlayer, &mut Transform), Without<Player>>,
player_query: Query<&Transform, With<Player>>,
) {
let player_transform = player_query.single();
// get the player translation in 2D
let player_translation = player_transform.translation.xy();
for (config, mut enemy_transform) in &mut query {
// get the enemy ship forward vector in 2D (already unit length)
let enemy_forward = (enemy_transform.rotation * Vec3::Y).xy();
// get the vector from the enemy ship to the player ship in 2D and normalize it.
let to_player = (player_translation - enemy_transform.translation.xy()).normalize();
// get the dot product between the enemy forward vector and the direction to the player.
let forward_dot_player = enemy_forward.dot(to_player);
// if the dot product is approximately 1.0 then the enemy is already facing the player and
// we can early out.
if (forward_dot_player - 1.0).abs() < f32::EPSILON {
continue;
}
// get the right vector of the enemy ship in 2D (already unit length)
let enemy_right = (enemy_transform.rotation * Vec3::X).xy();
// get the dot product of the enemy right vector and the direction to the player ship.
// if the dot product is negative them we need to rotate counter clockwise, if it is
// positive we need to rotate clockwise. Note that `copysign` will still return 1.0 if the
// dot product is 0.0 (because the player is directly behind the enemy, so perpendicular
// with the right vector).
let right_dot_player = enemy_right.dot(to_player);
// determine the sign of rotation from the right dot player. We need to negate the sign
// here as the 2D bevy co-ordinate system rotates around +Z, which is pointing out of the
// screen. Due to the right hand rule, positive rotation around +Z is counter clockwise and
// negative is clockwise.
let rotation_sign = -f32::copysign(1.0, right_dot_player);
// limit rotation so we don't overshoot the target. We need to convert our dot product to
// an angle here so we can get an angle of rotation to clamp against.
let max_angle = forward_dot_player.clamp(-1.0, 1.0).acos(); // clamp acos for safety
// calculate angle of rotation with limit
let rotation_angle =
rotation_sign * (config.rotation_speed * time.delta_seconds()).min(max_angle);
// rotate the enemy to face the player
enemy_transform.rotate_z(rotation_angle);
}
}
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), ..]
.
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), ..]
.
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 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
.
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_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(), z.is_nan(), w.is_nan()]
.
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.
sourcepub fn distance(self, rhs: Vec2) -> f32
pub fn distance(self, rhs: Vec2) -> f32
Computes the Euclidean distance between two points in space.
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 not be of length zero, nor very close to zero.
See also Self::try_normalize()
and Self::normalize_or_zero()
.
Panics
Will panic if self
is zero length when glam_assert
is enabled.
Examples found in repository?
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254
fn snap_to_player_system(
mut query: Query<&mut Transform, (With<SnapToPlayer>, Without<Player>)>,
player_query: Query<&Transform, With<Player>>,
) {
let player_transform = player_query.single();
// get the player translation in 2D
let player_translation = player_transform.translation.xy();
for mut enemy_transform in &mut query {
// get the vector from the enemy ship to the player ship in 2D and normalize it.
let to_player = (player_translation - enemy_transform.translation.xy()).normalize();
// get the quaternion to rotate from the initial enemy facing direction to the direction
// facing the player
let rotate_to_player = Quat::from_rotation_arc(Vec3::Y, to_player.extend(0.));
// rotate the enemy to face the player
enemy_transform.rotation = rotate_to_player;
}
}
/// Demonstrates rotating an enemy ship to face the player ship at a given rotation speed.
///
/// This method uses the vector dot product to determine if the enemy is facing the player and
/// if not, which way to rotate to face the player. The dot product on two unit length vectors
/// will return a value between -1.0 and +1.0 which tells us the following about the two vectors:
///
/// * If the result is 1.0 the vectors are pointing in the same direction, the angle between them is
/// 0 degrees.
/// * If the result is 0.0 the vectors are perpendicular, the angle between them is 90 degrees.
/// * If the result is -1.0 the vectors are parallel but pointing in opposite directions, the angle
/// between them is 180 degrees.
/// * If the result is positive the vectors are pointing in roughly the same direction, the angle
/// between them is greater than 0 and less than 90 degrees.
/// * If the result is negative the vectors are pointing in roughly opposite directions, the angle
/// between them is greater than 90 and less than 180 degrees.
///
/// It is possible to get the angle by taking the arc cosine (`acos`) of the dot product. It is
/// often unnecessary to do this though. Beware than `acos` will return `NaN` if the input is less
/// than -1.0 or greater than 1.0. This can happen even when working with unit vectors due to
/// floating point precision loss, so it pays to clamp your dot product value before calling
/// `acos`.
fn rotate_to_player_system(
time: Res<Time>,
mut query: Query<(&RotateToPlayer, &mut Transform), Without<Player>>,
player_query: Query<&Transform, With<Player>>,
) {
let player_transform = player_query.single();
// get the player translation in 2D
let player_translation = player_transform.translation.xy();
for (config, mut enemy_transform) in &mut query {
// get the enemy ship forward vector in 2D (already unit length)
let enemy_forward = (enemy_transform.rotation * Vec3::Y).xy();
// get the vector from the enemy ship to the player ship in 2D and normalize it.
let to_player = (player_translation - enemy_transform.translation.xy()).normalize();
// get the dot product between the enemy forward vector and the direction to the player.
let forward_dot_player = enemy_forward.dot(to_player);
// if the dot product is approximately 1.0 then the enemy is already facing the player and
// we can early out.
if (forward_dot_player - 1.0).abs() < f32::EPSILON {
continue;
}
// get the right vector of the enemy ship in 2D (already unit length)
let enemy_right = (enemy_transform.rotation * Vec3::X).xy();
// get the dot product of the enemy right vector and the direction to the player ship.
// if the dot product is negative them we need to rotate counter clockwise, if it is
// positive we need to rotate clockwise. Note that `copysign` will still return 1.0 if the
// dot product is 0.0 (because the player is directly behind the enemy, so perpendicular
// with the right vector).
let right_dot_player = enemy_right.dot(to_player);
// determine the sign of rotation from the right dot player. We need to negate the sign
// here as the 2D bevy co-ordinate system rotates around +Z, which is pointing out of the
// screen. Due to the right hand rule, positive rotation around +Z is counter clockwise and
// negative is clockwise.
let rotation_sign = -f32::copysign(1.0, right_dot_player);
// limit rotation so we don't overshoot the target. We need to convert our dot product to
// an angle here so we can get an angle of rotation to clamp against.
let max_angle = forward_dot_player.clamp(-1.0, 1.0).acos(); // clamp acos for safety
// calculate angle of rotation with limit
let rotation_angle =
rotation_sign * (config.rotation_speed * time.delta_seconds()).min(max_angle);
// rotate the enemy to face the player
enemy_transform.rotate_z(rotation_angle);
}
}
More examples
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
fn setup(
mut commands: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<ColorMaterial>>,
asset_server: Res<AssetServer>,
) {
// Camera
commands.spawn(Camera2dBundle::default());
// Sound
let ball_collision_sound = asset_server.load("sounds/breakout_collision.ogg");
commands.insert_resource(CollisionSound(ball_collision_sound));
// Paddle
let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
commands.spawn((
SpriteBundle {
transform: Transform {
translation: Vec3::new(0.0, paddle_y, 0.0),
scale: PADDLE_SIZE,
..default()
},
sprite: Sprite {
color: PADDLE_COLOR,
..default()
},
..default()
},
Paddle,
Collider,
));
// Ball
commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(Circle::default()).into(),
material: materials.add(BALL_COLOR),
transform: Transform::from_translation(BALL_STARTING_POSITION)
.with_scale(Vec2::splat(BALL_DIAMETER).extend(1.)),
..default()
},
Ball,
Velocity(INITIAL_BALL_DIRECTION.normalize() * BALL_SPEED),
));
// Scoreboard
commands.spawn((
ScoreboardUi,
TextBundle::from_sections([
TextSection::new(
"Score: ",
TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: TEXT_COLOR,
..default()
},
),
TextSection::from_style(TextStyle {
font_size: SCOREBOARD_FONT_SIZE,
color: SCORE_COLOR,
..default()
}),
])
.with_style(Style {
position_type: PositionType::Absolute,
top: SCOREBOARD_TEXT_PADDING,
left: SCOREBOARD_TEXT_PADDING,
..default()
}),
));
// Walls
commands.spawn(WallBundle::new(WallLocation::Left));
commands.spawn(WallBundle::new(WallLocation::Right));
commands.spawn(WallBundle::new(WallLocation::Bottom));
commands.spawn(WallBundle::new(WallLocation::Top));
// Bricks
let total_width_of_bricks = (RIGHT_WALL - LEFT_WALL) - 2. * GAP_BETWEEN_BRICKS_AND_SIDES;
let bottom_edge_of_bricks = paddle_y + GAP_BETWEEN_PADDLE_AND_BRICKS;
let total_height_of_bricks = TOP_WALL - bottom_edge_of_bricks - GAP_BETWEEN_BRICKS_AND_CEILING;
assert!(total_width_of_bricks > 0.0);
assert!(total_height_of_bricks > 0.0);
// Given the space available, compute how many rows and columns of bricks we can fit
let n_columns = (total_width_of_bricks / (BRICK_SIZE.x + GAP_BETWEEN_BRICKS)).floor() as usize;
let n_rows = (total_height_of_bricks / (BRICK_SIZE.y + GAP_BETWEEN_BRICKS)).floor() as usize;
let n_vertical_gaps = n_columns - 1;
// Because we need to round the number of columns,
// the space on the top and sides of the bricks only captures a lower bound, not an exact value
let center_of_bricks = (LEFT_WALL + RIGHT_WALL) / 2.0;
let left_edge_of_bricks = center_of_bricks
// Space taken up by the bricks
- (n_columns as f32 / 2.0 * BRICK_SIZE.x)
// Space taken up by the gaps
- n_vertical_gaps as f32 / 2.0 * GAP_BETWEEN_BRICKS;
// In Bevy, the `translation` of an entity describes the center point,
// not its bottom-left corner
let offset_x = left_edge_of_bricks + BRICK_SIZE.x / 2.;
let offset_y = bottom_edge_of_bricks + BRICK_SIZE.y / 2.;
for row in 0..n_rows {
for column in 0..n_columns {
let brick_position = Vec2::new(
offset_x + column as f32 * (BRICK_SIZE.x + GAP_BETWEEN_BRICKS),
offset_y + row as f32 * (BRICK_SIZE.y + GAP_BETWEEN_BRICKS),
);
// brick
commands.spawn((
SpriteBundle {
sprite: Sprite {
color: BRICK_COLOR,
..default()
},
transform: Transform {
translation: brick_position.extend(0.0),
scale: Vec3::new(BRICK_SIZE.x, BRICK_SIZE.y, 1.0),
..default()
},
..default()
},
Brick,
Collider,
));
}
}
}
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_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?
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
fn resize_image(
image_mesh: Query<(&Handle<StandardMaterial>, &Handle<Mesh>), With<HDRViewer>>,
materials: Res<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>,
images: Res<Assets<Image>>,
mut image_events: EventReader<AssetEvent<Image>>,
) {
for event in image_events.read() {
let (AssetEvent::Added { id } | AssetEvent::Modified { id }) = event else {
continue;
};
for (mat_h, mesh_h) in &image_mesh {
let Some(mat) = materials.get(mat_h) else {
continue;
};
let Some(ref base_color_texture) = mat.base_color_texture else {
continue;
};
if *id != base_color_texture.id() {
continue;
};
let Some(image_changed) = images.get(*id) else {
continue;
};
let size = image_changed.size_f32().normalize_or_zero() * 1.4;
// Resize Mesh
let quad = Mesh::from(Rectangle::from_size(size));
meshes.insert(mesh_h, quad);
}
}
}
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 1e-6
.
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, e.g. self - self.floor()
.
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 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
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
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
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 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?
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
fn rotate_camera(
mut camera_query: Query<&mut Transform, With<Camera3d>>,
app_status: Res<AppStatus>,
) {
if !app_status.rotating {
return;
}
for mut transform in camera_query.iter_mut() {
transform.translation = Vec2::from_angle(ROTATION_SPEED)
.rotate(transform.translation.xz())
.extend(transform.translation.y)
.xzy();
transform.look_at(Vec3::ZERO, Vec3::Y);
}
}
More examples
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
fn rotate_camera(
mut camera_query: Query<&mut Transform, With<Camera3d>>,
time: Res<Time>,
app_status: Res<AppStatus>,
) {
if !app_status.rotating {
return;
}
for mut transform in camera_query.iter_mut() {
transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_seconds())
.rotate(transform.translation.xz())
.extend(transform.translation.y)
.xzy();
transform.look_at(Vec3::ZERO, Vec3::Y);
}
}
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81
fn draw_example_collection(
mut gizmos: Gizmos,
mut my_gizmos: Gizmos<MyRoundGizmos>,
time: Res<Time>,
) {
let sin = time.elapsed_seconds().sin() * 50.;
gizmos.line_2d(Vec2::Y * -sin, Vec2::splat(-80.), Color::RED);
gizmos.ray_2d(Vec2::Y * sin, Vec2::splat(80.), Color::GREEN);
// Triangle
gizmos.linestrip_gradient_2d([
(Vec2::Y * 300., Color::BLUE),
(Vec2::new(-255., -155.), Color::RED),
(Vec2::new(255., -155.), Color::GREEN),
(Vec2::Y * 300., Color::BLUE),
]);
gizmos.rect_2d(
Vec2::ZERO,
time.elapsed_seconds() / 3.,
Vec2::splat(300.),
Color::BLACK,
);
// The circles have 32 line-segments by default.
my_gizmos.circle_2d(Vec2::ZERO, 120., Color::BLACK);
my_gizmos.ellipse_2d(
Vec2::ZERO,
time.elapsed_seconds() % TAU,
Vec2::new(100., 200.),
Color::YELLOW_GREEN,
);
// You may want to increase this for larger circles.
my_gizmos
.circle_2d(Vec2::ZERO, 300., Color::NAVY)
.segments(64);
// Arcs default amount of segments is linearly interpolated between
// 1 and 32, using the arc length as scalar.
my_gizmos.arc_2d(Vec2::ZERO, sin / 10., PI / 2., 350., Color::ORANGE_RED);
gizmos.arrow_2d(
Vec2::ZERO,
Vec2::from_angle(sin / -10. + PI / 2.) * 50.,
Color::YELLOW,
);
}
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.
sourcepub fn angle_between(self, rhs: Vec2) -> f32
pub fn angle_between(self, rhs: Vec2) -> f32
Returns the angle (in radians) between self
and 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?
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
fn rotate_camera(
mut camera_query: Query<&mut Transform, With<Camera3d>>,
app_status: Res<AppStatus>,
) {
if !app_status.rotating {
return;
}
for mut transform in camera_query.iter_mut() {
transform.translation = Vec2::from_angle(ROTATION_SPEED)
.rotate(transform.translation.xz())
.extend(transform.translation.y)
.xzy();
transform.look_at(Vec3::ZERO, Vec3::Y);
}
}
More examples
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388
fn rotate_camera(
mut camera_query: Query<&mut Transform, With<Camera3d>>,
time: Res<Time>,
app_status: Res<AppStatus>,
) {
if !app_status.rotating {
return;
}
for mut transform in camera_query.iter_mut() {
transform.translation = Vec2::from_angle(ROTATION_SPEED * time.delta_seconds())
.rotate(transform.translation.xz())
.extend(transform.translation.y)
.xzy();
transform.look_at(Vec3::ZERO, Vec3::Y);
}
}
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_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<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 more§impl Animatable for Vec2
impl Animatable for Vec2
§fn blend(inputs: impl Iterator<Item = BlendInput<Vec2>>) -> Vec2
fn blend(inputs: impl Iterator<Item = BlendInput<Vec2>>) -> Vec2
§fn post_process(&mut self, _world: &World)
fn post_process(&mut self, _world: &World)
World
.
Most animatable types do not need to implement this.§impl AsMutVectorParts<f32, 2> for Vec2
impl AsMutVectorParts<f32, 2> for Vec2
fn as_mut_parts(&mut self) -> &mut [f32; 2]
§impl AsRefVectorParts<f32, 2> for Vec2
impl AsRefVectorParts<f32, 2> for Vec2
fn as_ref_parts(&self) -> &[f32; 2]
§impl CreateFrom for Vec2
impl CreateFrom for Vec2
fn create_from<B>(reader: &mut Reader<B>) -> Vec2where
B: BufferRef,
source§impl<'de> Deserialize<'de> for Vec2
impl<'de> Deserialize<'de> for Vec2
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<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 more§impl From<Vec2> for WindowResolution
impl From<Vec2> for WindowResolution
§fn from(res: Vec2) -> WindowResolution
fn from(res: Vec2) -> WindowResolution
§impl FromIterator<Vec2> for BoxedPolygon
impl FromIterator<Vec2> for BoxedPolygon
§fn from_iter<I>(iter: I) -> BoxedPolygonwhere
I: IntoIterator<Item = Vec2>,
fn from_iter<I>(iter: I) -> BoxedPolygonwhere
I: IntoIterator<Item = Vec2>,
§impl FromIterator<Vec2> for BoxedPolyline2d
impl FromIterator<Vec2> for BoxedPolyline2d
§fn from_iter<I>(iter: I) -> BoxedPolyline2dwhere
I: IntoIterator<Item = Vec2>,
fn from_iter<I>(iter: I) -> BoxedPolyline2dwhere
I: IntoIterator<Item = Vec2>,
§impl<const N: usize> FromIterator<Vec2> for Polygon<N>
impl<const N: usize> FromIterator<Vec2> for Polygon<N>
§impl<const N: usize> FromIterator<Vec2> for Polyline2d<N>
impl<const N: usize> FromIterator<Vec2> for Polyline2d<N>
§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>,
§impl FromReflect for Vec2
impl FromReflect for Vec2
§fn from_reflect(reflect: &(dyn Reflect + 'static)) -> Option<Vec2>
fn from_reflect(reflect: &(dyn Reflect + 'static)) -> Option<Vec2>
Self
from a reflected value.§fn take_from_reflect(
reflect: Box<dyn Reflect>
) -> Result<Self, Box<dyn Reflect>>
fn take_from_reflect( reflect: Box<dyn Reflect> ) -> Result<Self, Box<dyn Reflect>>
Self
using,
constructing the value using from_reflect
if that fails. Read more§impl FromVectorParts<f32, 2> for Vec2
impl FromVectorParts<f32, 2> for Vec2
fn from_parts(parts: [f32; 2]) -> Vec2
§impl GetTypeRegistration for Vec2
impl GetTypeRegistration for Vec2
source§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 PartialEq for Vec2
impl PartialEq for Vec2
§impl Reflect for Vec2
impl Reflect for Vec2
§fn get_represented_type_info(&self) -> Option<&'static TypeInfo>
fn get_represented_type_info(&self) -> Option<&'static TypeInfo>
§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut dyn Any
.§fn as_reflect(&self) -> &(dyn Reflect + 'static)
fn as_reflect(&self) -> &(dyn Reflect + 'static)
§fn as_reflect_mut(&mut self) -> &mut (dyn Reflect + 'static)
fn as_reflect_mut(&mut self) -> &mut (dyn Reflect + 'static)
§fn clone_value(&self) -> Box<dyn Reflect>
fn clone_value(&self) -> Box<dyn Reflect>
Reflect
trait object. Read more§fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>
fn set(&mut self, value: Box<dyn Reflect>) -> Result<(), Box<dyn Reflect>>
§fn apply(&mut self, value: &(dyn Reflect + 'static))
fn apply(&mut self, value: &(dyn Reflect + 'static))
§fn reflect_kind(&self) -> ReflectKind
fn reflect_kind(&self) -> ReflectKind
§fn reflect_ref(&self) -> ReflectRef<'_>
fn reflect_ref(&self) -> ReflectRef<'_>
§fn reflect_mut(&mut self) -> ReflectMut<'_>
fn reflect_mut(&mut self) -> ReflectMut<'_>
§fn reflect_owned(self: Box<Vec2>) -> ReflectOwned
fn reflect_owned(self: Box<Vec2>) -> ReflectOwned
§fn reflect_partial_eq(&self, value: &(dyn Reflect + 'static)) -> Option<bool>
fn reflect_partial_eq(&self, value: &(dyn Reflect + 'static)) -> Option<bool>
§fn debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>
fn debug(&self, f: &mut Formatter<'_>) -> Result<(), Error>
§fn reflect_hash(&self) -> Option<u64>
fn reflect_hash(&self) -> Option<u64>
§fn serializable(&self) -> Option<Serializable<'_>>
fn serializable(&self) -> Option<Serializable<'_>>
§fn is_dynamic(&self) -> bool
fn is_dynamic(&self) -> bool
source§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
impl Serialize for Vec2
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,
§impl ShaderSize for Vec2where
f32: ShaderSize,
impl ShaderSize for Vec2where
f32: ShaderSize,
§const SHADER_SIZE: NonZero<u64> = _
const SHADER_SIZE: NonZero<u64> = _
ShaderType::min_size
)§impl ShaderType for Vec2where
f32: ShaderSize,
impl ShaderType for Vec2where
f32: ShaderSize,
§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 more§impl Struct for Vec2
impl Struct for Vec2
§fn field(&self, name: &str) -> Option<&(dyn Reflect + 'static)>
fn field(&self, name: &str) -> Option<&(dyn Reflect + 'static)>
name
as a &dyn Reflect
.§fn field_mut(&mut self, name: &str) -> Option<&mut (dyn Reflect + 'static)>
fn field_mut(&mut self, name: &str) -> Option<&mut (dyn Reflect + 'static)>
name
as a
&mut dyn Reflect
.§fn field_at(&self, index: usize) -> Option<&(dyn Reflect + 'static)>
fn field_at(&self, index: usize) -> Option<&(dyn Reflect + 'static)>
index
as a
&dyn Reflect
.§fn field_at_mut(&mut self, index: usize) -> Option<&mut (dyn Reflect + 'static)>
fn field_at_mut(&mut self, index: usize) -> Option<&mut (dyn Reflect + 'static)>
index
as a &mut dyn Reflect
.§fn iter_fields(&self) -> FieldIter<'_> ⓘ
fn iter_fields(&self) -> FieldIter<'_> ⓘ
§fn clone_dynamic(&self) -> DynamicStruct
fn clone_dynamic(&self) -> DynamicStruct
DynamicStruct
.source§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 more§impl TryFrom<Vec2> for Direction2d
impl TryFrom<Vec2> for Direction2d
§type Error = InvalidDirectionError
type Error = InvalidDirectionError
§fn try_from(
value: Vec2
) -> Result<Direction2d, <Direction2d as TryFrom<Vec2>>::Error>
fn try_from( value: Vec2 ) -> Result<Direction2d, <Direction2d as TryFrom<Vec2>>::Error>
§impl TypePath for Vec2
impl TypePath for Vec2
§fn short_type_path() -> &'static str
fn short_type_path() -> &'static str
§fn type_ident() -> Option<&'static str>
fn type_ident() -> Option<&'static str>
§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 xy(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
impl Copy for Vec2
impl Pod for Vec2
impl Point for Vec2
impl StructuralPartialEq for Vec2
Auto Trait Implementations§
impl RefUnwindSafe for Vec2
impl Send for Vec2
impl Sync for Vec2
impl Unpin for Vec2
impl UnwindSafe for Vec2
Blanket Implementations§
§impl<T, U> AsBindGroupShaderType<U> for T
impl<T, U> AsBindGroupShaderType<U> for T
§fn as_bind_group_shader_type(&self, _images: &RenderAssets<Image>) -> U
fn as_bind_group_shader_type(&self, _images: &RenderAssets<Image>) -> 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
§impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
impl<T> CheckedBitPattern for Twhere
T: AnyBitPattern,
§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
.§fn is_valid_bit_pattern(_bits: &T) -> bool
fn is_valid_bit_pattern(_bits: &T) -> bool
bits
as &Self
.§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
§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
.§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
.§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.§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.§impl<T> DowncastSync for T
impl<T> DowncastSync for T
§impl<T> DynamicTypePath for Twhere
T: TypePath,
impl<T> DynamicTypePath for Twhere
T: TypePath,
§fn reflect_type_path(&self) -> &str
fn reflect_type_path(&self) -> &str
TypePath::type_path
.§fn reflect_short_type_path(&self) -> &str
fn reflect_short_type_path(&self) -> &str
§fn reflect_type_ident(&self) -> Option<&str>
fn reflect_type_ident(&self) -> Option<&str>
TypePath::type_ident
.§fn reflect_crate_name(&self) -> Option<&str>
fn reflect_crate_name(&self) -> Option<&str>
TypePath::crate_name
.§fn reflect_module_path(&self) -> Option<&str>
fn reflect_module_path(&self) -> Option<&str>
§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> FromWorld for Twhere
T: Default,
impl<T> FromWorld for Twhere
T: Default,
§fn from_world(_world: &mut World) -> T
fn from_world(_world: &mut World) -> T
Self
using data from the given World
.§impl<T> GetPath for T
impl<T> GetPath for T
§fn reflect_path<'p>(
&self,
path: impl ReflectPath<'p>
) -> Result<&(dyn Reflect + 'static), ReflectPathError<'p>>
fn reflect_path<'p>( &self, path: impl ReflectPath<'p> ) -> Result<&(dyn Reflect + 'static), ReflectPathError<'p>>
path
. Read more§fn reflect_path_mut<'p>(
&mut self,
path: impl ReflectPath<'p>
) -> Result<&mut (dyn Reflect + 'static), ReflectPathError<'p>>
fn reflect_path_mut<'p>( &mut self, path: impl ReflectPath<'p> ) -> Result<&mut (dyn Reflect + 'static), ReflectPathError<'p>>
path
. Read more§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 more§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 more