Skip to content

自定义诊断

bevy_diagnostic 提供了 Diagnostic 系统,用于跟踪随时间变化的数值指标——帧率、内存使用、实体数量等。

注册诊断路径

每个指标通过一个 DiagnosticPath 标识。路径用 / 分隔,不能以 / 开头或结尾:

rust
use bevy::diagnostic::{
    Diagnostic, DiagnosticPath, Diagnostics, DiagnosticsPlugin, RegisterDiagnostic,
};
use bevy::prelude::*;

const ENTITY_COUNT_PATH: DiagnosticPath = DiagnosticPath::const_new("custom/entity_count");

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, DiagnosticsPlugin))
        .register_diagnostic(Diagnostic::new(ENTITY_COUNT_PATH))
        .add_systems(Startup, setup)
        .add_systems(Update, (spawn_entities, count_entities))
        .run();
}

#[derive(Component)]
struct Marker;

fn setup(mut commands: Commands) {
    commands.spawn(Camera2d);
    info!("自定义诊断示例:每秒统计一次实体数量");
}

fn spawn_entities(
    mut commands: Commands,
    keyboard: Res<ButtonInput<KeyCode>>,
    existing: Query<Entity, With<Marker>>,
) {
    if keyboard.just_pressed(KeyCode::Space) {
        for _ in 0..10 {
            commands.spawn(Marker);
        }
        info!(" spawned 10 个 Marker,现有 {}", existing.iter().count() + 10);
    }
}

fn count_entities(
    query: Query<Entity, With<Marker>>,
    mut diagnostics: Diagnostics,
    time: Res<Time>,
    mut accumulator: Local<f32>,
) {
    *accumulator += time.delta_secs();
    if *accumulator >= 1.0 {
        *accumulator -= 1.0;
        let count = query.iter().count() as f64;
        diagnostics.add_measurement(&ENTITY_COUNT_PATH, || count);
        info!("当前 Marker 实体数: {count}");
    }
}

Listing 33-4:自定义诊断——统计 Marker 实体数量

DiagnosticPath::const_new 可以在 const 上下文中使用,适合定义在模块顶层。register_diagnosticApp 上注册后,DiagnosticsStore 资源会自动初始化。

写入测量值

Diagnostics 是一个 SystemParam,提供 add_measurement 方法:

rust
diagnostics.add_measurement(&MY_PATH, || expensive_computation() as f64);

闭包只在诊断启用时才求值——如果不需要计算开销,这避免了无谓的浪费。

读取诊断值

DiagnosticsStore 资源存储了所有诊断的历史数据。可以读取:

  • get(&path):获取 Diagnostic 对象,包含历史记录、平均值
  • get_measurement(&path):获取最新一次测量值
  • measurement():返回 Option<&DiagnosticMeasurement>,含 timevalue

Diagnostic 还维护了一个指数移动平均(EMA),平滑因子默认为 2/21。可以通过 with_max_history_length 调整历史深度。

内置诊断

Bevy 内置了一些诊断插件:

  • FrameTimeDiagnosticsPlugin:帧时间、FPS、帧计数
  • LogDiagnosticsPlugin:定期把诊断值输出到日志
  • EntityCountDiagnosticsPlugin:实体总数
  • SystemInformationDiagnosticsPlugin:CPU / 内存使用

它们都通过 DiagnosticsPlugin 注册。你可以在同一 App 中同时使用内置和自定义诊断。