Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fps overlay #12382

Merged
merged 21 commits into from Mar 11, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/bevy_dev_tools/Cargo.toml
Expand Up @@ -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_time = { path = "../bevy_time", 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
serde = { version = "1.0", features = ["derive"], optional = true }
Expand Down
164 changes: 164 additions & 0 deletions crates/bevy_dev_tools/src/fps_overlay.rs
@@ -0,0 +1,164 @@
use bevy_app::{Plugin, Startup, Update};
use bevy_asset::AssetServer;
use bevy_color::Color;
use bevy_diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
use bevy_ecs::{
change_detection::DetectChanges,
component::Component,
query::With,
system::{Commands, Query, Res, Resource},
};
use bevy_input::{keyboard::KeyCode, ButtonInput};
use bevy_render::view::Visibility;
use bevy_text::{Text, TextSection, TextStyle};
use bevy_ui::node_bundles::TextBundle;

#[derive(Default)]
/// A plugin that adds an FPS overlay to the Bevy application.
pub struct FpsOverlayPlugin {
matiqo15 marked this conversation as resolved.
Show resolved Hide resolved
/// 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) {
if !app.is_plugin_added::<FrameTimeDiagnosticsPlugin>() {
matiqo15 marked this conversation as resolved.
Show resolved Hide resolved
app.add_plugins(FrameTimeDiagnosticsPlugin);
}
app.insert_resource(self.config.clone())
.add_systems(Startup, setup)
.add_systems(Update, (customize_text, update_text, toggle_overlay));
}
}

#[derive(Resource, Clone)]
/// Configuration options for the FPS overlay.
pub struct FpsOverlayConfig {
/// File path for the font file. If set to `None`,the default font is used.
/// Note: The overlay won't be visible if you set it to `None` and run without `default_font` feature.
pub font_path: Option<String>,
matiqo15 marked this conversation as resolved.
Show resolved Hide resolved
/// Size of the overlay text.
pub font_size: f32,
/// Color of the overlay text.
pub font_color: Color,
/// Keybind for toggling on/off the overlay.
/// If set to none, [`KeyCode::F1`] is used
pub keybind: Option<KeyCode>,
matiqo15 marked this conversation as resolved.
Show resolved Hide resolved
}

impl Default for FpsOverlayConfig {
fn default() -> Self {
FpsOverlayConfig {
font_path: None,
font_size: 32.0,
font_color: Color::WHITE,
keybind: None,
}
}
}

#[derive(Component)]
struct FpsText;

fn setup(
mut commands: Commands,
overlay_config: Res<FpsOverlayConfig>,
asset_server: Res<AssetServer>,
) {
commands.spawn((
TextBundle::from_sections([
TextSection::new(
"FPS: ",
if let Some(font_path) = &overlay_config.font_path {
TextStyle {
font_size: overlay_config.font_size,
color: overlay_config.font_color,
font: asset_server.load(font_path),
}
} else {
TextStyle {
font_size: overlay_config.font_size,
color: overlay_config.font_color,
..Default::default()
}
},
),
TextSection::from_style(if let Some(font_path) = &overlay_config.font_path {
TextStyle {
font_size: overlay_config.font_size,
color: overlay_config.font_color,
font: asset_server.load(font_path),
}
} else {
TextStyle {
font_size: overlay_config.font_size,
color: overlay_config.font_color,
..Default::default()
}
}),
]),
FpsText,
));
}

fn update_text(
diagnostic: Res<DiagnosticsStore>,
mut query: Query<(&mut Text, &Visibility), With<FpsText>>,
) {
for (mut text, visibility) in &mut query {
if let Visibility::Hidden = *visibility {
return;
}
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>,
asset_server: Res<AssetServer>,
mut query: Query<&mut Text, With<FpsText>>,
) {
if !overlay_config.is_changed() {
matiqo15 marked this conversation as resolved.
Show resolved Hide resolved
return;
}

for mut text in &mut query {
for section in text.sections.iter_mut() {
section.style = if let Some(font_path) = &overlay_config.font_path {
TextStyle {
font_size: overlay_config.font_size,
color: overlay_config.font_color,
font: asset_server.load(font_path),
}
} else {
TextStyle {
font_size: overlay_config.font_size,
color: overlay_config.font_color,
..Default::default()
}
}
}
}
}

fn toggle_overlay(
matiqo15 marked this conversation as resolved.
Show resolved Hide resolved
input: Res<ButtonInput<KeyCode>>,
mut query: Query<&mut Visibility, With<FpsText>>,
overlay_config: Res<FpsOverlayConfig>,
) {
if (overlay_config.keybind.is_none() && input.just_pressed(KeyCode::F1))
| (overlay_config.keybind.is_some() && input.just_pressed(overlay_config.keybind.unwrap()))
{
for mut visibility in query.iter_mut() {
*visibility = if let Visibility::Hidden = *visibility {
Visibility::Visible
} else {
Visibility::Hidden
}
}
}
}
3 changes: 3 additions & 0 deletions crates/bevy_dev_tools/src/lib.rs
Expand Up @@ -2,8 +2,11 @@
//! focused on improving developer experience.

use bevy_app::prelude::*;

#[cfg(feature = "bevy_ci_testing")]
pub mod ci_testing;
/// Module containing logic for FPS overlay.
matiqo15 marked this conversation as resolved.
Show resolved Hide resolved
pub mod fps_overlay;

/// Enables developer tools in an [`App`]. This plugin is added automatically with `bevy_dev_tools`
/// feature.
Expand Down