Fps overlay (#12382)

# Objective

- Part of #12351
- Add fps overlay

## Solution

- Create `FpsOverlayPlugin`
- Allow for configuration through resource `FpsOverlayConfig`
- Allow for configuration during runtime

### Preview on default settings

![20240308_22h23m25s_grim](https://github.com/bevyengine/bevy/assets/62356462/33d3d7a9-435e-4e0b-9814-d3274e779a69)

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
Mateusz Wachowiak 2024-03-11 20:26:14 +01:00 committed by GitHub
parent 27215b79b0
commit 2d29954034
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 190 additions and 0 deletions

View file

@ -2763,6 +2763,18 @@ description = "A scene showcasing light gizmos"
category = "Gizmos" category = "Gizmos"
wasm = true wasm = true
[[example]]
name = "fps_overlay"
path = "examples/dev_tools/fps_overlay.rs"
doc-scrape-examples = true
required-features = ["bevy_dev_tools"]
[package.metadata.example.fps_overlay]
name = "FPS overlay"
description = "Demonstrates FPS overlay"
category = "Dev tools"
wasm = true
[profile.wasm-release] [profile.wasm-release]
inherits = "release" inherits = "release"
opt-level = "z" opt-level = "z"

View file

@ -19,6 +19,12 @@ bevy_ecs = { path = "../bevy_ecs", version = "0.14.0-dev" }
bevy_render = { path = "../bevy_render", version = "0.14.0-dev" } bevy_render = { path = "../bevy_render", version = "0.14.0-dev" }
bevy_time = { path = "../bevy_time", version = "0.14.0-dev" } bevy_time = { path = "../bevy_time", version = "0.14.0-dev" }
bevy_window = { path = "../bevy_window", version = "0.14.0-dev" } bevy_window = { path = "../bevy_window", version = "0.14.0-dev" }
bevy_asset = { path = "../bevy_asset", version = "0.14.0-dev" }
bevy_ui = { path = "../bevy_ui", version = "0.14.0-dev" }
bevy_text = { path = "../bevy_text", version = "0.14.0-dev" }
bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.14.0-dev" }
bevy_color = { path = "../bevy_color", version = "0.14.0-dev" }
bevy_input = { path = "../bevy_input", version = "0.14.0-dev" }
# other # other
serde = { version = "1.0", features = ["derive"], optional = true } serde = { version = "1.0", features = ["derive"], optional = true }

View file

@ -0,0 +1,98 @@
//! Module containing logic for FPS overlay.
use bevy_app::{Plugin, Startup, Update};
use bevy_asset::Handle;
use bevy_color::Color;
use bevy_diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
use bevy_ecs::{
component::Component,
query::With,
schedule::{common_conditions::resource_changed, IntoSystemConfigs},
system::{Commands, Query, Res, Resource},
};
use bevy_text::{Font, Text, TextSection, TextStyle};
use bevy_ui::node_bundles::TextBundle;
/// A plugin that adds an FPS overlay to the Bevy application.
///
/// This plugin will add the [`FrameTimeDiagnosticsPlugin`] if it wasn't added before.
///
/// Note: It is recommended to use native overlay of rendering statistics when possible for lower overhead and more accurate results.
/// The correct way to do this will vary by platform:
/// - **Metal**: setting env variable `MTL_HUD_ENABLED=1`
#[derive(Default)]
pub struct FpsOverlayPlugin {
/// Starting configuration of overlay, this can be later be changed through [`FpsOverlayConfig`] resource.
pub config: FpsOverlayConfig,
}
impl Plugin for FpsOverlayPlugin {
fn build(&self, app: &mut bevy_app::App) {
// TODO: Use plugin dependencies, see https://github.com/bevyengine/bevy/issues/69
if !app.is_plugin_added::<FrameTimeDiagnosticsPlugin>() {
app.add_plugins(FrameTimeDiagnosticsPlugin);
}
app.insert_resource(self.config.clone())
.add_systems(Startup, setup)
.add_systems(
Update,
(
customize_text.run_if(resource_changed::<FpsOverlayConfig>),
update_text,
),
);
}
}
/// Configuration options for the FPS overlay.
#[derive(Resource, Clone)]
pub struct FpsOverlayConfig {
/// Configuration of text in the overlay.
pub text_config: TextStyle,
}
impl Default for FpsOverlayConfig {
fn default() -> Self {
FpsOverlayConfig {
text_config: TextStyle {
font: Handle::<Font>::default(),
font_size: 32.0,
color: Color::WHITE,
},
}
}
}
#[derive(Component)]
struct FpsText;
fn setup(mut commands: Commands, overlay_config: Res<FpsOverlayConfig>) {
commands.spawn((
TextBundle::from_sections([
TextSection::new("FPS: ", overlay_config.text_config.clone()),
TextSection::from_style(overlay_config.text_config.clone()),
]),
FpsText,
));
}
fn update_text(diagnostic: Res<DiagnosticsStore>, mut query: Query<&mut Text, With<FpsText>>) {
for mut text in &mut query {
if let Some(fps) = diagnostic.get(&FrameTimeDiagnosticsPlugin::FPS) {
if let Some(value) = fps.smoothed() {
text.sections[1].value = format!("{value:.2}");
}
}
}
}
fn customize_text(
overlay_config: Res<FpsOverlayConfig>,
mut query: Query<&mut Text, With<FpsText>>,
) {
for mut text in &mut query {
for section in text.sections.iter_mut() {
section.style = overlay_config.text_config.clone();
}
}
}

View file

@ -3,8 +3,10 @@
#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![cfg_attr(docsrs, feature(doc_auto_cfg))]
use bevy_app::prelude::*; use bevy_app::prelude::*;
#[cfg(feature = "bevy_ci_testing")] #[cfg(feature = "bevy_ci_testing")]
pub mod ci_testing; pub mod ci_testing;
pub mod fps_overlay;
/// Enables developer tools in an [`App`]. This plugin is added automatically with `bevy_dev_tools` /// Enables developer tools in an [`App`]. This plugin is added automatically with `bevy_dev_tools`
/// feature. /// feature.

View file

@ -45,6 +45,7 @@ git checkout v0.4.0
- [Assets](#assets) - [Assets](#assets)
- [Async Tasks](#async-tasks) - [Async Tasks](#async-tasks)
- [Audio](#audio) - [Audio](#audio)
- [Dev tools](#dev-tools)
- [Diagnostics](#diagnostics) - [Diagnostics](#diagnostics)
- [ECS (Entity Component System)](#ecs-entity-component-system) - [ECS (Entity Component System)](#ecs-entity-component-system)
- [Games](#games) - [Games](#games)
@ -219,6 +220,12 @@ Example | Description
[Spatial Audio 2D](../examples/audio/spatial_audio_2d.rs) | Shows how to play spatial audio, and moving the emitter in 2D [Spatial Audio 2D](../examples/audio/spatial_audio_2d.rs) | Shows how to play spatial audio, and moving the emitter in 2D
[Spatial Audio 3D](../examples/audio/spatial_audio_3d.rs) | Shows how to play spatial audio, and moving the emitter in 3D [Spatial Audio 3D](../examples/audio/spatial_audio_3d.rs) | Shows how to play spatial audio, and moving the emitter in 3D
## Dev tools
Example | Description
--- | ---
[FPS overlay](../examples/dev_tools/fps_overlay.rs) | Demonstrates FPS overlay
## Diagnostics ## Diagnostics
Example | Description Example | Description

View file

@ -0,0 +1,65 @@
//! Showcase how to use and configure FPS overlay.
use bevy::{
dev_tools::fps_overlay::{FpsOverlayConfig, FpsOverlayPlugin},
prelude::*,
};
fn main() {
App::new()
.add_plugins((
DefaultPlugins,
FpsOverlayPlugin {
config: FpsOverlayConfig {
text_config: TextStyle {
// Here we define size of our overlay
font_size: 50.0,
// We can also change color of the overlay
color: Color::srgb(0.0, 1.0, 0.0),
// If we want, we can use a custom font
font: default(),
},
},
},
))
.add_systems(Startup, setup)
.add_systems(Update, customize_config)
.run();
}
fn setup(mut commands: Commands) {
// We need to spawn camera to see overlay
commands.spawn(Camera2dBundle::default());
commands.spawn(
TextBundle::from_sections([
TextSection::new(
"Press 1 to change color of the overlay.",
TextStyle {
font_size: 25.0,
..default()
},
),
TextSection::new(
"\nPress 2 to change size of the overlay",
TextStyle {
font_size: 25.0,
..default()
},
),
])
.with_style(Style {
justify_self: JustifySelf::Center,
..default()
}),
);
}
fn customize_config(input: Res<ButtonInput<KeyCode>>, mut overlay: ResMut<FpsOverlayConfig>) {
if input.just_pressed(KeyCode::Digit1) {
// Changing resource will affect overlay
overlay.text_config.color = Color::srgb(1.0, 0.0, 0.0);
}
if input.just_pressed(KeyCode::Digit2) {
overlay.text_config.font_size -= 2.0;
}
}