Skip to content

Commit

Permalink
Update to Bevy 0.13 (#315)
Browse files Browse the repository at this point in the history
# Objective

Closes #314 and #317.

This PR will be merged once Bevy 0.13 is released. Feel free to use this `bevy-main` branch in the meantime if you want to use the main branch of Bevy with `bevy_xpbd`.

## Solution

Update to the latest Bevy version.

For the 0.13 migration, I will be trying to implement various changes, mostly surrounding the new geometric primitives and ray structs. I will probably do these in PRs that I merge into this one, and it will all be merged into main once 0.13 is actually released.

- [x] Combine `PhysicsDebugRenderer` and `PhysicsDebugConfig` into `PhysicsGizmos` gizmo configuration group
- [x] Support creating colliders from primitives #326
- [x] Support ellipses and regular polygons as colliders (conical frusta and tori later) #326
- [x] Support creating `ShapeCaster`s with primitive shapes
- [x] Use `Direction2d`/`Direction3d` in spatial query APIs #329

---

## Migration Guide

### Debug rendering

The `PhysicsDebugConfig` resource and `PhysicsDebugRenderer` system parameter have been removed in favor of the new `PhysicsGizmos` [gizmo configuration group](https://bevyengine.org/news/bevy-0-13/#multiple-gizmo-configurations).

Before:

```rust
fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins,
            PhysicsPlugins::default(),
            PhysicsDebugPlugin::default(),
        ))
        // Configure physics debug rendering
        .insert_resource(PhysicsDebugConfig {
            aabb_color: Some(Color::WHITE),
            ..default()
        })
        .run();
}
```

After:

```rust
fn main() {
    App::new()
        .add_plugins((
            DefaultPlugins,
            PhysicsPlugins::default(),
            PhysicsDebugPlugin::default(),
        ))
        // Configure physics debug rendering
        .insert_gizmo_group(
            PhysicsGizmos {
                aabb_color: Some(Color::WHITE),
                ..default()
            },
            GizmoConfig::default(),
        )
        .run();
}
```

This also allows you to configure e.g. line width for just physics gizmos by configuring their `GizmoConfig`.

### Renamed `Collider` constructors (#326)

- Replace `Collider::ball` with `Collider::circle` in 2D and `Collider::sphere` in 3D
- Replace `Collider::cuboid` with `Collider::rectangle` in 2D

### Ray and shape casting (#329)

For spatial queries, replace `Vec2`/`Vec3` directions with [`Direction2d`](https://docs.rs/bevy/0.13.0/bevy/math/primitives/struct.Direction2d.html)/[`Direction3d`](https://docs.rs/bevy/0.13.0/bevy/math/primitives/struct.Direction3d.html).

```rust
// Before
let caster = RayCaster::new(Vec3::ZERO, Vec3::X);

// After
let caster = RayCaster::new(Vec3::ZERO, Direction3d::X);
```

This applies to `RayCaster`, `ShapeCaster`, `SpatialQuery` methods like `cast_ray`, and many other methods that use directions.
  • Loading branch information
Jondolf authored Feb 20, 2024
1 parent 36e0d82 commit dc98b65
Show file tree
Hide file tree
Showing 82 changed files with 1,888 additions and 1,309 deletions.
17 changes: 10 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[![3D crates.io](https://img.shields.io/crates/v/bevy_xpbd_3d?label=3D%20crates.io)](https://crates.io/crates/bevy_xpbd_3d)
[![3D docs.rs](https://img.shields.io/docsrs/bevy_xpbd_3d?label=3D%20docs.rs)](https://docs.rs/bevy_xpbd_3d)

**Bevy XPBD** is a 2D and 3D physics engine based on *Extended Position Based Dynamics* (XPBD)
**Bevy XPBD** is a 2D and 3D physics engine based on _Extended Position Based Dynamics_ (XPBD)
for the [Bevy game engine](https://bevyengine.org/).

## Design
Expand All @@ -17,9 +17,9 @@ Below are some of the core design principles used in Bevy XPBD.
- **Made with Bevy, for Bevy.** No wrappers around existing engines.
- **Provide an ergonomic and familiar API.** Ergonomics is key for a good experience.
- **Utilize the ECS as much as possible.** The engine should feel like a part of Bevy, and it shouldn't
need to maintain a separate physics world.
need to maintain a separate physics world.
- **Use a highly modular plugin architecture.** Users should be able to replace parts of the engine
with their own implementations.
with their own implementations.
- **Have good documentation.** A physics engine is pointless if you don't know how to use it.

## Features
Expand Down Expand Up @@ -104,23 +104,25 @@ fn setup(
RigidBody::Static,
Collider::cuboid(8.0, 0.002, 8.0),
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Plane::from_size(8.0))),
material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()),
mesh: meshes.add(Plane3d::default().mesh().size(8.0, 8.0)),
material: materials.add(Color::rgb(0.3, 0.5, 0.3)),
..default()
},
));

// Cube
commands.spawn((
RigidBody::Dynamic,
AngularVelocity(Vec3::new(2.5, 3.4, 1.6)),
Collider::cuboid(1.0, 1.0, 1.0),
PbrBundle {
mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })),
material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()),
mesh: meshes.add(Cuboid::default()),
material: materials.add(Color::rgb(0.8, 0.7, 0.6)),
transform: Transform::from_xyz(0.0, 4.0, 0.0),
..default()
},
));

