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

问题描述

一个Bevy项目中,其中包含以下名为my_scene.scn的场景文件

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

此源代码位于this official Bevy example之后:

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。根据{{​​3}},这 将替换之前的SpriteComponents

对应的场景文件是:

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