avian_pickup 0.1.3

A plugin for implementing picking up dynamic rigid bodies in Avian physics for the Bevy engine.Modeled after Half Life 2's gravity gun.
Documentation
use avian3d::{prelude::*, sync::ancestor_marker::AncestorMarker};
use bevy::prelude::*;

pub(crate) const METERS_PER_INCH: f32 = 0.0254;

pub(crate) fn rigid_body_compound_collider(
    rigid_body: Entity,
    q_collider_ancestor: &Query<&Children, With<AncestorMarker<ColliderMarker>>>,
    q_collider: &Query<(&Transform, &Collider, Option<&CollisionLayers>)>,
    filter: &SpatialQueryFilter,
) -> Option<Collider> {
    let mut colliders = Vec::new();
    if let Ok((&_transform, col, layers)) = q_collider.get(rigid_body) {
        let layers = layers.copied().unwrap_or_default();
        if filter.test(rigid_body, layers) {
            colliders.push((Vec3::ZERO, Quat::IDENTITY, col.clone()));
        }
    }
    if let Ok(children) = q_collider_ancestor.get(rigid_body) {
        for child in children.iter() {
            rigid_body_compound_collider_recursive(
                *child,
                q_collider_ancestor,
                q_collider,
                filter,
                &mut colliders,
            );
        }
    }
    if colliders.is_empty() {
        None
    } else {
        Some(Collider::compound(colliders))
    }
}

fn rigid_body_compound_collider_recursive(
    candidate: Entity,
    q_collider_ancestor: &Query<&Children, With<AncestorMarker<ColliderMarker>>>,
    q_collider: &Query<(&Transform, &Collider, Option<&CollisionLayers>)>,
    filter: &SpatialQueryFilter,
    colliders: &mut Vec<(Vec3, Quat, Collider)>,
) {
    if let Ok((&transform, collider, layers)) = q_collider.get(candidate) {
        let layers = layers.copied().unwrap_or_default();
        if filter.test(candidate, layers) {
            colliders.push((transform.translation, transform.rotation, collider.clone()));
        }
    }
    if let Ok(children) = q_collider_ancestor.get(candidate) {
        for child in children.iter() {
            rigid_body_compound_collider_recursive(
                *child,
                q_collider_ancestor,
                q_collider,
                filter,
                colliders,
            );
        }
    }
}

pub(crate) trait GetBestGlobalTransform {
    fn get_best_global_transform(&self, entity: Entity) -> Transform;
}

impl GetBestGlobalTransform
    for Query<'_, '_, (&GlobalTransform, Option<&Position>, Option<&Rotation>)>
{
    fn get_best_global_transform(&self, entity: Entity) -> Transform {
        let (global_transform, position, rotation) = self
            .get(entity)
            .expect("Got an entity without `GlobalTransform`");
        if let Some(position) = position {
            if let Some(rotation) = rotation {
                return Transform::from_translation(position.0).with_rotation(rotation.0);
            }
        }
        global_transform.compute_transform()
    }
}