-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
custom.rs
188 lines (166 loc) · 5.96 KB
/
custom.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! This example shows how to create a new custom entry for your Perf UI.
//!
//! We will keep track of the time when the mouse was last clicked, by
//! storing it in an ECS resource, and implement a Perf UI entry to display it.
//!
//! This example is the "full" complex version. It shows how to add support
//! for all the fancy features of the crate, so that you can make your custom
//! Perf UI entry look nice, just like the ones provided by the library. :)
//!
//! If you just want to see how to create a custom entry with minimal boilerplate,
//! see the `custom_minimal` example instead.
use bevy::prelude::*;
use bevy::utils::Duration;
use bevy::input::mouse::MouseButtonInput;
use bevy::input::ButtonState;
use bevy::ecs::system::lifetimeless::SRes;
use bevy::ecs::system::SystemParam;
use iyes_perf_ui::prelude::*;
use iyes_perf_ui::entry::PerfUiEntry;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
// we want Bevy to measure these values for us:
.add_plugins(bevy::diagnostic::FrameTimeDiagnosticsPlugin)
.add_plugins(PerfUiPlugin)
// we must register our custom entry type
.add_perf_ui_simple_entry::<PerfUiTimeSinceLastClick>()
.init_resource::<TimeSinceLastClick>()
.add_systems(Startup, setup)
.add_systems(Update, handle_click)
.run();
}
fn setup(mut commands: Commands, ass: Res<AssetServer>) {
// spawn a camera to be able to see anything
commands.spawn(Camera2dBundle::default());
commands.spawn((
PerfUiRoot {
// Let's provide some custom fonts, so we can also
// see the font changing when an entry is highlighted
font_label: ass.load("Ubuntu-B.ttf"),
font_value: ass.load("Ubuntu-R.ttf"),
font_highlight: ass.load("Ubuntu-RI.ttf"),
// just so things don't move around (Ubuntu font is not fixed width)
values_col_width: Some(64.0),
..default()
},
PerfUiEntryFPS::default(),
PerfUiTimeSinceLastClick::default(),
));
}
/// Global resource to store the time when the mouse was last clicked
#[derive(Resource, Default)]
pub struct TimeSinceLastClick {
last_click: Duration,
}
/// Custom Perf UI entry to show the time since the last mouse click
#[derive(Component)]
pub struct PerfUiTimeSinceLastClick {
/// The label text to display, to allow customization
pub label: String,
/// Should we display units?
pub display_units: bool,
/// Highlight the value if it goes above this threshold
pub threshold_highlight: Option<f32>,
/// Support color gradients!
pub color_gradient: ColorGradient,
/// Width for formatting the string
pub digits: u8,
/// Precision for formatting the string
pub precision: u8,
/// Required to ensure the entry appears in the correct place in the Perf UI
pub sort_key: i32,
}
impl Default for PerfUiTimeSinceLastClick {
fn default() -> Self {
PerfUiTimeSinceLastClick {
label: String::new(),
display_units: true,
threshold_highlight: Some(10.0),
color_gradient: ColorGradient::new_preset_gyr(1.0, 4.0, 8.0).unwrap(),
digits: 2,
precision: 3,
// get the correct value from the library
sort_key: iyes_perf_ui::utils::next_sort_key(),
}
}
}
// Implement the trait for integration into the Perf UI
impl PerfUiEntry for PerfUiTimeSinceLastClick {
type Value = f64;
// Any system parameters we need in order to compute our value
type SystemParam = (SRes<Time>, SRes<TimeSinceLastClick>);
// The text that will be shown as the Perf UI label
fn label(&self) -> &str {
// return our stored value, if customized, or the default
if self.label.is_empty() {
"Time since last click"
} else {
&self.label
}
}
// We must return the sort key we stored when constructing the struct
fn sort_key(&self) -> i32 {
self.sort_key
}
// Called every frame to compute a new value to show
fn update_value(
&self,
(time, lastclick): &mut <Self::SystemParam as SystemParam>::Item<'_, '_>,
) -> Option<Self::Value> {
let d = time.elapsed() - lastclick.last_click;
Some(d.as_secs_f64())
}
fn format_value(
&self,
value: &Self::Value,
) -> String {
// we can use a premade helper function for nice-looking formatting
let mut s = iyes_perf_ui::utils::format_pretty_float(self.digits, self.precision, *value);
// (and append units to it)
if self.display_units {
s.push_str(" s");
}
s
}
// (optional) We should add a width hint, so that the displayed
// strings in the UI can be correctly aligned.
// This value represents the largest length the formatted string
// is expected to have.
fn width_hint(&self) -> usize {
// there is a helper we can use, since we use `format_pretty_float`
let w = iyes_perf_ui::utils::width_hint_pretty_float(self.digits, self.precision);
if self.display_units {
w + 2
} else {
w
}
}
// (optional) Called every frame to determine if a custom color should be used for the value
fn value_color(
&self,
value: &Self::Value,
) -> Option<Color> {
self.color_gradient.get_color_for_value(*value as f32)
}
// (optional) Called every frame to determine if the value should be highlighted
fn value_highlight(
&self,
value: &Self::Value,
) -> bool {
self.threshold_highlight
.map(|t| (*value as f32) > t)
.unwrap_or(false)
}
}
fn handle_click(
time: Res<Time>,
mut lastclick: ResMut<TimeSinceLastClick>,
mut evr_mouse: EventReader<MouseButtonInput>,
) {
for ev in evr_mouse.read() {
if ev.state == ButtonState::Pressed {
lastclick.last_click = time.elapsed();
}
}
}