Rust游戏开发插件bevy-inspector-egui的使用,Bevy引擎实时调试与属性检视UI工具
Rust游戏开发插件bevy-inspector-egui的使用,Bevy引擎实时调试与属性检视UI工具
快速插件使用
WorldInspectorPlugin
显示世界的实体、资源和资产。
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
在窗口中显示单个资源。
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);
});
});
}
完整示例代码
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
:显示详细工具提示
调试技巧
- 实时调整参数:在游戏运行时直接修改数值观察效果
- 组件过滤:使用搜索功能快速定位特定组件
- 实体选择:点击场景中的实体在检视器中查看其组件
- 历史记录:查看属性修改历史便于调试
注意事项
- 确保为需要检视的类型正确实现
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;
}
}
});
}