// Light
commands.spawn(PointLightBundle {
point_light: PointLight {
Expand All @@ -131,6 +133,7 @@ fn setup(
transform: Transform::from_xyz(4.0, 8.0, 4.0),
..default()
});

// Camera
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(-4.0, 6.5, 8.0).looking_at(Vec3::ZERO, Vec3::Y),
Expand Down
2 changes: 1 addition & 1 deletion crates/benches_common_3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ version = "0.1.0"
edition = "2021"

[dependencies]
bevy = { version = "0.12", default-features = false }
bevy = { version = "0.13", default-features = false }
bevy_xpbd_3d = { path = "../bevy_xpbd_3d", default-features = false }
criterion = "0.5"
11 changes: 6 additions & 5 deletions crates/bevy_xpbd_2d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ parallel = ["parry2d?/parallel", "parry2d-f64?/parallel"]
enhanced-determinism = [
"parry2d?/enhanced-determinism",
"parry2d-f64?/enhanced-determinism",
"glam/libm",
"bevy_math/libm",
]

default-collider = ["dep:nalgebra"]
Expand All @@ -46,19 +46,20 @@ required-features = ["2d"]

[dependencies]
bevy_xpbd_derive = { path = "../bevy_xpbd_derive", version = "0.1" }
bevy = { version = "0.12", default-features = false }
bevy = { version = "0.13", default-features = false }
bevy_math = "0.13"
parry2d = { version = "0.13", optional = true }
parry2d-f64 = { version = "0.13", optional = true }
nalgebra = { version = "0.32", features = ["convert-glam024"], optional = true }
glam = { version = "0.24", features = ["approx"] }
nalgebra = { version = "0.32", features = ["convert-glam025"], optional = true }
serde = { version = "1", features = ["derive"], optional = true }
derive_more = "0.99"
indexmap = "2.0.0"
fxhash = "0.2.1"
itertools = "0.11"
itertools = "0.12"

[dev-dependencies]
examples_common_2d = { path = "../examples_common_2d" }
bevy_math = { version = "0.13", features = ["approx"] }
approx = "0.5"
insta = "1.0"

Expand Down
10 changes: 4 additions & 6 deletions crates/bevy_xpbd_2d/examples/chain_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,8 @@ fn setup(

let particle_count = 100;
let particle_radius = 1.2;
let particle_mesh: Mesh2dHandle = meshes
.add(shape::Circle::new(particle_radius as f32).into())
.into();
let particle_material = materials.add(ColorMaterial::from(Color::rgb(0.2, 0.7, 0.9)));
let particle_mesh: Mesh2dHandle = meshes.add(Circle::new(particle_radius as f32)).into();
let particle_material = materials.add(Color::rgb(0.2, 0.7, 0.9));

// Spawn kinematic particle that can follow the mouse
let mut previous_particle = commands
Expand All @@ -54,7 +52,7 @@ fn setup(
let current_particle = commands
.spawn((
RigidBody::Dynamic,
MassPropertiesBundle::new_computed(&Collider::ball(particle_radius), 1.0),
MassPropertiesBundle::new_computed(&Collider::circle(particle_radius), 1.0),
MaterialMesh2dBundle {
mesh: particle_mesh.clone(),
material: particle_material.clone(),
Expand All @@ -79,7 +77,7 @@ fn setup(
}

fn follow_mouse(
buttons: Res<Input<MouseButton>>,
buttons: Res<ButtonInput<MouseButton>>,
windows: Query<&Window, With<PrimaryWindow>>,
camera: Query<(&Camera, &GlobalTransform)>,
mut follower: Query<&mut Transform, With<FollowMouse>>,
Expand Down
14 changes: 7 additions & 7 deletions crates/bevy_xpbd_2d/examples/collision_layers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn setup(
..default()
},
RigidBody::Static,
Collider::cuboid(500.0, 25.0),
Collider::rectangle(500.0, 25.0),
CollisionLayers::new([Layer::Blue], [Layer::Blue]),
));

Expand All @@ -55,15 +55,15 @@ fn setup(
..default()
},
RigidBody::Static,
Collider::cuboid(500.0, 25.0),
Collider::rectangle(500.0, 25.0),
CollisionLayers::new([Layer::Red], [Layer::Red]),
));

let marble_radius = 7.5;
let marble_mesh = meshes.add(shape::Circle::new(marble_radius).into());
let marble_mesh = meshes.add(Circle::new(marble_radius));

// Spawn blue marbles that belong on the blue layer and collide with blue
let blue_material = materials.add(ColorMaterial::from(Color::rgb(0.2, 0.7, 0.9)));
let blue_material = materials.add(Color::rgb(0.2, 0.7, 0.9));
for x in -6..6 {
for y in 0..4 {
commands.spawn((
Expand All @@ -78,14 +78,14 @@ fn setup(
..default()
},
RigidBody::Dynamic,
Collider::ball(marble_radius as Scalar),
Collider::circle(marble_radius as Scalar),
CollisionLayers::new([Layer::Blue], [Layer::Blue]),
));
}
}

// Spawn red marbles that belong on the red layer and collide with red
let red_material = materials.add(ColorMaterial::from(Color::rgb(0.9, 0.3, 0.3)));
let red_material = materials.add(Color::rgb(0.9, 0.3, 0.3));
for x in -6..6 {
for y in -4..0 {
commands.spawn((
Expand All @@ -100,7 +100,7 @@ fn setup(
..default()
},
RigidBody::Dynamic,
Collider::ball(marble_radius as Scalar),
Collider::circle(marble_radius as Scalar),
CollisionLayers::new([Layer::Red], [Layer::Red]),
));
}
Expand Down
10 changes: 5 additions & 5 deletions crates/bevy_xpbd_2d/examples/custom_collider.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,16 @@ fn setup(
let center_radius = 200.0;
let particle_radius = 5.0;

let red = materials.add(Color::rgb(0.9, 0.3, 0.3).into());
let blue = materials.add(Color::rgb(0.1, 0.6, 1.0).into());
let particle_mesh = meshes.add(shape::Circle::new(particle_radius).into());
let red = materials.add(Color::rgb(0.9, 0.3, 0.3));
let blue = materials.add(Color::rgb(0.1, 0.6, 1.0));
let particle_mesh = meshes.add(Circle::new(particle_radius));

// Spawn rotating body at the center.
commands
.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(shape::Circle::new(center_radius).into()).into(),
material: materials.add(Color::rgb(0.7, 0.7, 0.8).into()).clone(),
mesh: meshes.add(Circle::new(center_radius)).into(),
material: materials.add(Color::rgb(0.7, 0.7, 0.8)).clone(),
..default()
},
RigidBody::Kinematic,
Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_xpbd_2d/examples/distance_joint_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fn setup(mut commands: Commands) {
..default()
},
RigidBody::Dynamic,
MassPropertiesBundle::new_computed(&Collider::cuboid(50.0, 50.0), 1.0),
MassPropertiesBundle::new_computed(&Collider::rectangle(50.0, 50.0), 1.0),
))
.id();

Expand Down
53 changes: 31 additions & 22 deletions crates/bevy_xpbd_2d/examples/dynamic_character_2d/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@

mod plugin;

use bevy::{prelude::*, render::render_resource::PrimitiveTopology, sprite::MaterialMesh2dBundle};
use bevy::{
prelude::*,
render::{render_asset::RenderAssetUsages, render_resource::PrimitiveTopology},
sprite::MaterialMesh2dBundle,
};
use bevy_xpbd_2d::{math::*, prelude::*};
use plugin::*;

Expand All @@ -37,17 +41,8 @@ fn setup(
// Player
commands.spawn((
MaterialMesh2dBundle {
mesh: meshes
.add(
shape::Capsule {
radius: 12.5,
depth: 20.0,
..default()
}
.into(),
)
.into(),
material: materials.add(ColorMaterial::from(Color::rgb(0.2, 0.7, 0.9))),
mesh: meshes.add(Capsule2d::new(12.5, 20.0)).into(),
material: materials.add(Color::rgb(0.2, 0.7, 0.9)),
transform: Transform::from_xyz(0.0, -100.0, 0.0),
..default()
},
Expand Down Expand Up @@ -75,7 +70,7 @@ fn setup(
..default()
},
RigidBody::Dynamic,
Collider::cuboid(30.0, 30.0),
Collider::rectangle(30.0, 30.0),
));

// Platforms
Expand All @@ -90,7 +85,7 @@ fn setup(
..default()
},
RigidBody::Static,
Collider::cuboid(1100.0, 50.0),
Collider::rectangle(1100.0, 50.0),
));
commands.spawn((
SpriteBundle {
Expand All @@ -103,7 +98,7 @@ fn setup(
..default()
},
RigidBody::Static,
Collider::cuboid(300.0, 25.0),
Collider::rectangle(300.0, 25.0),
));
commands.spawn((
SpriteBundle {
Expand All @@ -116,7 +111,7 @@ fn setup(
..default()
},
RigidBody::Static,
Collider::cuboid(300.0, 25.0),
Collider::rectangle(300.0, 25.0),
));
commands.spawn((
SpriteBundle {
Expand All @@ -129,7 +124,7 @@ fn setup(
..default()
},
RigidBody::Static,
Collider::cuboid(150.0, 80.0),
Collider::rectangle(150.0, 80.0),
));
commands.spawn((
SpriteBundle {
Expand All @@ -142,44 +137,58 @@ fn setup(
..default()
},
RigidBody::Static,
Collider::cuboid(150.0, 80.0),
Collider::rectangle(150.0, 80.0),
));

// Ramps
let mut ramp_mesh = Mesh::new(PrimitiveTopology::TriangleList);

let mut ramp_mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
);

ramp_mesh.insert_attribute(
Mesh::ATTRIBUTE_POSITION,
vec![[-125.0, 80.0, 0.0], [-125.0, 0.0, 0.0], [125.0, 0.0, 0.0]],
);

let ramp_collider = Collider::triangle(
Vector::new(-125.0, 80.0),
Vector::NEG_X * 125.0,
Vector::X * 125.0,
);

commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(ramp_mesh).into(),
material: materials.add(ColorMaterial::from(Color::rgb(0.4, 0.4, 0.5))),
material: materials.add(Color::rgb(0.4, 0.4, 0.5)),
transform: Transform::from_xyz(-275.0, -150.0, 0.0),
..default()
},
RigidBody::Static,
ramp_collider,
));
let mut ramp_mesh = Mesh::new(PrimitiveTopology::TriangleList);

let mut ramp_mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
);

ramp_mesh.insert_attribute(
Mesh::ATTRIBUTE_POSITION,
vec![[20.0, -40.0, 0.0], [20.0, 40.0, 0.0], [-20.0, -40.0, 0.0]],
);

let ramp_collider = Collider::triangle(
Vector::new(20.0, -40.0),
Vector::new(20.0, 40.0),
Vector::new(-20.0, -40.0),
);

commands.spawn((
MaterialMesh2dBundle {
mesh: meshes.add(ramp_mesh).into(),
material: materials.add(ColorMaterial::from(Color::rgb(0.4, 0.4, 0.5))),
material: materials.add(Color::rgb(0.4, 0.4, 0.5)),
transform: Transform::from_xyz(380.0, -110.0, 0.0),
..default()
},
Expand Down
11 changes: 5 additions & 6 deletions crates/bevy_xpbd_2d/examples/dynamic_character_2d/plugin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ impl Plugin for CharacterControllerPlugin {
keyboard_input,
gamepad_input,
update_grounded,
apply_deferred,
movement,
apply_movement_damping,
)
Expand Down Expand Up @@ -106,7 +105,7 @@ impl CharacterControllerBundle {
character_controller: CharacterController,
rigid_body: RigidBody::Dynamic,
collider,
ground_caster: ShapeCaster::new(caster_shape, Vector::ZERO, 0.0, Vector::NEG_Y)
ground_caster: ShapeCaster::new(caster_shape, Vector::ZERO, 0.0, Direction2d::NEG_Y)
.with_max_time_of_impact(10.0),
locked_axes: LockedAxes::ROTATION_LOCKED,
movement: MovementBundle::default(),
Expand All @@ -128,10 +127,10 @@ impl CharacterControllerBundle {
/// Sends [`MovementAction`] events based on keyboard input.
fn keyboard_input(
mut movement_event_writer: EventWriter<MovementAction>,
keyboard_input: Res<Input<KeyCode>>,
keyboard_input: Res<ButtonInput<KeyCode>>,
) {
let left = keyboard_input.any_pressed([KeyCode::A, KeyCode::Left]);
let right = keyboard_input.any_pressed([KeyCode::D, KeyCode::Right]);
let left = keyboard_input.any_pressed([KeyCode::KeyA, KeyCode::ArrowLeft]);
let right = keyboard_input.any_pressed([KeyCode::KeyD, KeyCode::ArrowRight]);

let horizontal = right as i8 - left as i8;
let direction = horizontal as Scalar;
Expand All @@ -150,7 +149,7 @@ fn gamepad_input(
mut movement_event_writer: EventWriter<MovementAction>,
gamepads: Res<Gamepads>,
axes: Res<Axis<GamepadAxis>>,
buttons: Res<Input<GamepadButton>>,
buttons: Res<ButtonInput<GamepadButton>>,
) {
for gamepad in gamepads.iter() {
let axis_lx = GamepadAxis {
Expand Down
Loading

0 comments on commit dc98b65

Please sign in to comment.