ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Bevy加载状态机教程:如何用bevy_asset_loader构建Loading State并保证加载完成才切换场景

Bevy加载状态机教程:如何用bevy_asset_loader构建Loading State并保证加载完成才切换场景 Bevy加载状态机教程如何用bevy_asset_loader构建Loading State并保证加载完成才切换场景【免费下载链接】bevy_asset_loaderBevy plugin helping with asset loading and organization项目地址: https://gitcode.com/gh_mirrors/be/bevy_asset_loaderBevy加载状态机教程来了bevy_asset_loader是一个帮助游戏资产加载与组织的 Bevy 插件它能自动加载资产集合AssetCollection并保证所有资产完全加载后才切换场景把繁琐的手动等待逻辑全部交给状态机处理。本教程带你从零构建 Loading State理解其内部状态机流转并配置失败兜底告别画面一闪而过出现空白贴图的烦恼。为什么 Bevy 资产加载需要状态机在 Bevy 中AssetServer的加载是异步的load()调用后Handle立即返回但资产可能还在磁盘读取中。如果在资产没加载完时就切换到游戏场景你会遇到❌ 贴图显示为默认白色占位图❌ 音频首次播放无声❌ 系统里asset_server.get(handle)返回Nonebevy_asset_loader的思路是让游戏停留在一个专门的加载状态里由插件每帧检查加载进度全部就绪后才自动切换到下一个状态。你只需声明哪些资产属于这个场景切换时机由插件保证。核心概念AssetCollection 与 LoadingState整个插件围绕两个概念概念作用AssetCollection用 derive 宏把一组Handle字段声明成结构体加载完成后自动作为Resource插入 ECSLoadingState绑定到一个 Bevy State 的加载状态机负责加载、轮询进度、切换场景声明资产集合非常简洁只需给字段标注#[asset(path ...)]#[derive(AssetCollection, Resource)] struct AudioAssets { #[asset(path audio/background.ogg)] background: HandleAudioSource, }三步构建你的第一个 Loading State以 two_collections.rs 为例完整流程只有三行核心代码App::new() .add_plugins(DefaultPlugins) .init_state::MyStates() .add_loading_state( LoadingState::new(MyStates::AssetLoading) // ① 在哪个状态加载 .continue_to_state(MyStates::Next) // ② 加载完成后切到哪个状态 .load_collection::ImageAssets() // ③ 加载哪些资产集合 .load_collection::AudioAssets(), ) .add_systems(OnEnter(MyStates::Next), spawn_player) .run();进入MyStates::Next状态时ImageAssets和AudioAssets都已作为 Resource 可用且所有 Handle 均完全加载。load_collection可以链式调用把同一场景需要的多个集合一起注册。 插件的入口配置代码位于 src/loading_state.rs其中LoadingStateAppExttrait 提供了add_loading_state和configure_loading_state两个方法。内部状态机4个阶段如何驱动加载过程bevy_asset_loader在你的加载状态内部又维护了一个私有子状态机见 src/loading_state.rs 的InternalLoadingStateInitialize起点判断是否需要先加载动态资产清单LoadingDynamicAssetCollections加载.assets.ron等动态资产配置文件没有动态资产时直接跳过LoadingAssets真正加载你的 AssetCollection每帧检查所有 Handle 的加载状态Finalize所有集合就绪插入资源可执行finally_init_resource的自定义初始化然后触发状态切换这套调度封装在run_loading_state系统中只在加载状态内运行run_if(in_state(...))不会干扰其他状态的帧循环。插件如何保证加载完成才切换关键逻辑在 src/loading_state/systems.rs逐 Handle 轮询count_loaded_handles每帧调用asset_server.is_loaded_with_dependencies(handle.id())统计已完成 / 总数就绪才建集合只有当done total时才调用Assets::create(world)构建集合并insert_resource——资源在加载前根本不存在从根源上杜绝拿到未加载完成资产的 bug依赖加载也算检查的是含依赖的加载状态比如 GLB 模型会连带其内部贴图一起等待全部集合完成后finish_loading_state才设置NextState切换到你配置的目标状态换句话说你写的所有OnEnter(NextState)系统运行时资产一定就绪。配置失败状态加载失败时优雅降级 ⚠️如果某个文件路径写错或未注册对应的资产加载器Bevy 会在日志中打印警告。此时默认行为是卡死在加载状态你可以在状态机中配置一个失败分支LoadingState::new(MyStates::AssetLoading) .continue_to_state(MyStates::Next) .on_failure_continue_to_state(MyStates::ErrorScreen) .load_collection::MyAssets()当检测到递归依赖加载失败state.is_failed()时状态机自动切换到ErrorScreen你可以在那里显示错误提示。完整可运行示例见 failure_state.rs。进阶技巧子状态、进度条与延迟初始化 使用子状态Sub State如果你的菜单本身是一个子状态机如MainMenuState::Loading → Game只需add_sub_state后照常注册 LoadingState插件完全支持参见 sub_state.rs。 加载进度条启用progress_trackingfeature 后插件与iyes_progress集成把每个集合的加载进度done/total暴露出来可轻松实现加载界面的进度条且只有进度全部完成才切换场景参见 progress_tracking.rs。 加载后派生资源finally_init_resource::R()会在所有资产集合就绪后用FromWorld初始化派生资源——例如把两张加载好的图合成第三张图示例见 finally_init_resource.rs。 插件内追加集合功能模块如PlayerPlugin可用configure_loading_state(LoadingStateConfig::new(...).load_collection::PlayerAssets())把自己需要的集合追加进同一个加载状态无需改动主入口参考 configure_loading_state.rs。常见问题速答问题解答没有配置continue_to_state会怎样加载完成后停在加载状态内部 Done 停车态不切换动态资产.assets.ron支持吗支持standard_dynamic_assetsfeature 下路径等配置可外置为数据文件加载状态里能加自己的系统吗能用LoadingStateSet系统集合做显式排序即可不用加载状态行不行行init_collection::MyAssets()可直接初始化但文件夹加载、动态资产等需要等待的特性只在加载状态中可用小结bevy_asset_loader用三行配置就完成了 Bevy 中最常见的资产加载编排声明集合 → 绑定加载状态 → 指定切换目标。其内部 4 阶段子状态机 逐 Handle 依赖检查从机制上保证了加载完成才切换场景再配上失败状态与进度追踪一个完整的、生产级的加载界面流程就齐了。快去 examples 目录里跑一跑示例给你的游戏加上可靠的加载状态机吧【免费下载链接】bevy_asset_loaderBevy plugin helping with asset loading and organization项目地址: https://gitcode.com/gh_mirrors/be/bevy_asset_loader创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进