资源管理

概述

学习目标

  • 理解资源管理系统的基本概念
  • 掌握资源类型的定义和使用
  • 学会加载资源(同步、异步、预加载、热重载)
  • 了解资源管理(句柄、生命周期、清理、缓存)

前置知识要求

  • Bevy 快速入门
  • ECS 基础
  • 资源(Resources)基础

核心概念

什么是资源管理?

资源管理是 Bevy 中用于加载和管理游戏资源的功能。Bevy 的资源管理系统支持多种资源类型,包括模型、纹理、音频、字体等。

为什么需要资源管理?

  1. 资源加载:游戏需要加载各种资源,如模型、纹理、音频等
  2. 异步加载:资源加载是异步的,不会阻塞游戏运行
  3. 资源缓存:资源管理系统会自动缓存已加载的资源
  4. 热重载:支持热重载,可以在运行时重新加载资源

资源管理的核心组件

Bevy 资源管理系统包含以下核心组件:

  • AssetServer:资源服务器,用于加载资源
  • Assets:资源集合,存储已加载的资源
  • Handle:资源句柄,用于引用资源
  • AssetLoader:资源加载器,用于加载特定类型的资源

基础用法

资源加载

加载资源的基本方法。

源代码文件bevy/examples/asset/asset_loading.rs

代码示例

use bevy::{asset::LoadedFolder, prelude::*};

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn setup(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    meshes: Res<Assets<Mesh>>,
    mut materials: ResMut<Assets<StandardMaterial>>,
) {
    // 默认情况下,AssetServer 将从 "assets" 文件夹内加载资源
    // 例如,下一行将加载 "ROOT/assets/models/cube/cube.gltf"
    // 其中 "ROOT" 是应用程序的目录
    //
    // 这可以通过设置 [`AssetPlugin.file_path`] 来覆盖
    let cube_handle = asset_server.load(
        GltfAssetLabel::Primitive {
            mesh: 0,
            primitive: 0,
        }
        .from_asset("models/cube/cube.gltf"),
    );
    let sphere_handle = asset_server.load(
        GltfAssetLabel::Primitive {
            mesh: 0,
            primitive: 0,
        }
        .from_asset("models/sphere/sphere.gltf"),
    );

    // 所有资源在加载完成后都会进入它们的 Assets<T> 集合
    if let Some(sphere) = meshes.get(&sphere_handle) {
        // 你可能会注意到这不会运行!这是因为资源在并行加载时不会阻塞
        // 当资源加载完成时,它将出现在相关的 Assets<T> 集合中
        info!("{:?}", sphere.primitive_topology());
    } else {
        info!("sphere 尚未加载");
    }

    // 你可以像这样加载文件夹中的所有资源。它们将在不阻塞的情况下并行加载
    // LoadedFolder 资源保存文件夹中每个资源的句柄
    // 这些都是 LoadedFolder 资源的依赖项,这意味着如果你想要等待文件夹中的所有资源加载
    // 可以等待 LoadedFolder 资源触发 AssetEvent::LoadedWithDependencies
    // 如果你想保持文件夹中的资源存活,请确保存储返回的句柄
    let _loaded_folder: Handle<LoadedFolder> = asset_server.load_folder("models/torus");

    // 如果你想要文件夹中特定资源的句柄,最简单的方法是调用 load
    // 它不会再次加载
    // LoadedFolder 资源最终也会保存资源的句柄,但等待它加载并找到正确的句柄需要更多工作
    let torus_handle = asset_server.load(
        GltfAssetLabel::Primitive {
            mesh: 0,
            primitive: 0,
        }
        .from_asset("models/torus/torus.gltf"),
    );

    // 你也可以直接将资源添加到它们的 Assets<T> 存储中
    let material_handle = materials.add(StandardMaterial {
        base_color: Color::srgb(0.8, 0.7, 0.6),
        ..default()
    });

    // 使用加载的资源创建实体
    commands.spawn((
        Mesh3d(torus_handle),
        MeshMaterial3d(material_handle.clone()),
        Transform::from_xyz(-3.0, 0.0, 0.0),
    ));
}

关键要点

  • 使用 AssetServer 加载资源
  • 资源加载是异步的,不会阻塞游戏运行
  • 使用 Assets<T> 集合访问已加载的资源
  • 可以使用 load_folder() 加载整个文件夹的资源
  • 可以使用 add() 方法直接添加资源到集合中

说明: 资源加载是资源管理系统的基础。通过 AssetServer 加载资源,资源会在后台异步加载,不会阻塞游戏运行。加载完成后,资源会出现在相应的 Assets<T> 集合中。

资源句柄

使用资源句柄引用资源。

关键信息

  • Handle<T> 是资源的引用
  • 句柄可以在资源加载完成之前使用
  • 句柄可以克隆,多个句柄可以引用同一个资源
  • 资源只有在所有句柄都被丢弃后才会被卸载

说明: 资源句柄是资源管理系统的核心。它允许在资源加载完成之前就使用资源,并且可以安全地共享资源引用。

资源生命周期

理解资源的生命周期。

关键信息

  • 资源在加载时创建
  • 资源在最后一个句柄被丢弃时卸载
  • 资源可以被缓存以提高性能
  • 资源可以被热重载

