使用 Handle 将资产加载到 Bevy 引擎中并稍后使用资产的正确方法?

问题描述

我正在学习 Rust 和 Bevy 引擎,并且我希望在整个应用程序生命周期内保持加载某些资产(例如 Fonts)。


// 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,}
    ...
}

底部函数 setup_ui() 中,我使用 .clone() 复制该资产。如果我不使用 .clone(),我会收到错误

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

我有两个问题:

  1. 我是否在 Font 操作期间复制了整个 .clone()

  2. 这是保持资源加载并供以后使用的“正确”方法,还是有我不知道的更好的方法来实现这一点?

解决方法

关于您的问题,我建议您阅读(非官方)bevy cheatbook's chapter on assets,它会回答您的大部分问题。我将在此处引用与您的问题相关的部分:

  1. 不,您不是在复制 Font,而是在复制 Handle

句柄有内置的引用计数(类似于 Rust 中的 Rc/Arc)。这允许 Bevy 跟踪资产是否仍然需要,并在不再需要时自动卸载它。您可以使用 .clone() 为同一资产创建多个句柄。克隆是一种廉价的操作,但它是明确的,以确保您了解代码中创建额外句柄并可能影响资产生命周期的位置。

  1. 这是两种建议的方式之一。

您可以将句柄存储在您方便的地方(例如在资源中)。 如果您没有将句柄存储在任何地方,您始终可以通过调用 asset_server.load 从路径生成一个。您可以在需要时简单地执行此操作,而不必费心存储句柄。

重复调用 asset_server.load 是有效的,因为在内部,该函数会检查资产是否已加载并重用所述资产。 (这可以在 AssetServer::load_async 方法的源代码中看到,特别是 l. 246-252)。

那么什么时候将句柄存储在优于 asset_server.load 的资源中? 如果没有更多的句柄存在,资产服务器将卸载资产。 对于 UI 中使用的字体,这通常不太可能发生,但对于您希望始终保持加载状态的其他类型的资产来说可能更常见。 将句柄存储在资源中可确保它永远不会被卸载。

代码的其他一些提示:

  • 您可以使用 .insert_resource(ResFont::default()) 代替 .init_resource(ResFont),然后调用 Default 实现。
  • pub fn setup_ui(res_font: ResMut<ResFont>) 中,您可以只使用 Res<ResFont>,因为您不会对其进行变异。

为了将来参考,此回复适用于 Bevy 0.5。