jakobhellermann / bevy-inspector-egui

Inspector plugin for the bevy game engine
Apache License 2.0
1.15k stars 169 forks source link

How can I inspect my Player component? #79

Closed igortavtib closed 1 year ago

igortavtib commented 2 years ago

Hi! I have a player component with a direction and is_moving properties:

#[derive(Component)]
pub struct Player {
    direction: Direction,
    is_moving: bool,
}

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

But when trying to use the inspector I can't watch to player direction or is_moving propertires. What should I do?

njelly commented 2 years ago

I have a very similar situation with trying to inspect a component with an enum field. The compiler says that I must implement bevy::reflect::Reflect on the enum, which is frankly annoying (it's just an enum! shouldn't it be the same as an i32?). There's got to be a solution with less boilerplate, right?

jakobhellermann commented 2 years ago

The inspector somehow needs to know how to display these types. For the world inspector, there are two options:

  1. Derive Reflect for the Player and Direction types, and call app.register_type::<Player>().register_type::<Direction>();.
  2. Derive Inspectable for the types and register them in the InspectableRegistry.

it's just an enum! shouldn't it be the same as an i32?

In the inspector I want to display a dropdown of the values "Up", "Down", "Left" and "Right", for that to work I need to know what kind of variants the enum has and what their names are. Reflect provides exactly that information. Without it, the inspector just looks at an arbitrary component and knows that it is 2 bytes large, but has no way to interpret that data.

njelly commented 2 years ago

I see. Thanks for the explanation!

njelly commented 2 years ago

@jakobhellermann is there an example of implementing an enum so that it shows up in the world inspector? I suppose similar to how the depth_calculation field on the Camera component is rendered. My issue is that implementing bevy::reflect::Reflect requires many methods and functions, and since I'm new to rust and bevy I'm not sure exactly what I should return for each of them.

There is an example in this repo in enum.rs, but this isn't what I'm looking for.

jakobhellermann commented 2 years ago

@jakobhellermann is there an example of implementing an enum so that it shows up in the world inspector? I suppose similar to how the depth_calculation field on the Camera component is rendered. My issue is that implementing bevy::reflect::Reflect requires many methods and functions, and since I'm new to rust and bevy I'm not sure exactly what I should return for each of them.

There is an example in this repo in enum.rs, but this isn't what I'm looking for.

The Reflect trait is meant to be derived, not manually implemented (which is very tedious). So

#[derive(Reflect)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

should in theory work. The problem is, I think reflect reflect for enums was only recently implemented, and wasn't released in bevy 0.8. So this solution will only work in ~3 Months when bevy 0.9 releases.

Until then, you can use the alternative method of implementing Inspectable:

#[derive(Component, Inspectable)]
pub struct Player {
    direction: Direction,
    is_moving: bool,
}

#[derive(Inspectable)]
enum Direction {
    Up,
    Down,
    Left,
    Right,
}

use bevy_inspector_egui::prelude::*; // this imports the RegisterInspectable trait that adds the `app.register_inspectable` method
fn main() {
  App::new()
    .register_inspectable::<Player>()
    .register_inspectable::<Direction>()
    .run();
njelly commented 2 years ago

Fantastic! Thank you, I've gotten it to work in 0.8 (at least for my needs).

Here's some of the relevant code:

#[derive(Clone, Copy, Inspectable, PartialEq, Reflect)]
pub enum CardinalDirection4 {
    None,
    East,
    South,
    West,
    North,
}
#[derive(Component, Default, Inspectable, Reflect)]
#[reflect(Component)]
pub struct Unit {
    pub facing: CardinalDirection4,
    pub input_move: CardinalDirection4,
    pub input_aim: f32, // 2D rotation
}
impl Plugin for DebugPlugin {
    fn build(&self, app: &mut App) {
        if cfg!(debug_assertions) {
            app.add_plugin(WorldInspectorPlugin::new())
                .register_inspectable::<Unit>()
                .register_type::<SpriteAnimation>();
        }
    }
}

And my world inspector now looks like this:

Screen Shot 2022-09-02 at 11 07 57 AM
igortavtib commented 2 years ago

Thanks for all the explanation!

jakobhellermann commented 1 year ago

I think this can be closed now.

For what its worth, on 0.16 you just have to derive Reflect and call .register_type.