说明: 资源的生命周期由句柄管理。只要还有句柄引用资源,资源就会保持在内存中。当所有句柄都被丢弃时,资源会被卸载。

进阶用法

自定义资源类型

创建自定义资源类型。

源代码文件bevy/examples/asset/custom_asset.rs

代码示例

use bevy::{
    asset::{io::Reader, AssetLoader, LoadContext},
    prelude::*,
    reflect::TypePath,
};
use serde::Deserialize;

#[derive(Asset, TypePath, Debug, Deserialize)]
struct CustomAsset {
    value: i32,
}

#[derive(Default)]
struct CustomAssetLoader;

impl AssetLoader for CustomAssetLoader {
    type Asset = CustomAsset;
    type Settings = ();
    type Error = CustomAssetLoaderError;

    async fn load(
        &self,
        reader: &mut dyn Reader,
        _settings: &(),
        _load_context: &mut LoadContext<'_>,
    ) -> Result<Self::Asset, Self::Error> {
        let mut bytes = Vec::new();
        reader.read_to_end(&mut bytes).await?;
        let custom_asset = ron::de::from_bytes::<CustomAsset>(&bytes)?;
        Ok(custom_asset)
    }

    fn extensions(&self) -> &[&str] {
        &["custom"]
    }
}

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .init_asset::<CustomAsset>()
        .init_asset_loader::<CustomAssetLoader>()
        .run();
}

关键要点

  • 使用 #[derive(Asset, TypePath)] 定义资源类型
  • 实现 AssetLoader trait 来创建资源加载器
  • 在应用中初始化资源类型和加载器
  • 可以支持自定义文件格式

说明: 自定义资源类型允许你创建自己的资源格式。这对于游戏特定的数据格式非常有用。

热重载

在运行时重新加载资源。

源代码文件bevy/examples/asset/hot_asset_reloading.rs

代码示例

use bevy::prelude::*;

fn main() {
    App::new()
        .add_plugins(DefaultPlugins)
        .add_systems(Startup, setup)
        .run();
}

fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
    // 加载我们的网格
    let scene_handle =
        asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/torus/torus.gltf"));

    // 对网格的任何更改都会自动重新加载!尝试修改 torus.gltf
    // 你应该会立即看到更改出现在应用中

    commands.spawn(SceneRoot(scene_handle));
}

关键要点

  • 热重载允许在运行时修改资源文件
  • 修改后的资源会自动重新加载
  • 需要启用 file_watcher cargo feature
  • 适合开发时快速迭代

说明: 热重载功能允许在开发时快速迭代。修改资源文件后,资源会自动重新加载,无需重启游戏。

嵌入资源

将资源嵌入到可执行文件中。

源代码文件bevy/examples/asset/embedded_asset.rs

关键信息

  • 可以使用 embedded_asset! 宏嵌入资源
  • 嵌入的资源包含在可执行文件中
  • 适合小型资源或需要快速加载的资源
  • 可以与其他资源加载方式结合使用

说明: 嵌入资源允许将资源直接包含在可执行文件中。这对于小型资源或需要快速加载的资源非常有用。

额外资源源

从多个源加载资源。

源代码文件bevy/examples/asset/extra_source.rs

关键信息

  • 可以配置多个资源源
  • 可以从不同的目录或服务器加载资源
  • 可以设置资源源的优先级
  • 适合模块化资源管理

说明: 额外资源源允许从多个位置加载资源。这对于模块化资源管理或从服务器加载资源非常有用。

实际应用

在游戏开发中的应用场景

资源管理在游戏开发中有广泛的应用:

  1. 模型加载:加载 3D 模型和场景
  2. 纹理加载:加载纹理和材质
  3. 音频加载:加载音频文件
  4. 字体加载:加载字体文件
  5. 配置文件:加载游戏配置数据

常见问题

问题 1:如何等待资源加载完成?

解决方案:可以监听 AssetEvent::LoadedWithDependencies 事件,或者使用 Assets<T>get() 方法检查资源是否已加载。

问题 2:如何管理资源的生命周期?

解决方案:资源的生命周期由句柄管理。只要还有句柄引用资源,资源就会保持在内存中。确保在不再需要资源时丢弃句柄。

问题 3:如何优化资源加载性能?

解决方案:可以使用资源预加载、资源缓存、资源压缩等技术来优化资源加载性能。

性能考虑

  1. 资源预加载:在需要之前预加载资源
  2. 资源缓存:合理使用资源缓存以减少重复加载
  3. 资源压缩:使用压缩格式减少资源大小
  4. 异步加载:利用异步加载避免阻塞游戏运行

相关资源

相关源代码文件

  • bevy/examples/asset/asset_loading.rs - 资源加载示例
  • bevy/examples/asset/custom_asset.rs - 自定义资源类型示例
  • bevy/examples/asset/hot_asset_reloading.rs - 热重载示例
  • bevy/examples/asset/embedded_asset.rs - 嵌入资源示例
  • bevy/examples/asset/extra_source.rs - 额外资源源示例

官方文档链接

进一步学习建议

  • 学习场景系统,了解如何加载和管理场景
  • 学习资源管理,了解如何优化资源加载性能
  • 学习自定义资源类型,了解如何创建自己的资源格式

索引返回上级目录