dimforge / bevy_rapier

Official Rapier plugin for the Bevy game engine.
https://rapier.rs
Apache License 2.0
1.24k stars 260 forks source link

Split up `RapierContext` #502

Open Jondolf opened 4 months ago

Jondolf commented 4 months ago

The RapierContext resource is massive. It has the island manager, broad phase, narrow phase, CCD solver, physics pipeline, query pipeline, integration parameters, rigid bodies, colliders, and joints. Quoting the docs: "The Rapier context, containing all the state of the physics engine." It is also what is used to step the simulation, perform scene queries, query for collision pairs, and control character controllers.

This kind of "god struct" feels almost antithetical to an ECS. Almost everything is handled by one struct with dozens of unrelated responsibilities. This is unidiomatic, bad for composability and modularity, bad for documentation, and bad from a UX standpoint.

What solution would you like?

RapierContext should be split up into several resources. For methods that require access to multiple different resources, system parameters can be used.

For example, the query pipeline could be turned into its own resource. It could be renamed to SceneQuery, or there could be a new system parameter for it, like bevy_xpbd's SpatialQuery. If it was its own system parameter, ray casting could look like this:

fn cast_ray(scene_query: SceneQuery) {
    let ray_pos = Vec3::new(1.0, 2.0, 3.0);
    let ray_dir = Vec3::new(0.0, 1.0, 0.0);
    let max_toi = 4.0;
    let solid = true;
    let filter = QueryFilter::default();

    if let Some((entity, toi)) = scene_query.cast_ray(
        ray_pos, ray_dir, max_toi, solid, filter
    ) {
        let hit_point = ray_pos + ray_dir * toi;
        println!("Entity {:?} hit at point {}", entity, hit_point);
    }
}

I find that IntegrationParameters also doesn't really make sense in RapierContext. It could either be in RapierConfiguration where other global configuration resides, or be its own resource.

Some more internal structures like the island manager, rigid body sets, collider sets, and so on might be fine in the same resource, or split into separate resources.

Plugin architecture?

Personally, I would also like to see Rapier try a more plugin-oriented architecture. It would allow for some nice flexibility and composability, making it more straightforward for third-party alternatives to be used if a specific first-party solution is insufficient, while also providing a logical place for docs.rs documentation. For example, collision detection could be handled by one plugin, and the solver by another. bevy_xpbd has a very plugin-heavy architecture, but even just a few plugins would help break up the monolithic structure.

Of course, this would probably require changes to how the simulation loop in bevy_rapier works, but I don't see why it wouldn't inherently be doable.

Vrixyz commented 4 months ago

https://github.com/dimforge/bevy_rapier/pull/328 suggests taking the route of physics World as entities, that's the best option in my opinion too, which plays well with this PR: add more or split components to customize a physics world.