dimforge / dimforge/bevy_rapier
Make it easier to get static snapshots of collider data
- Dominant language
- Rust
- Stars
- 1.6k
- Forks
- 282
- PR merge metrics
- No merged PRs in 30d
Description
I've been having a very hard time with this and wonder if there's any way bevy_rapier might make this easier. I'm trying to integrate physics into my pathfinding, which can take more than a single frame. Previously, my AStar calls generated paths that routed entities through areas in which they couldn't physically fit. I'm trying to add shapes to this algorithm such that valid successors to a given tile are only those in which the shape of the source entity can fit. Here's an example of what I have right now:
```
fn find_path_for_shape(
pool: &AsyncComputeTaskPool,
initiator: Entity,
start: &dyn PointLike,
destination: &dyn PointLike,
map: &Map,
query_pipeline: &QueryPipeline,
collider_query: &QueryPipelineColliderComponentsQuery,
shape: &dyn Shape,
channel: &Sender>,
) {
let collider_set = QueryPipelineColliderComponentsSet(&collider_query);
let shapes = Shapes(
collider_query
.iter()
.map(|(a, b, c, d)| (a, b.clone(), c.clone(), d.clone()))
.collect::>(),
);
let start = start.i32();
let destination = destination.i32();
let map_clone = map.clone();
let shape_clone = shape.clone();
let channel_clone = channel.clone();
pool.spawn(async {
let path = astar(
&start,
|p| {
let mut successors: Vec<((i32, i32), u32)> = vec![];
for tile in map_clone.get_available_exits(p.0 as usize, p.1 as usize) {
let mut should_push = true;
let shape_pos = Isometry::new(vector![tile.0 as f32, tile.1 as f32], 0.);
query_pipeline.intersections_with_shape(
&shapes,
&shape_pos,
&*shape_clone,
InteractionGroups::all(),
Some(&|v| v.entity() != initiator),
|handle| {
should_push = false;
false
},
);
if should_push {
successors.push(((tile.0 as i32, tile.1 as i32), (tile.2 * 100.) as u32));
}
}
successors
},
|p| (p.distance_squared(&destination) * 100.) as u32,
|p| *p == destination.into(),
);
channel_clone
.send(if let Some(path) = path {
Some(Path(path.0))
} else {
None
})
.expect("Channel should exist");
})
.detach();
}
```
It was suggested that I make a wrapper type that creates a static snapshots of colliders to pass into the pool. I'm fine with this, as I can probably correct for changes in the system that actually negotiates calculated paths for cases where a path gets blocked. Here is a partial attempt at that:
```
struct Shapes(Vec<(Entity, ColliderPosition, ColliderShape, ColliderFlags)>);
impl ComponentSet for Shapes {
fn size_hint(&self) -> usize {
self.0.len()
}
fn for_each(&self, f: impl FnMut(bevy_rapier2d::rapier::data::Index, &SharedShape)) {
unimplemented!()
}
}
impl ComponentSetOption for Shapes {
fn get(&self, index: Index) -> std::option::Option<&SharedShape> {
self.0
.get(index.into())
.map(|v: &(Entity, ColliderPosition, ColliderShape, ColliderFlags)| &v.2)
}
}
impl ComponentSet for Shapes {
fn size_hint(&self) -> usize {
self.0.len()
}
fn for_each(&self, f: impl FnMut(bevy_rapier2d::rapier::data::Index, &ColliderFlags)) {
unimplemented!()
}
}
impl ComponentSetOption for Shapes {
fn get(
&self,
index: bevy_rapier2d::rapier2d::data::Index,
) -> std::option::Option<&ColliderFlags> {
self.0.get(index)
}
}
impl ComponentSet for Shapes {
fn size_hint(&self) -> usize {
self.0.len()
}
fn for_each(&self, f: impl FnMut(bevy_rapier2d::rapier::data::Index, &ColliderPosition)) {
unimplemented!()
}
}
impl ComponentSetOption for Shapes {
fn get(
&self,
index: bevy_rapier2d::rapier2d::data::Index,
) -> std::option::Option<&ColliderPosition> {
self.0.get(index)
}
}
```
Obviously that's incomplete, but here are some of the errors I'm getting:
error[E0284]: type annotations needed: cannot satisfy `<_ as SliceIndex<[(bevy::prelude::Entity, bevy_rapier2d::prelude::ColliderPosition, bevy_rapier2d::prelude::SharedShape, bevy_rapier2d::prelude::ColliderFlags)]>>::Output == (bevy::prelude::Entity, bevy_rapier2d::prelude::ColliderPosition, bevy_rapier2d::prelude::SharedShape, bevy_rapier2d::prelude::ColliderFlags)`
--> src\pathfinding.rs:63:14
|
63 | .get(index.into())
| ^^^ cannot satisfy `<_ as SliceIndex<[(bevy::prelude::Entity, bevy_rapier2d::prelude::ColliderPosition, bevy_rapier2d::prelude::SharedShape, bevy_rapier2d::prelude::ColliderFlags)]>>::Output == (bevy::prelude::Entity, bevy_rapier2d::prelude::ColliderPosition, bevy_rapier2d::prelude::SharedShape, bevy_rapier2d::prelude::ColliderFlags)`
error[E0621]: explicit lifetime required in the type of `shape`
--> src\pathfinding.rs:129:10
|
114 | shape: &dyn Shape,
| ---------- help: add explicit lifetime `'static` to the type of `shape`: `&'static (dyn bevy_rapier2d::prelude::Shape + 'static)`
...
129 | pool.spawn(async {
| ^^^^^ lifetime `'static` required
error[E0621]: explicit lifetime required in the type of `query_pipeline`
--> src\pathfinding.rs:129:10
|
112 | query_pipeline: &QueryPipeline,
| -------------- help: add explicit lifetime `'static` to the type of `query_pipeline`: `&'static bevy_rapier2d::prelude::QueryPipeline`
...
129 | pool.spawn(async {
| ^^^^^ lifetime `'static` required
This is probably a more advanced use case, and I'm not sure what the plugin might do to make this easier. Maybe even an example of snapshotting collision data and accessing it in a pool would be useful? There are some obvious mistakes in my `Shapes` code--Rust Analyzer's automatic import added a few broken paths, for instance--but I feel like I'm adding mud to an existing mess rather than working toward a solution. Alternately, I'm not sure if there's a better solution to my pathfinding issue than taking physical shapes into account, but I had enough special cases for handling bad data that I thought it might help to prevent that bad data from being generated in the first place.
Thanks.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.