Rust游戏开发插件bevy-inspector-egui的使用,Bevy引擎实时调试与属性检视UI工具

Rust游戏开发插件bevy-inspector-egui的使用,Bevy引擎实时调试与属性检视UI工具

快速插件使用

WorldInspectorPlugin

显示世界的实体、资源和资产。

image of the world inspector

use bevy::prelude::*;
use bevy_inspector_egui::quick::WorldInspectorPlugin;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(EguiPlugin::default())
        .add_plugins(WorldInspectorPlugin::new())
        .run();
}

ResourceInspectorPlugin

在窗口中显示单个资源。

image of the resource inspector

use bevy::prelude::*;
use bevy_inspector_egui::prelude::*;
use bevy_inspector_egui::quick::ResourceInspectorPlugin;

// `InspectorOptions` 是完全可选的
#[derive(Reflect, Resource, Default, InspectorOptions)]
#[reflect(Resource, InspectorOptions)]
struct Configuration {
    name: String,
    #[inspector(min = 0.0, max = 1.0)]
    option: f32,
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_resource::<Configuration>() // `ResourceInspectorPlugin` 不会初始化资源
        .register_type::<Configuration>() // 你需要注册你的类型来显示它
        .add_plugins(EguiPlugin::default())
        .add_plugins(ResourceInspectorPlugin::<Configuration>::default())
        // 也适用于内置资源,只要它们是 `Reflect`
        .add_plugins(ResourceInspectorPlugin::<Time>::default())
        .run();
}

手动UI使用

快速插件不允许自定义egui窗口或其内容,但你可以轻松构建自己的UI:

use bevy::prelude::*;
use bevy_egui::EguiPlugin;
use bevy_inspector_egui::prelude::*;
use std::any::TypeId;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(EguiPlugin::default())
        .add_plugins(bevy_inspector_egui::DefaultInspectorConfigPlugin) // 添加默认选项和 `InspectorEguiImpl`s
        .add_systems(EguiPrimaryContextPass, inspector_ui)
        .run();
}

fn inspector_ui(world: &mut World) {
    let Ok(egui_context) = world
        .query_filtered::<&mut EguiContext, With<PrimaryEguiContext>>()
        .get_single(world)
    else {
        return;
    };
    let mut egui_context = egui_context.clone();

    egui::Window::new("UI").show(egui_context.get_mut(), |ui| {
        egui::ScrollArea::vertical().show(ui, |ui| {
            // 等同于 `WorldInspectorPlugin`
            bevy_inspector_egui::bevy_inspector::ui_for_world(world, ui);

            egui::CollapsingHeader::new("Materials").show(ui, |ui| {
                bevy_inspector_egui::bevy_inspector::ui_for_assets::<StandardMaterial>(world, ui);
            });

            ui.heading("Entities");
            bevy_inspector_egui::bevy_inspector::ui_for_world_entities(world, ui);
        });
    });
}

image of the egui_dock example

完整示例代码

use bevy::prelude::*;
use bevy_inspector_egui::prelude::*;
use bevy_inspector_egui::quick::{WorldInspectorPlugin, ResourceInspectorPlugin};

// 自定义配置资源
#[derive(Reflect, Resource, Default, InspectorOptions)]
#[reflect(Resource, InspectorOptions)]
struct GameConfig {
    player_name: String,
    #[inspector(min = 0.0, max = 100.0)]
    player_health: f32,
    #[inspector(min = 0.0, max = 10.0)]
    game_difficulty: f32,
    enable_sound: bool,
}

// 玩家组件
#[derive(Component, Reflect, Default)]
#[reflect(Component)]
struct Player {
    #[inspector(min = 0.0, max = 100.0)]
    health: f32,
    speed: f32,
    is_alive: bool,
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        // 初始化自定义资源
        .init_resource::<GameConfig>()
        // 注册反射类型
        .register_type::<GameConfig>()
        .register_type::<Player>()
        // 添加egui插件
        .add_plugins(bevy_egui::EguiPlugin)
        // 添加世界检查器插件
        .add_plugins(WorldInspectorPlugin::new())
        // 添加资源检查器插件
        .add_plugins(ResourceInspectorPlugin::<GameConfig>::default())
        .add_plugins(ResourceInspectorPlugin::<Time>::default())
        // 启动系统
        .add_systems(Startup, setup)
        .add_systems(Update, player_movement)
        .run();
}

