pub struct Aabb2d {
pub min: Vec2,
pub max: Vec2,
}
Expand description
A 2D axis-aligned bounding box, or bounding rectangle
Fields§
§min: Vec2
The minimum, conventionally bottom-left, point of the box
max: Vec2
The maximum, conventionally top-right, point of the box
Implementations§
§impl Aabb2d
impl Aabb2d
pub fn new(center: Vec2, half_size: Vec2) -> Aabb2d
pub fn new(center: Vec2, half_size: Vec2) -> Aabb2d
Constructs an AABB from its center and half-size.
Examples found in repository?
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 414 415 416 417 418 419
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,
0.,
aabb_cast.aabb.half_size() * 2.,
LIME,
);
}
}
}
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.radius(),
LIME,
);
}
}
}
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., 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;
}
}
More examples
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
fn collisions(
windows: Query<&Window>,
mut query: Query<(&mut Velocity, &mut Transform), With<Contributor>>,
) {
let window = windows.single();
let window_size = window.size();
let collision_area = Aabb2d::new(Vec2::ZERO, (window_size - SPRITE_SIZE) / 2.);
// The maximum height the birbs should try to reach is one birb below the top of the window.
let max_bounce_height = (window_size.y - SPRITE_SIZE * 2.0).max(0.0);
let min_bounce_height = max_bounce_height * 0.4;
let mut rng = rand::thread_rng();
for (mut velocity, mut transform) in &mut query {
// Clamp the translation to not go out of the bounds
if transform.translation.y < collision_area.min.y {
transform.translation.y = collision_area.min.y;
// How high this birb will bounce.
let bounce_height = rng.gen_range(min_bounce_height..=max_bounce_height);
// Apply the velocity that would bounce the birb up to bounce_height.
velocity.translation.y = (bounce_height * GRAVITY * 2.).sqrt();
}
// Birbs might hit the ceiling if the window is resized.
// If they do, bounce them.
if transform.translation.y > collision_area.max.y {
transform.translation.y = collision_area.max.y;
velocity.translation.y *= -1.0;
}
// On side walls flip the horizontal velocity
if transform.translation.x < collision_area.min.x {
transform.translation.x = collision_area.min.x;
velocity.translation.x *= -1.0;
velocity.rotation *= -1.0;
}
if transform.translation.x > collision_area.max.x {
transform.translation.x = collision_area.max.x;
velocity.translation.x *= -1.0;
velocity.rotation *= -1.0;
}
}
}
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
fn check_for_collisions(
mut commands: Commands,
mut score: ResMut<Score>,
mut ball_query: Query<(&mut Velocity, &Transform), With<Ball>>,
collider_query: Query<(Entity, &Transform, Option<&Brick>), With<Collider>>,
mut collision_events: EventWriter<CollisionEvent>,
) {
let (mut ball_velocity, ball_transform) = ball_query.single_mut();
for (collider_entity, collider_transform, maybe_brick) in &collider_query {
let collision = ball_collision(
BoundingCircle::new(ball_transform.translation.truncate(), BALL_DIAMETER / 2.),
Aabb2d::new(
collider_transform.translation.truncate(),
collider_transform.scale.truncate() / 2.,
),
);
if let Some(collision) = collision {
// Sends a collision event so that other systems can react to the collision
collision_events.send_default();
// Bricks should be despawned and increment the scoreboard on collision
if maybe_brick.is_some() {
commands.entity(collider_entity).despawn();
**score += 1;
}
// Reflect the ball's velocity when it collides
let mut reflect_x = false;
let mut reflect_y = false;
// Reflect only if the velocity is in the opposite direction of the collision
// This prevents the ball from getting stuck inside the bar
match collision {
Collision::Left => reflect_x = ball_velocity.x > 0.0,
Collision::Right => reflect_x = ball_velocity.x < 0.0,
Collision::Top => reflect_y = ball_velocity.y < 0.0,
Collision::Bottom => reflect_y = ball_velocity.y > 0.0,
}
// Reflect velocity on the x-axis if we hit something on the x-axis
if reflect_x {
ball_velocity.x = -ball_velocity.x;
}
// Reflect velocity on the y-axis if we hit something on the y-axis
if reflect_y {
ball_velocity.y = -ball_velocity.y;
}
}
}
}
pub fn from_point_cloud(
translation: Vec2,
rotation: impl Into<Rotation2d>,
points: &[Vec2]
) -> Aabb2d
pub fn from_point_cloud( translation: Vec2, rotation: impl Into<Rotation2d>, points: &[Vec2] ) -> Aabb2d
pub fn bounding_circle(&self) -> BoundingCircle
pub fn bounding_circle(&self) -> BoundingCircle
Computes the smallest BoundingCircle
containing this Aabb2d
.
pub fn closest_point(&self, point: Vec2) -> Vec2
pub fn closest_point(&self, point: Vec2) -> Vec2
Finds the point on the AABB that is closest to the given point
.
If the point is outside the AABB, the returned point will be on the perimeter of the AABB. Otherwise, it will be inside the AABB and returned as is.
Examples found in repository?
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461
fn ball_collision(ball: BoundingCircle, bounding_box: Aabb2d) -> Option<Collision> {
if !ball.intersects(&bounding_box) {
return None;
}
let closest = bounding_box.closest_point(ball.center());
let offset = ball.center() - closest;
let side = if offset.x.abs() > offset.y.abs() {
if offset.x < 0. {
Collision::Left
} else {
Collision::Right
}
} else if offset.y > 0. {
Collision::Top
} else {
Collision::Bottom
};
Some(side)
}
Trait Implementations§
§impl BoundingVolume for Aabb2d
impl BoundingVolume for Aabb2d
§fn transformed_by(
self,
translation: impl Into<<Aabb2d as BoundingVolume>::Translation>,
rotation: impl Into<<Aabb2d as BoundingVolume>::Rotation>
) -> Aabb2d
fn transformed_by( self, translation: impl Into<<Aabb2d as BoundingVolume>::Translation>, rotation: impl Into<<Aabb2d as BoundingVolume>::Rotation> ) -> Aabb2d
Transforms the bounding volume by first rotating it around the origin and then applying a translation.
The result is an Axis-Aligned Bounding Box that encompasses the rotated shape.
Note that the result may not be as tightly fitting as the original, and repeated rotations can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB, and consider storing the original AABB and rotating that every time instead.
§fn transform_by(
&mut self,
translation: impl Into<<Aabb2d as BoundingVolume>::Translation>,
rotation: impl Into<<Aabb2d as BoundingVolume>::Rotation>
)
fn transform_by( &mut self, translation: impl Into<<Aabb2d as BoundingVolume>::Translation>, rotation: impl Into<<Aabb2d as BoundingVolume>::Rotation> )
Transforms the bounding volume by first rotating it around the origin and then applying a translation.
The result is an Axis-Aligned Bounding Box that encompasses the rotated shape.
Note that the result may not be as tightly fitting as the original, and repeated rotations can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB, and consider storing the original AABB and rotating that every time instead.
§fn rotated_by(
self,
rotation: impl Into<<Aabb2d as BoundingVolume>::Rotation>
) -> Aabb2d
fn rotated_by( self, rotation: impl Into<<Aabb2d as BoundingVolume>::Rotation> ) -> Aabb2d
Rotates the bounding volume around the origin by the given rotation.
The result is an Axis-Aligned Bounding Box that encompasses the rotated shape.
Note that the result may not be as tightly fitting as the original, and repeated rotations can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB, and consider storing the original AABB and rotating that every time instead.
§fn rotate_by(
&mut self,
rotation: impl Into<<Aabb2d as BoundingVolume>::Rotation>
)
fn rotate_by( &mut self, rotation: impl Into<<Aabb2d as BoundingVolume>::Rotation> )
Rotates the bounding volume around the origin by the given rotation.
The result is an Axis-Aligned Bounding Box that encompasses the rotated shape.
Note that the result may not be as tightly fitting as the original, and repeated rotations can cause the AABB to grow indefinitely. Avoid applying multiple rotations to the same AABB, and consider storing the original AABB and rotating that every time instead.
§type Translation = Vec2
type Translation = Vec2
Vec2
for 2D and Vec3
for 3D.§type Rotation = Rotation2d
type Rotation = Rotation2d
f32
for 2D and Quat
for 3D.§type HalfSize = Vec2
type HalfSize = Vec2
f32
radius for a circle, or a Vec3
with half sizes for x, y and z for a 3D axis-aligned
bounding box§fn center(&self) -> <Aabb2d as BoundingVolume>::Translation
fn center(&self) -> <Aabb2d as BoundingVolume>::Translation
§fn half_size(&self) -> <Aabb2d as BoundingVolume>::HalfSize
fn half_size(&self) -> <Aabb2d as BoundingVolume>::HalfSize
§fn visible_area(&self) -> f32
fn visible_area(&self) -> f32
§fn merge(&self, other: &Aabb2d) -> Aabb2d
fn merge(&self, other: &Aabb2d) -> Aabb2d
self
and other
.§fn grow(
&self,
amount: impl Into<<Aabb2d as BoundingVolume>::HalfSize>
) -> Aabb2d
fn grow( &self, amount: impl Into<<Aabb2d as BoundingVolume>::HalfSize> ) -> Aabb2d
§fn shrink(
&self,
amount: impl Into<<Aabb2d as BoundingVolume>::HalfSize>
) -> Aabb2d
fn shrink( &self, amount: impl Into<<Aabb2d as BoundingVolume>::HalfSize> ) -> Aabb2d
§fn scale_around_center(
&self,
scale: impl Into<<Aabb2d as BoundingVolume>::HalfSize>
) -> Aabb2d
fn scale_around_center( &self, scale: impl Into<<Aabb2d as BoundingVolume>::HalfSize> ) -> Aabb2d
§fn translate_by(
&mut self,
translation: impl Into<<Aabb2d as BoundingVolume>::Translation>
)
fn translate_by( &mut self, translation: impl Into<<Aabb2d as BoundingVolume>::Translation> )
§fn translated_by(self, translation: impl Into<Self::Translation>) -> Self
fn translated_by(self, translation: impl Into<Self::Translation>) -> Self
§impl IntersectsVolume<Aabb2d> for Aabb2d
impl IntersectsVolume<Aabb2d> for Aabb2d
§fn intersects(&self, other: &Aabb2d) -> bool
fn intersects(&self, other: &Aabb2d) -> bool
§impl IntersectsVolume<Aabb2d> for AabbCast2d
impl IntersectsVolume<Aabb2d> for AabbCast2d
§fn intersects(&self, volume: &Aabb2d) -> bool
fn intersects(&self, volume: &Aabb2d) -> bool
§impl IntersectsVolume<Aabb2d> for BoundingCircle
impl IntersectsVolume<Aabb2d> for BoundingCircle
§fn intersects(&self, aabb: &Aabb2d) -> bool
fn intersects(&self, aabb: &Aabb2d) -> bool
§impl IntersectsVolume<Aabb2d> for RayCast2d
impl IntersectsVolume<Aabb2d> for RayCast2d
§fn intersects(&self, volume: &Aabb2d) -> bool
fn intersects(&self, volume: &Aabb2d) -> bool
§impl IntersectsVolume<BoundingCircle> for Aabb2d
impl IntersectsVolume<BoundingCircle> for Aabb2d
§fn intersects(&self, circle: &BoundingCircle) -> bool
fn intersects(&self, circle: &BoundingCircle) -> bool
impl Copy for Aabb2d
Auto Trait Implementations§
impl Freeze for Aabb2d
impl RefUnwindSafe for Aabb2d
impl Send for Aabb2d
impl Sync for Aabb2d
impl Unpin for Aabb2d
impl UnwindSafe for Aabb2d
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<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
§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<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§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 more