bevy_boxddd 0.1.0

Bevy integration for the boxddd Rust bindings to Box3D
Documentation
use bevy_app::App;
use bevy_boxddd::prelude::*;
use bevy_math::Vec3;
use bevy_time::{TimePlugin, TimeUpdateStrategy};
use bevy_transform::components::Transform;

fn physics_app(settings: BoxdddPhysicsSettings) -> App {
    let mut app = App::new();
    app.add_plugins(TimePlugin)
        .insert_resource(TimeUpdateStrategy::FixedTimesteps(1))
        .add_plugins(BoxdddPhysicsPlugin::new(settings));
    app
}

#[test]
fn fixed_step_moves_dynamic_body_and_syncs_transform() {
    let mut app = physics_app(BoxdddPhysicsSettings::default());

    app.world_mut().spawn((
        RigidBody::Static,
        Collider::cuboid(10.0, 0.5, 10.0),
        Transform::from_xyz(0.0, -0.5, 0.0),
    ));
    let falling = app
        .world_mut()
        .spawn((
            RigidBody::Dynamic,
            Collider::sphere(0.5),
            Transform::from_xyz(0.0, 4.0, 0.0),
        ))
        .id();

    for _ in 0..8 {
        app.update();
    }

    let transform = app
        .world()
        .entity(falling)
        .get::<Transform>()
        .expect("falling body should still have a Transform");
    assert!(transform.translation.y < 4.0);
}

#[test]
fn static_body_uses_bevy_authored_transform() {
    let mut app = physics_app(BoxdddPhysicsSettings::default());
    let ground = app
        .world_mut()
        .spawn((
            RigidBody::Static,
            Collider::cuboid(10.0, 0.5, 10.0),
            Transform::from_xyz(0.0, -1.25, 0.0),
        ))
        .id();

    for _ in 0..4 {
        app.update();
    }

    let body = app.world().entity(ground).get::<BoxdddBody>().unwrap().id();
    let context = app.world().get_non_send::<BoxdddPhysicsContext>().unwrap();
    let position = context.world().unwrap().body_position(body);

    assert_eq!(position, boxddd::Pos::new(0.0, -1.25, 0.0));
}

#[test]
fn linear_velocity_component_controls_body_before_sync() {
    let settings = BoxdddPhysicsSettings {
        gravity: Vec3::ZERO,
        ..Default::default()
    };
    let mut app = physics_app(settings);
    let entity = app
        .world_mut()
        .spawn((
            RigidBody::Dynamic,
            Collider::sphere(0.5),
            LinearVelocity(Vec3::new(2.0, 0.0, 0.0)),
            Transform::from_xyz(0.0, 1.0, 0.0),
        ))
        .id();

    for _ in 0..4 {
        app.update();
    }

    let transform = app.world().entity(entity).get::<Transform>().unwrap();
    assert!(transform.translation.x > 0.0);
}

#[test]
fn external_impulse_is_applied_once_and_then_removed() {
    let settings = BoxdddPhysicsSettings {
        gravity: Vec3::ZERO,
        ..Default::default()
    };
    let mut app = physics_app(settings);
    let entity = app
        .world_mut()
        .spawn((
            RigidBody::Dynamic,
            Collider::sphere(0.5),
            ExternalImpulse::at_center(Vec3::new(6.0, 0.0, 0.0)),
            Transform::from_xyz(0.0, 1.0, 0.0),
        ))
        .id();

    for _ in 0..4 {
        app.update();
    }

    let transform = app.world().entity(entity).get::<Transform>().unwrap();
    assert!(transform.translation.x > 0.0);
    assert!(
        app.world()
            .entity(entity)
            .get::<ExternalImpulse>()
            .is_none()
    );
}