#bevy-ecs #bevy #ecs #async #async-task #game

bevy-async-ecs

Bevy ECS的异步接口

8个版本 (5个重大变更)

0.6.0 2024年8月13日
0.5.1 2024年6月4日
0.5.0 2024年2月18日
0.4.1 2024年1月24日
0.1.0 2023年12月1日

#341 in 游戏开发

Download history 159/week @ 2024-06-03 7/week @ 2024-06-10 5/week @ 2024-06-17 41/week @ 2024-06-24 45/week @ 2024-07-01 42/week @ 2024-07-29 123/week @ 2024-08-12

每月下载 165次
用于 haalka

MIT 许可协议

51KB
1K SLoC

🔄 Bevy Async ECS

License: MIT Doc Crate Bevy tracking

什么是Bevy Async ECS?

Bevy Async ECS是标准Bevy World的异步接口。它旨在为熟悉Bevy ECS的用户提供简单直观的使用体验。

AsyncWorld

AsyncWorld是进一步异步操作世界入口点。它只能通过使用FromWorld trait实现来创建。它应由与主Bevy应用并行运行的可执行器驱动(这可以是TaskPool之一或运行在另一个线程上的阻塞可执行器)。

内部,AsyncWorld只是封装了一个MPSC通道发送者。因此,它可以便宜地克隆并进一步发送到不同的线程或任务。这意味着所有对AsyncWorld的操作都以FIFO顺序处理。然而,没有在AsyncWorld之间或共享相同内部通道发送者的任何衍生品之间,或者任何单独构建的AsyncWorld之间的顺序保证。

需要注意的是,当异步任务运行时,Bevy仍在运行并修改世界!假设世界可能在任何异步调用之间被修改。然而,有几种方法可以确保多个命令一起应用,而不在之间修改世界。

  • 构建一个纯Bevy CommandQueue,然后通过CommandQueueSender::send_queue()将其发送到Bevy World
  • 通过AsyncWorld::start_queue()使用由AsyncWorld提供的队列构建器

基本示例

use bevy::prelude::*;
use bevy::tasks::AsyncComputeTaskPool;
use bevy_async_ecs::*;

// vanilla Bevy system
fn print_names(query: Query<(Entity, &Name)>) {
	for (id, name) in query.iter() {
		info!("entity {:?} has name '{}'", id, name);
	}
}

fn main() {
	App::new()
		.add_plugins((DefaultPlugins, AsyncEcsPlugin))
		.add_systems(Startup, |world: &mut World| {
			let async_world = AsyncWorld::from_world(world);
			let fut = async move {
				let print_names = async_world.register_system(print_names).await;

				let entity = async_world.spawn_named("Frank").await;
				print_names.run().await;
				entity.despawn().await;
			};
			AsyncComputeTaskPool::get().spawn(fut).detach();
		})
		.run();
}

多线程

bevy-async-ecs不明确要求multi-threaded功能(尽管所有测试和示例都这么做)。然而,当任务执行器在单个线程上运行时(例如在wasm上),异步世界可能会发生死锁。如果这是您的一个痛点,请打开一个GitHub问题。

最近兼容的版本

bevy bevy-async-ecs
0.14 0.6.0
0.13 0.5.1
0.12 0.4.1
0.11 N/A

依赖项

~12MB
~202K SLoC