Reputation: 61
I am learning Rust and Bevy engine, and I want to keep certain assets (such as Font
s) loaded during the entire application life-time.
// Resource for fonts:
#[derive(Default, Clone)]
pub struct ResFont {
pub ui: Handle<Font>, // The font that will be used in this example.
pub dialog: Handle<Font>,
...
}
// Insert resource in main() during App building:
{
.insert_resource(ResFont::default())
}
// Load resource during startup:
pub fn startup(asset_server: Res<AssetServer>, mut res_font: ResMut<ResFont>)
{
res_font.ui = asset_server.load("font/Default.ttf");
}
// Use the font resource in a different place:
pub fn setup_ui(res_font: ResMut<ResFont>)
{
...
TextStyle {
font: res_font.ui.clone(),
font_size: 12.0,
color: Color::WHITE,
}
...
}
In the function setup_ui()
at the bottom, I am using .clone()
to copy that asset. If I don't use .clone()
, I get the error:
cannot move out of dereference of `bevy::prelude::ResMut<'_, resource::text::ResFont>`
move occurs because value has type `bevy::prelude::Handle<bevy::prelude::Font>`, which does not implement the `Copy` traitrustc(E0507)
ui.rs(19, 27): move occurs because value has type `bevy::prelude::Handle<bevy::prelude::Font>`, which does not implement the `Copy` trait
I have two questions:
Am I copying the entire Font
here during the .clone()
operation?
Is this the "proper" way to keep resources loaded and for use later, or is there is a better way to achieve this that I don't know of?
Upvotes: 6
Views: 4586
Reputation: 91
Regarding your questions, I'd recommend you to give the (unofficial) bevy cheatbook's chapter on assets a read, it will answer most of your questions. I'm going to quote the parts relevant to your questions here:
Font
, just the Handle
.Handles have built-in reference counting (similar to Rc/Arc in Rust). This allows Bevy to track if an asset is still needed, and automatically unload it when it no longer is. You can use .clone() to create multiple handles to the same asset. The clone is a cheap operation, but it is explicit, to ensure that you are aware of the places in your code that create additional handles and may affect the lifetime of assets.
You could store your handles somewhere that is convenient for you (such as in resources). If you don't have your handle stored anywhere, you can always generate one from a path by calling asset_server.load. You could simply do that whenever you need, and not bother storing handles.
Repeatedly calling asset_server.load
works because internally, the function checks if the asset has already been loaded and reuses said asset. (This can be seen in the source code of the AssetServer::load_async
method, specifically l. 246-252).
So when is storing handles in a resource superior to asset_server.load
?
The asset server will unload an asset if no more handles to it exist.
This would usually be unlikely to happen for a font used in the UI, but could be more common for other types of assets you want to stay loaded at all times.
Storing the handle in a resource ensures it will never be unloaded.
Some other hints for your code:
.insert_resource(ResFont::default())
you could just use .init_resource(ResFont)
, which would then call the Default
implementation.pub fn setup_ui(res_font: ResMut<ResFont>)
, you can just use Res<ResFont>
instead, as you're not mutating it.For future reference, this reply applies for Bevy 0.5.
Upvotes: 9