|
1 |
| -//! Let's say you have a trait that you want to implement for some of your components. |
2 |
| -//! |
3 |
| -//! ``` |
4 |
| -//! # use bevy::prelude::*; |
5 |
| -//! # |
6 |
| -//! /// Components that display a message when hovered. |
7 |
| -//! pub trait Tooltip { |
8 |
| -//! /// Text displayed when hovering over an entity with this trait. |
9 |
| -//! fn tooltip(&self) -> &str; |
10 |
| -//! } |
11 |
| -//! ``` |
12 |
| -//! |
13 |
| -//! In order to be useful within bevy, you'll want to be able to query for this trait. |
14 |
| -//! |
15 |
| -//! ``` |
16 |
| -//! # use bevy::prelude::*; |
17 |
| -//! # // Required to make the macro work, because cargo thinks |
18 |
| -//! # // we are in `bevy_trait_query` when compiling this example. |
19 |
| -//! # use bevy_trait_query::*; |
20 |
| -//! |
21 |
| -//! // Just add this attribute... |
22 |
| -//! #[bevy_trait_query::queryable] |
23 |
| -//! pub trait Tooltip { |
24 |
| -//! fn tooltip(&self) -> &str; |
25 |
| -//! } |
26 |
| -//! |
27 |
| -//! // ...and now you can use your trait in queries. |
28 |
| -//! fn show_tooltips_system( |
29 |
| -//! tooltips: Query<&dyn Tooltip>, |
30 |
| -//! // ... |
31 |
| -//! ) { |
32 |
| -//! // ... |
33 |
| -//! } |
34 |
| -//! # bevy_ecs::system::assert_is_system(show_tooltips_system); |
35 |
| -//! ``` |
36 |
| -//! |
37 |
| -//! Since Rust unfortunately lacks any kind of reflection, it is necessary to register each |
38 |
| -//! component with the trait when the app gets built. |
39 |
| -//! |
40 |
| -//! ``` |
41 |
| -//! # use bevy::prelude::*; |
42 |
| -//! # use bevy_trait_query::*; |
43 |
| -//! # |
44 |
| -//! # #[bevy_trait_query::queryable] |
45 |
| -//! # pub trait Tooltip { |
46 |
| -//! # fn tooltip(&self) -> &str; |
47 |
| -//! # } |
48 |
| -//! # |
49 |
| -//! #[derive(Component)] |
50 |
| -//! struct Player(String); |
51 |
| -//! |
52 |
| -//! #[derive(Component)] |
53 |
| -//! enum Villager { |
54 |
| -//! Farmer, |
55 |
| -//! // ... |
56 |
| -//! } |
57 |
| -//! |
58 |
| -//! #[derive(Component)] |
59 |
| -//! struct Monster; |
60 |
| -//! |
61 |
| -//! /* ...trait implementations omitted for brevity... */ |
62 |
| -//! |
63 |
| -//! # impl Tooltip for Player { |
64 |
| -//! # fn tooltip(&self) -> &str { |
65 |
| -//! # &self.0 |
66 |
| -//! # } |
67 |
| -//! # } |
68 |
| -//! # |
69 |
| -//! # impl Tooltip for Villager { |
70 |
| -//! # fn tooltip(&self) -> &str { |
71 |
| -//! # "Villager" |
72 |
| -//! # } |
73 |
| -//! # } |
74 |
| -//! # |
75 |
| -//! # impl Tooltip for Monster { |
76 |
| -//! # fn tooltip(&self) -> &str { |
77 |
| -//! # "Run!" |
78 |
| -//! # } |
79 |
| -//! # } |
80 |
| -//! # |
81 |
| -//! struct TooltipPlugin; |
82 |
| -//! |
83 |
| -//! impl Plugin for TooltipPlugin { |
84 |
| -//! fn build(&self, app: &mut App) { |
85 |
| -//! // We must import this trait in order to register our components. |
86 |
| -//! // If we don't register them, they will be invisible to the game engine. |
87 |
| -//! use bevy_trait_query::RegisterExt; |
88 |
| -//! |
89 |
| -//! app |
90 |
| -//! .register_component_as::<dyn Tooltip, Player>() |
91 |
| -//! .register_component_as::<dyn Tooltip, Villager>() |
92 |
| -//! .register_component_as::<dyn Tooltip, Monster>() |
93 |
| -//! .add_systems(Update, show_tooltips); |
94 |
| -//! } |
95 |
| -//! } |
96 |
| -//! # fn show_tooltips() {} |
97 |
| -//! # |
98 |
| -//! # fn main() { |
99 |
| -//! # App::new().add_plugins((DefaultPlugins, TooltipPlugin)).update(); |
100 |
| -//! # } |
101 |
| -//! ``` |
102 |
| -//! |
103 |
| -//! Unlike queries for concrete types, it's possible for an entity to have multiple components |
104 |
| -//! that match a trait query. |
105 |
| -//! |
106 |
| -//! ``` |
107 |
| -//! # use bevy::prelude::*; |
108 |
| -//! # use bevy_trait_query::*; |
109 |
| -//! # |
110 |
| -//! # #[bevy_trait_query::queryable] |
111 |
| -//! # pub trait Tooltip { |
112 |
| -//! # fn tooltip(&self) -> &str; |
113 |
| -//! # } |
114 |
| -//! # |
115 |
| -//! # #[derive(Component)] |
116 |
| -//! # struct Player(String); |
117 |
| -//! # |
118 |
| -//! # #[derive(Component)] |
119 |
| -//! # struct Monster; |
120 |
| -//! # |
121 |
| -//! # impl Tooltip for Player { |
122 |
| -//! # fn tooltip(&self) -> &str { |
123 |
| -//! # &self.0 |
124 |
| -//! # } |
125 |
| -//! # } |
126 |
| -//! # |
127 |
| -//! # impl Tooltip for Monster { |
128 |
| -//! # fn tooltip(&self) -> &str { |
129 |
| -//! # "Run!" |
130 |
| -//! # } |
131 |
| -//! # } |
132 |
| -//! # |
133 |
| -//! # fn main() { |
134 |
| -//! # App::new() |
135 |
| -//! # .add_plugins(DefaultPlugins) |
136 |
| -//! # .register_component_as::<dyn Tooltip, Player>() |
137 |
| -//! # .register_component_as::<dyn Tooltip, Monster>() |
138 |
| -//! # .add_systems(Startup, setup) |
139 |
| -//! # .update(); |
140 |
| -//! # } |
141 |
| -//! # |
142 |
| -//! # fn setup(mut commands: Commands) { |
143 |
| -//! # commands.spawn(Player("Fourier".to_owned())); |
144 |
| -//! # commands.spawn(Monster); |
145 |
| -//! # } |
146 |
| -//! |
147 |
| -//! fn show_tooltips( |
148 |
| -//! tooltips: Query<&dyn Tooltip>, |
149 |
| -//! // ... |
150 |
| -//! ) { |
151 |
| -//! // Iterate over each entity that has tooltips. |
152 |
| -//! for entity_tooltips in &tooltips { |
153 |
| -//! // Iterate over each component implementing `Tooltip` for the current entity. |
154 |
| -//! for tooltip in entity_tooltips { |
155 |
| -//! println!("Tooltip: {}", tooltip.tooltip()); |
156 |
| -//! } |
157 |
| -//! } |
158 |
| -//! |
159 |
| -//! // If you instead just want to iterate over all tooltips, you can do: |
160 |
| -//! for tooltip in tooltips.iter().flatten() { |
161 |
| -//! println!("Tooltip: {}", tooltip.tooltip()); |
162 |
| -//! } |
163 |
| -//! } |
164 |
| -//! ``` |
165 |
| -//! |
166 |
| -//! Alternatively, if you expect to only have component implementing the trait for each entity, |
167 |
| -//! you can use the filter [`One`](crate::one::One). This has significantly better performance than iterating |
168 |
| -//! over all trait impls. |
169 |
| -//! |
170 |
| -//! ``` |
171 |
| -//! # use bevy::prelude::*; |
172 |
| -//! # use bevy_trait_query::*; |
173 |
| -//! # |
174 |
| -//! # #[bevy_trait_query::queryable] |
175 |
| -//! # pub trait Tooltip { |
176 |
| -//! # fn tooltip(&self) -> &str; |
177 |
| -//! # } |
178 |
| -//! # |
179 |
| -//! use bevy_trait_query::One; |
180 |
| -//! |
181 |
| -//! fn show_tooltips( |
182 |
| -//! tooltips: Query<One<&dyn Tooltip>>, |
183 |
| -//! // ... |
184 |
| -//! ) { |
185 |
| -//! for tooltip in &tooltips { |
186 |
| -//! println!("Tooltip: {}", tooltip.tooltip()); |
187 |
| -//! } |
188 |
| -//! } |
189 |
| -//! # bevy_ecs::system::assert_is_system(show_tooltips); |
190 |
| -//! ``` |
191 |
| -//! |
192 |
| -//! Trait queries support basic change detection filtration. So to get all the components that |
193 |
| -//! implement the target trait, and have also changed in some way since the last tick, you can: |
194 |
| -//! ```no_run |
195 |
| -//! # use bevy::prelude::*; |
196 |
| -//! # use bevy_trait_query::*; |
197 |
| -//! # |
198 |
| -//! # #[bevy_trait_query::queryable] |
199 |
| -//! # pub trait Tooltip { |
200 |
| -//! # fn tooltip(&self) -> &str; |
201 |
| -//! # } |
202 |
| -//! # |
203 |
| -//! fn show_tooltips( |
204 |
| -//! tooltips_query: Query<All<&dyn Tooltip>> |
205 |
| -//! // ... |
206 |
| -//! ) { |
207 |
| -//! // Iterate over all entities with at least one component implementing `Tooltip` |
208 |
| -//! for entity_tooltips in &tooltips_query { |
209 |
| -//! // Iterate over each component for the current entity that changed since the last time the system was run. |
210 |
| -//! for tooltip in entity_tooltips.iter_changed() { |
211 |
| -//! println!("Changed Tooltip: {}", tooltip.tooltip()); |
212 |
| -//! } |
213 |
| -//! } |
214 |
| -//! } |
215 |
| -//! ``` |
216 |
| -//! |
217 |
| -//! Similar to [`iter_changed`](crate::all::All::iter_changed), we have [`iter_added`](crate::all::All::iter_added) |
218 |
| -//! to detect entities which have had a trait-implementing component added since the last tick. |
219 |
| -//! |
220 |
| -//! If you know you have only one component that implements the target trait, |
221 |
| -//! you can use `OneAdded` or `OneChanged` which behave more like the typical |
222 |
| -//! `bevy` `Added/Changed` filters: |
223 |
| -//! ```no_run |
224 |
| -//! # use bevy::prelude::*; |
225 |
| -//! # use bevy_trait_query::*; |
226 |
| -//! # |
227 |
| -//! # #[bevy_trait_query::queryable] |
228 |
| -//! # pub trait Tooltip { |
229 |
| -//! # fn tooltip(&self) -> &str; |
230 |
| -//! # } |
231 |
| -//! # |
232 |
| -//! fn show_tooltips( |
233 |
| -//! tooltips_query: Query<One<&dyn Tooltip>, OneChanged<dyn Tooltip>> |
234 |
| -//! // ... |
235 |
| -//! ) { |
236 |
| -//! // Iterate over each entity that has one tooltip implementing component that has also changed |
237 |
| -//! for tooltip in &tooltips_query { |
238 |
| -//! println!("Changed Tooltip: {}", tooltip.tooltip()); |
239 |
| -//! } |
240 |
| -//! } |
241 |
| -//! ``` |
242 |
| -//! Note in the above example how `OneChanged` does *not* take a reference to the trait object! |
243 |
| -//! |
244 |
| -//! # Performance |
245 |
| -//! |
246 |
| -//! The performance of trait queries is quite competitive. Here are some benchmarks for simple cases: |
247 |
| -//! |
248 |
| -//! | | Concrete type | One<dyn Trait> | All<dyn Trait> | |
249 |
| -//! |-------------------|----------------|-------------------|-----------------| |
250 |
| -//! | 1 match | 8.395 µs | 28.174 µs | 81.027 µs | |
251 |
| -//! | 2 matches | 8.473 µs | - | 106.47 µs | |
252 |
| -//! | 1-2 matches | - | 14.619 µs | 92.876 µs | |
253 |
| -//! |
| 1 | +//! <style> |
| 2 | +//! .rustdoc-hidden { display: none; } |
| 3 | +//! </style> |
| 4 | +#![doc = include_str!("../../README.md")] |
254 | 5 |
|
255 | 6 | use bevy_ecs::{
|
256 | 7 | component::{ComponentId, StorageType},
|
|
0 commit comments