fn setup(mut commands: Commands) {
    // 添加摄像机
    commands.spawn(Camera2dBundle::default());
    
    // 创建玩家实体
    commands.spawn((
        SpriteBundle {
            sprite: Sprite {
                color: Color::rgb(0.25, 0.25, 0.75),
                custom_size: Some(Vec2::new(50.0, 50.0)),
                ..default()
            },
            transform: Transform::from_translation(Vec3::new(0.0, 0.0, 0.0)),
            ..default()
        },
        Player {
            health: 100.0,
            speed: 200.0,
            is_alive: true,
        },
        Name::new("Player"),
    ));
}

fn player_movement(
    time: Res<Time>,
    keyboard_input: Res<Input<KeyCode>>,
    mut query: Query<(&mut Transform, &Player)>,
) {
    for (mut transform, player) in query.iter_mut() {
        if !player.is_alive {
            continue;
        }

        let mut direction = Vec3::ZERO;
        
        if keyboard_input.pressed(KeyCode::W) {
            direction.y += 1.0;
        }
        if keyboard_input.pressed(KeyCode::S) {
            direction.y -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::A) {
            direction.x -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::D) {
            direction.x += 1.0;
        }
        
        if direction.length() > 0.0 {
            direction = direction.normalize();
        }
        
        transform.translation += direction * player.speed * time.delta_seconds();
    }
}

1 回复

Bevy Inspector egui:实时调试与属性检视UI工具

简介

bevy-inspector-egui 是专为 Bevy 游戏引擎设计的实时调试插件,它利用 egui 库提供强大的运行时属性检视功能。开发者可以在游戏运行过程中动态查看和修改组件、资源和系统的属性,极大提升了开发调试效率。

主要特性

  • 实时检视和编辑组件属性
  • 支持自定义类型的检视界面
  • 资源管理和调试功能
  • 系统执行监控
  • 无需重新编译即可调整参数

安装方法

在 Cargo.toml 中添加依赖:

[dependencies]
bevy = "0.13"
bevy-inspector-egui = "0.22"

基本使用

1. 添加插件到应用

use bevy::prelude::*;
use bevy_inspector_egui::quick::WorldInspectorPlugin;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_plugins(WorldInspectorPlugin::new())
        .run();
}

2. 检视组件属性

为组件添加 #[derive(Reflect)]InspectorOptions]

use bevy::prelude::*;
use bevy_inspector_egui::prelude::*;
use bevy_inspector_egui::InspectorOptions;

#[derive(Component, Reflect, InspectorOptions, Default)]
#[reflect(Component, InspectorOptions)]
struct Player {
    #[inspector(min = 0.0, max = 100.0)]
    health: f32,
    #[inspector(min = 0.0, max = 10.0)]
    speed: f32,
    name: String,
    is_alive: bool,
}

3. 注册反射类型

app.register_type::<Player>();

高级功能示例

自定义检视窗口

use bevy_inspector_egui::prelude::*;

fn custom_inspector_ui(world: &mut World) {
    let mut egui_context = world
        .resource_mut::<bevy_inspector_egui::bevy_egui::EguiContext>()
        .get_mut();
    
    egui::Window::new("自定义检视器").show(&egui_context, |ui| {
        bevy_inspector_egui::bevy_inspector::ui_for_world(world, ui);
        
        ui.separator();
        
        if ui.button("重置游戏").clicked() {
            // 重置逻辑
        }
    });
}

资源检视

#[derive(Resource, Reflect, InspectorOptions)]
struct GameSettings {
    #[inspector(min = 1, max = 10)]
    difficulty: u8,
    music_volume: f32,
    sfx_volume: f32,
}

// 注册资源
app.register_type::<GameSettings>()
    .insert_resource(GameSettings {
        difficulty: 3,
        music_volume: 0.7,
        sfx_volume: 0.8,
    });

