Struct bevy::math::bounding::Aabb2d

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

pub fn new(center: Vec2, half_size: Vec2) -> Aabb2d

Constructs an AABB from its center and half-size.

Examples found in repository?
examples/2d/bounding_2d.rs (line 346)
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
Hide additional examples
examples/games/contributors.rs (line 243)
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;
        }
    }
}
examples/games/breakout.rs (lines 372-375)
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

Computes the smallest Aabb2d containing the given set of points, transformed by translation and rotation.

§Panics

Panics if the given set of points is empty.

pub fn bounding_circle(&self) -> BoundingCircle

Computes the smallest BoundingCircle containing this Aabb2d.

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?
examples/games/breakout.rs (line 446)
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

§

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> )

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

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> )

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

The position type used for the volume. This should be Vec2 for 2D and Vec3 for 3D.
§

type Rotation = Rotation2d

The rotation type used for the volume. This should be f32 for 2D and Quat for 3D.
§

type HalfSize = Vec2

The type used for the size of the bounding volume. Usually a half size. For example an 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

Returns the center of the bounding volume.
§

fn half_size(&self) -> <Aabb2d as BoundingVolume>::HalfSize

Returns the half size of the bounding volume.
§

fn visible_area(&self) -> f32

Computes the visible surface area of the bounding volume. This method can be useful to make decisions about merging bounding volumes, using a Surface Area Heuristic. Read more
§

fn contains(&self, other: &Aabb2d) -> bool

Checks if this bounding volume contains another one.
§

fn merge(&self, other: &Aabb2d) -> Aabb2d

Computes the smallest bounding volume that contains both self and other.
§

fn grow( &self, amount: impl Into<<Aabb2d as BoundingVolume>::HalfSize> ) -> Aabb2d

Increases the size of the bounding volume in each direction by the given amount.
§

fn shrink( &self, amount: impl Into<<Aabb2d as BoundingVolume>::HalfSize> ) -> Aabb2d

Decreases the size of the bounding volume in each direction by the given amount.
§

fn scale_around_center( &self, scale: impl Into<<Aabb2d as BoundingVolume>::HalfSize> ) -> Aabb2d

Scale the size of the bounding volume around its center by the given amount
§

fn translate_by( &mut self, translation: impl Into<<Aabb2d as BoundingVolume>::Translation> )

Translates the bounding volume by the given translation.
§

fn translated_by(self, translation: impl Into<Self::Translation>) -> Self

Translates the bounding volume by the given translation.
§

impl Clone for Aabb2d

§

fn clone(&self) -> Aabb2d

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
§

impl Debug for Aabb2d

§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
§

impl IntersectsVolume<Aabb2d> for Aabb2d

§

fn intersects(&self, other: &Aabb2d) -> bool

Check if a volume intersects with this intersection test
§

impl IntersectsVolume<Aabb2d> for AabbCast2d

§

fn intersects(&self, volume: &Aabb2d) -> bool

Check if a volume intersects with this intersection test
§

impl IntersectsVolume<Aabb2d> for BoundingCircle

§

fn intersects(&self, aabb: &Aabb2d) -> bool

Check if a volume intersects with this intersection test
§

impl IntersectsVolume<Aabb2d> for RayCast2d

§

fn intersects(&self, volume: &Aabb2d) -> bool

Check if a volume intersects with this intersection test
§

impl IntersectsVolume<BoundingCircle> for Aabb2d

§

fn intersects(&self, circle: &BoundingCircle) -> bool

Check if a volume intersects with this intersection test
§

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§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
§

impl<T, U> AsBindGroupShaderType<U> for T
where U: ShaderType, &'a T: for<'a> Into<U>,

§

fn as_bind_group_shader_type(&self, _images: &RenderAssets<GpuImage>) -> U

Return the T ShaderType for self. When used in AsBindGroup derives, it is safe to assume that all images in self exist.
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<T> Downcast<T> for T

§

fn downcast(&self) -> &T

§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert 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>

Convert 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)

Convert &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)

Convert &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
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<S> FromSample<S> for S

§

fn from_sample_(s: S) -> S

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> IntoEither for T

source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
§

impl<F, T> IntoSample<T> for F
where T: FromSample<F>,

§

fn into_sample(self) -> T

§

impl<T> Pointable for T

§

const ALIGN: usize = _

The alignment of pointer.
§

type Init = T

The type for initializers.
§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
source§

impl<T> Same for T

§

type Output = T

Should always be Self
source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
§

impl<T, U> ToSample<U> for T
where U: FromSample<T>,

§

fn to_sample_(self) -> U

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<T> TypeData for T
where T: 'static + Send + Sync + Clone,

§

fn clone_type_data(&self) -> Box<dyn TypeData>

§

impl<T> Upcast<T> for T

§

fn upcast(&self) -> Option<&T>

§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
§

impl<T> ConditionalSend for T
where T: Send,

§

impl<S, T> Duplex<S> for T
where T: FromSample<S> + ToSample<S>,

§

impl<T> Settings for T
where T: 'static + Send + Sync,

§

impl<T> WasmNotSend for T
where T: Send,

§

impl<T> WasmNotSendSync for T
where T: WasmNotSend + WasmNotSync,

§

impl<T> WasmNotSync for T
where T: Sync,