dimforge / bevy_rapier

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

Reflect and register `Collider` type #404

Open timothee-haudebourg opened 1 year ago

timothee-haudebourg commented 1 year ago

Hi, I'm blocked because the Collider type is not registered to the app, and cannot be manually registered because it lacks the required traits implementations. I guess it is related to this TODO: https://github.com/dimforge/bevy_rapier/blob/af5ac6e258141105909b4182509393b04566c148/src/geometry/collider.rs#L61

I suppose this is not the only type that requires reflection. Is there any work in progress to add those? If not I may write a PR.

Aceeri commented 1 year ago

This currently requires some changes on bevy_reflect side as Compound is a self-referential type, I would suggest using https://github.com/devildahu/bevy_mod_component_mirror for now, but know that it will be a subset of the available collider types.

Luminoth commented 3 months ago

it looks like the linked PR has been merged, is the door opened now to impl Reflect on Collider? The space editor project has a requirement on that for Components.

janhohenheim commented 3 months ago

Semi-relevant issue: https://github.com/dimforge/rapier/issues/467

Zeenobit commented 1 month ago

The HEAD revision of moonshine-save now supports "component mappers" to solve this issue as a workaround.

It's a similar idea to component mirror, but baked into the save pipeline:

app.register_type::<SerializedCollider>()
  .add_systems(
      PreUpdate,
      (
          save_default()
              .map_component(serialize_collider)
              .into_file("example.ron"),
          load_from_file_with_mapper(
              "example.ron",
              SceneMapper::default().map(deserialize_collider),
          ),
      ),
  )

Where serialize_collider and deserialize_collider are defined as:

#[derive(Component, Reflect)]
#[reflect(Component)]
enum SerializedCollider {
    Ball(f32),
    // ...
}

fn serialize_collider(collider: &Collider) -> SerializedCollider {
    if let Some(ball) = collider.as_ball() {
        SerializedCollider::Ball(ball.radius())
    } else {
        todo!()
    }
}

fn deserialize_collider(serialized: &SerializedCollider) -> Collider {
    match serialized {
        SerializedCollider::Ball(radius) => Collider::ball(*radius),
        _ => todo!(),
    }
}

I'm curious to know if:

  1. Can every collider be serialized indirectly like this? If not, what subset of it could be?
  2. Are there any other types in bevy_rapier that suffer from the same issue?