快捷键

  • F12:切换检视器显示/隐藏
  • 鼠标悬停 + Alt:显示详细工具提示

调试技巧

  1. 实时调整参数:在游戏运行时直接修改数值观察效果
  2. 组件过滤:使用搜索功能快速定位特定组件
  3. 实体选择:点击场景中的实体在检视器中查看其组件
  4. 历史记录:查看属性修改历史便于调试

注意事项

  • 确保为需要检视的类型正确实现 Reflect trait
  • 性能敏感场景建议在发布版本中移除检视器插件
  • 自定义类型需要手动实现或派生 InspectorOptions

这个插件极大地简化了 Bevy 游戏的调试过程,让开发者能够更直观地理解和调整游戏状态。

完整示例代码

use bevy::prelude::*;
use bevy_inspector_egui::prelude::*;
use bevy_inspector_egui::InspectorOptions;
use bevy_inspector_egui::quick::WorldInspectorPlugin;

// 玩家组件定义
#[derive(Component, Reflect, InspectorOptions, Default)]
#[reflect(Component, InspectorOptions)]
struct Player {
    #[inspector(min = 0.0, max = 100.0)]
    health: f32,
    #[inspector(min = 0.0, max = 10.0)]
    speed: f32,
    name: String,
    is_alive: bool,
}

// 游戏设置资源
#[derive(Resource, Reflect, InspectorOptions)]
struct GameSettings {
    #[inspector(min = 1, max = 10)]
    difficulty: u8,
    music_volume: f32,
    sfx_volume: f32,
}

fn main() {
    App::new()
        // 添加默认插件
        .add_plugins(DefaultPlugins)
        // 添加检视器插件
        .add_plugins(WorldInspectorPlugin::new())
        // 注册反射类型
        .register_type::<Player>()
        .register_type::<GameSettings>()
        // 初始化资源
        .insert_resource(GameSettings {
            difficulty: 3,
            music_volume: 0.7,
            sfx_volume: 0.8,
        })
        // 添加启动系统
        .add_systems(Startup, setup)
        // 添加更新系统
        .add_systems(Update, player_movement)
        .run();
}

// 初始化系统
fn setup(mut commands: Commands) {
    // 生成玩家实体
    commands.spawn((
        Player {
            health: 100.0,
            speed: 5.0,
            name: "Hero".to_string(),
            is_alive: true,
        },
        Transform::default(),
    ));
    
    // 生成相机
    commands.spawn(Camera2dBundle::default());
}

// 玩家移动系统
fn player_movement(
    time: Res<Time>,
    keyboard_input: Res<ButtonInput<KeyCode>>,
    mut query: Query<(&mut Transform, &Player)>,
) {
    for (mut transform, player) in query.iter_mut() {
        let mut direction = Vec3::ZERO;
        
        if keyboard_input.pressed(KeyCode::ArrowUp) {
            direction.y += 1.0;
        }
        if keyboard_input.pressed(KeyCode::ArrowDown) {
            direction.y -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::ArrowLeft) {
            direction.x -= 1.0;
        }
        if keyboard_input.pressed(KeyCode::ArrowRight) {
            direction.x += 1.0;
        }
        
        // 使用检视器中可调整的速度值
        transform.translation += direction.normalize_or_zero() * player.speed * time.delta_seconds();
    }
}

// 自定义检视界面函数
fn custom_inspector_ui(world: &mut World) {
    let mut egui_context = world
        .resource_mut::<bevy_inspector_egui::bevy_egui::EguiContext>()
        .get_mut();
    
    egui::Window::new("自定义检视器").show(&egui_context, |ui| {
        bevy_inspector_egui::bevy_inspector::ui_for_world(world, ui);
        
        ui.separator();
        
        if ui.button("重置游戏").clicked() {
            // 重置游戏状态的逻辑
            if let Some(mut settings) = world.get_resource_mut::<GameSettings>() {
                settings.difficulty = 3;
                settings.music_volume = 0.7;
                settings.sfx_volume = 0.8;
            }
        }
    });
}
回到顶部