如何将组件添加到场景中生成的实体?

How to add components to entities spawned in a scene?

在具有以下名为 my_scene.scn 的场景文件的 Bevy 项目中:

[
  (
    entity: 0,
    components: [
      {
        "type": "Transform",
        "map": {
          "translation": {
            "type": "Vec3", 
            "value": (150.0, 200.0, 0.0),
          },
          "rotation": {
            "type": "Quat",
            "value": (0.0, 0.0, 0.0, 1.0),
          },
          "scale": {
            "type": "Vec3",
            "value": (0.75, 0.75, 0.0),
          },
        },
      },
    ]
  )
]

并且这个源代码遵循 这个官方 Bevy 例子:

use bevy::prelude::*;

fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .add_startup_system(load_scene_system.system())
        .run();
}

fn load_scene_system(asset_server: Res<AssetServer>, mut scene_spawner: ResMut<SceneSpawner>) {
    let scene_handle: Handle<Scene> = asset_server.load("my_scene.scn");

    scene_spawner.spawn_dynamic(scene_handle);
    // ^ How to add components to entities created here ?

    asset_server.watch_for_changes().unwrap();
}

我想向这个实体 0 添加其他组件,例如 SpriteComponents。我该如何实现?

这是我想出的解决方案。这个想法是存储一个组件 包含创建更动态组件的信息。

例如,要动态加载场景文件中引用的精灵图像,我们 可以定义一个SpriteLoader组件,然后添加一个系统,用我们想要的组件替换这个加载器组件。

use bevy::prelude::*;

fn main() {
    App::build()
        .add_plugins(DefaultPlugins)
        .register_component::<SpriteLoader>()
        .add_startup_system(load_scene_system.system())
        .add_system(load_sprite_system.system())
        .run();
}

fn load_scene_system(asset_server: Res<AssetServer>, mut scene_spawner: ResMut<SceneSpawner>) {
    let scene_handle: Handle<DynamicScene> = asset_server.load("my_scene.scn");
    scene_spawner.spawn_dynamic(scene_handle);
    asset_server.watch_for_changes().unwrap();
}

/// Component indicating that a sprite will be loaded for the entity.
#[derive(Properties, Default)]
pub struct SpriteLoader {
    /// Path of the sprite to load
    pub path: String
}

/// Replaces the `SpritLoader` component with the corresponding `SpriteComponents`.
pub fn load_sprite_system(
    mut commands: Commands,
    asset_server: Res<AssetServer>,
    mut materials: ResMut<Assets<ColorMaterial>>,
    query: Query<(Entity, Added<SpriteLoader>)>,
) {
    for (entity, sprite_loader) in query.iter() {
        commands.remove_one::<SpriteLoader>(entity);

        let path = PathBuf::from(sprite_loader.path.clone());

        commands.insert(
            entity,
            SpriteComponents {
                material: materials.add(asset_server.load(path).into()),
                ..SpriteComponents::default()
            },
        );
    }
}

这里,一旦一个SpriteLoader被添加到实体中,load_sprite_system系统将删除它并插入一个 SpriteComponents 代替。根据 的文档 insert, 这个 将替换之前的 SpriteComponents.

对应的场景文件为:

[
  (
    entity: 0,
    components: [
      {
        "type": "SpriteLoader",
        "map": { 
          "path": "my_sprite.png",
        },
      },
    ]
  )
]