Skip to content

Commit e93bdcb

Browse files
committed
update to bevy_rapier 0.25 + add voxel support + example for 2d
1 parent 7ecb597 commit e93bdcb

File tree

8 files changed

+214
-33
lines changed

8 files changed

+214
-33
lines changed

bevy_rapier2d/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ to-bevy-mesh = ["bevy/bevy_render", "bevy/bevy_asset"]
6666
[dependencies]
6767
bevy = { version = "0.16.0", default-features = false, features = ["std"] }
6868
nalgebra = { version = "0.33", features = ["convert-glam029"] }
69-
rapier2d = "0.24"
69+
rapier2d = "0.25"
7070
bitflags = "2.4"
7171
log = "0.4"
7272
serde = { version = "1", features = ["derive"], optional = true }

bevy_rapier2d/examples/testbed2.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ mod locked_rotations2;
1111
mod multiple_colliders2;
1212
mod player_movement2;
1313
mod rope_joint2;
14+
mod voxels2;
1415

1516
use bevy::prelude::*;
1617
use bevy_egui::{egui, EguiContexts, EguiPlugin};
@@ -22,6 +23,7 @@ pub enum Examples {
2223
#[default]
2324
None,
2425
Boxes2,
26+
Voxels2,
2527
DebugToggle2,
2628
RopeJoint2,
2729
DebugDespawn2,
@@ -75,6 +77,7 @@ fn main() {
7577
.init_state::<Examples>()
7678
.insert_resource(ExampleSet(vec![
7779
(Examples::Boxes2, "Boxes3").into(),
80+
(Examples::Voxels2, "Voxels2").into(),
7881
(Examples::RopeJoint2, "RopeJoint2").into(),
7982
(Examples::DebugDespawn2, "DebugDespawn2").into(),
8083
(Examples::Despawn2, "Despawn3").into(),
@@ -94,6 +97,13 @@ fn main() {
9497
)
9598
.add_systems(OnExit(Examples::Boxes2), cleanup)
9699
//
100+
//boxes2
101+
.add_systems(
102+
OnEnter(Examples::Voxels2),
103+
(voxels2::setup_graphics, voxels2::setup_physics),
104+
)
105+
.add_systems(OnExit(Examples::Voxels2), cleanup)
106+
//
97107
// Debug toggle
98108
.add_systems(
99109
OnEnter(Examples::DebugToggle2),

bevy_rapier2d/examples/voxels2.rs

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
use bevy::prelude::*;
2+
use bevy_rapier2d::prelude::*;
3+
use nalgebra::{point, Vector2};
4+
use rapier2d::prelude::{SharedShape, VoxelPrimitiveGeometry};
5+
6+
fn main() {
7+
App::new()
8+
.insert_resource(ClearColor(Color::srgb(
9+
0xF9 as f32 / 255.0,
10+
0xF9 as f32 / 255.0,
11+
0xFF as f32 / 255.0,
12+
)))
13+
.add_plugins((
14+
DefaultPlugins,
15+
RapierPhysicsPlugin::<NoUserData>::pixels_per_meter(10.0),
16+
RapierDebugRenderPlugin::default(),
17+
))
18+
.add_systems(Startup, (setup_graphics, setup_physics))
19+
.run();
20+
}
21+
22+
pub fn setup_graphics(mut commands: Commands) {
23+
commands.spawn((Camera2d, Transform::from_xyz(0.0, 20.0, 0.0)));
24+
}
25+
26+
pub fn setup_physics(mut commands: Commands) {
27+
let scale = 15f32;
28+
/*
29+
* Create dynamic objects to fall on voxels.
30+
*/
31+
let nx = 50;
32+
for i in 0..nx {
33+
for j in 0..10 {
34+
// if test_ccd {
35+
// rb = rb.linvel(vector![0.0, -1000.0] * scale).ccd_enabled(true);
36+
// }
37+
// let falling_objects = if falling_objects == 3 {
38+
// j % 3
39+
// } else {
40+
// falling_objects
41+
// };
42+
43+
let ball_radius = 0.5 * scale;
44+
let co = match 0 {
45+
0 => Collider::ball(ball_radius),
46+
1 => Collider::cuboid(ball_radius, ball_radius),
47+
2 => Collider::capsule_y(ball_radius, ball_radius),
48+
_ => unreachable!(),
49+
};
50+
commands.spawn((
51+
Transform::from_xyz(
52+
(i as f32 * 2.0 - nx as f32 / 2.0) * scale,
53+
(20.0 + j as f32 * 2.0) * scale,
54+
0.0,
55+
),
56+
RigidBody::Dynamic,
57+
co,
58+
));
59+
}
60+
}
61+
let num = 8;
62+
let rad = 10.0;
63+
64+
let shift = rad * 2.0 + rad;
65+
let centerx = shift * (num / 2) as f32;
66+
let centery = shift / 2.0;
67+
68+
let mut offset = -(num as f32) * (rad * 2.0 + rad) * 0.5;
69+
70+
for j in 0usize..20 {
71+
for i in 0..num {
72+
let x = i as f32 * shift - centerx + offset;
73+
let y = j as f32 * shift + centery + 30.0;
74+
}
75+
76+
offset -= 0.05 * rad * (num as f32 - 1.0);
77+
}
78+
79+
/*
80+
* Voxelization.
81+
*/
82+
let polyline = vec![
83+
point![0.0, 0.0],
84+
point![0.0, 10.0],
85+
point![7.0, 4.0],
86+
point![14.0, 10.0],
87+
point![14.0, 0.0],
88+
point![13.0, 7.0],
89+
point![7.0, 2.0],
90+
point![1.0, 7.0],
91+
]
92+
.iter()
93+
.map(|p| p * scale)
94+
.collect::<Vec<_>>();
95+
let indices: Vec<_> = (0..polyline.len() as u32)
96+
.map(|i| [i, (i + 1) % polyline.len() as u32])
97+
.collect();
98+
99+
let shape = SharedShape::voxelized_mesh(
100+
VoxelPrimitiveGeometry::PseudoCube,
101+
&polyline,
102+
&indices,
103+
0.2 * scale,
104+
FillMode::default(),
105+
);
106+
commands.spawn((
107+
Transform::from_xyz(-20.0 * scale, -10.0 * scale, 0.0),
108+
Collider::from(shape),
109+
));
110+
111+
/*
112+
* A voxel wavy floor.
113+
*/
114+
let voxel_size = Vector2::new(scale, scale);
115+
let voxels: Vec<_> = (0..300)
116+
.map(|i| {
117+
let y = (i as f32 / 20.0).sin().clamp(-0.5, 0.5) * 20.0;
118+
point![(i as f32 - 125.0) * voxel_size.x / 2.0, y * voxel_size.y]
119+
})
120+
.collect();
121+
commands.spawn((
122+
Transform::from_xyz(0.0, 0.0, 0.0),
123+
Collider::from(rapier2d::prelude::SharedShape::voxels_from_points(
124+
VoxelPrimitiveGeometry::PseudoCube,
125+
voxel_size,
126+
&voxels,
127+
)),
128+
));
129+
}

bevy_rapier3d/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ to-bevy-mesh = ["bevy/bevy_render", "bevy/bevy_asset"]
6767
[dependencies]
6868
bevy = { version = "0.16.0", default-features = false, features = ["std"] }
6969
nalgebra = { version = "0.33", features = ["convert-glam029"] }
70-
rapier3d = "0.24"
70+
rapier3d = "0.25"
7171
bitflags = "2.4"
7272
log = "0.4"
7373
serde = { version = "1", features = ["derive"], optional = true }

src/geometry/shape_views/collider_view.rs

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ pub enum ColliderView<'a> {
2222
Segment(SegmentView<'a>),
2323
/// A triangle shape.
2424
Triangle(TriangleView<'a>),
25+
/// A Voxels shape.
26+
Voxels(VoxelsView<'a>),
2527
/// A triangle mesh shape.
2628
TriMesh(TriMeshView<'a>),
2729
/// A set of segments.
@@ -73,6 +75,7 @@ impl fmt::Debug for ColliderView<'_> {
7375
ColliderView::Capsule(view) => write!(f, "{:?}", view.raw),
7476
ColliderView::Segment(view) => write!(f, "{:?}", view.raw),
7577
ColliderView::Triangle(view) => write!(f, "{:?}", view.raw),
78+
ColliderView::Voxels(view) => write!(f, "{:?}", view.raw),
7679
ColliderView::TriMesh(_) => write!(f, "Trimesh (not representable)"),
7780
ColliderView::Polyline(_) => write!(f, "Polyline (not representable)"),
7881
ColliderView::HalfSpace(view) => write!(f, "{:?}", view.raw),
@@ -108,6 +111,7 @@ impl<'a> From<TypedShape<'a>> for ColliderView<'a> {
108111
TypedShape::Capsule(s) => ColliderView::Capsule(CapsuleView { raw: s }),
109112
TypedShape::Segment(s) => ColliderView::Segment(SegmentView { raw: s }),
110113
TypedShape::Triangle(s) => ColliderView::Triangle(TriangleView { raw: s }),
114+
TypedShape::Voxels(s) => ColliderView::Voxels(VoxelsView { raw: s }),
111115
TypedShape::TriMesh(s) => ColliderView::TriMesh(TriMeshView { raw: s }),
112116
TypedShape::Polyline(s) => ColliderView::Polyline(PolylineView { raw: s }),
113117
TypedShape::HalfSpace(s) => ColliderView::HalfSpace(HalfSpaceView { raw: s }),
@@ -129,8 +133,6 @@ impl<'a> From<TypedShape<'a>> for ColliderView<'a> {
129133
TypedShape::RoundTriangle(s) => {
130134
ColliderView::RoundTriangle(RoundTriangleView { raw: s })
131135
}
132-
// RoundedTriMesh,
133-
// RoundedHeightField,
134136
#[cfg(feature = "dim2")]
135137
TypedShape::RoundConvexPolygon(s) => {
136138
ColliderView::RoundConvexPolygon(RoundConvexPolygonView { raw: s })
@@ -171,6 +173,7 @@ impl<'a> ColliderView<'a> {
171173
ColliderView::Capsule(CapsuleView { raw: s }) => TypedShape::Capsule(s),
172174
ColliderView::Segment(SegmentView { raw: s }) => TypedShape::Segment(s),
173175
ColliderView::Triangle(TriangleView { raw: s }) => TypedShape::Triangle(s),
176+
ColliderView::Voxels(VoxelsView { raw: s }) => TypedShape::Voxels(s),
174177
ColliderView::TriMesh(TriMeshView { raw: s }) => TypedShape::TriMesh(s),
175178
ColliderView::Polyline(PolylineView { raw: s }) => TypedShape::Polyline(s),
176179
ColliderView::HalfSpace(HalfSpaceView { raw: s }) => TypedShape::HalfSpace(s),
@@ -192,8 +195,6 @@ impl<'a> ColliderView<'a> {
192195
ColliderView::RoundTriangle(RoundTriangleView { raw: s }) => {
193196
TypedShape::RoundTriangle(s)
194197
}
195-
// RoundedTriMesh,
196-
// RoundedHeightField,
197198
#[cfg(feature = "dim2")]
198199
ColliderView::RoundConvexPolygon(RoundConvexPolygonView { raw: s }) => {
199200
TypedShape::RoundConvexPolygon(s)
@@ -219,6 +220,7 @@ impl<'a> ColliderView<'a> {
219220
ColliderView::Capsule(CapsuleView { raw }) => SharedShape::new(*raw),
220221
ColliderView::Segment(SegmentView { raw }) => SharedShape::new(*raw),
221222
ColliderView::Triangle(TriangleView { raw }) => SharedShape::new(*raw),
223+
ColliderView::Voxels(VoxelsView { raw }) => SharedShape::new(raw.clone()),
222224
ColliderView::TriMesh(TriMeshView { raw }) => SharedShape::new(raw.clone()),
223225
ColliderView::Polyline(PolylineView { raw }) => SharedShape::new(raw.clone()),
224226
ColliderView::HalfSpace(HalfSpaceView { raw }) => SharedShape::new(*raw),
@@ -276,11 +278,14 @@ impl<'a> ColliderView<'a> {
276278
Some(Either::Right(b)) => SharedShape::new(b),
277279
},
278280
ColliderView::Segment(s) => SharedShape::new(s.raw.scaled(&scale.into())),
279-
// ColliderView::RoundSegment(s) => SharedShape::new(RoundShape {
280-
// border_radius: s.raw.border_radius,
281-
// inner_shape: s.raw.inner_shape.scaled(&scale.into()),
282-
// }),
283281
ColliderView::Triangle(t) => SharedShape::new(t.raw.scaled(&scale.into())),
282+
ColliderView::Voxels(cp) => match cp.raw.clone().scaled(&scale.into()) {
283+
None => {
284+
log::error!("Failed to apply scale {} to Voxels shape.", scale);
285+
SharedShape::ball(0.0)
286+
}
287+
Some(scaled) => SharedShape::new(scaled),
288+
},
284289
ColliderView::RoundTriangle(t) => SharedShape::new(RoundShape {
285290
border_radius: t.raw.border_radius,
286291
inner_shape: t.raw.inner_shape.scaled(&scale.into()),

src/geometry/shape_views/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub use self::round_shape::*;
1010
pub use self::segment::*;
1111
pub use self::triangle::*;
1212
pub use self::trimesh::*;
13+
pub use self::voxels::*;
1314

1415
#[cfg(feature = "dim2")]
1516
pub use self::convex_polygon::*;
@@ -29,6 +30,7 @@ mod round_shape;
2930
mod segment;
3031
mod triangle;
3132
mod trimesh;
33+
mod voxels;
3234

3335
#[cfg(feature = "dim2")]
3436
mod convex_polygon;

src/geometry/shape_views/voxels.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use rapier::prelude::Voxels;
2+
3+
/// Read-only access to the properties of a [`Voxels`] shape.
4+
#[derive(Copy, Clone)]
5+
pub struct VoxelsView<'a> {
6+
/// The raw shape from Rapier.
7+
pub raw: &'a Voxels,
8+
}

0 commit comments

Comments
 (0)