#scene #process #bevy #post #hook

bevy_scene_postprocess

一个为Bevy提供的在加载场景后进行后处理的crate。

1个不稳定版本

0.1.0 2024年8月23日

#561 in 游戏开发

Download history 166/week @ 2024-08-18

每月 166 次下载

MIT/Apache

35KB
571

bevy_scene_postprocess

一个为Bevy提供的在加载场景后进行“后处理”的crate。

为什么?

场景很棒,但有一个大问题:它们通常是从GLTF加载的。这意味着场景的表现力受限于GLTF。像Blenvy这样的crate通过提供操作生成场景的方法(在Blenvy的情况下,通过将GltfExtra解码为组件)使这变得更好。

虽然这很好,但存在一个尴尬的问题。这要求你生成场景,然后等待新生成的场景被处理。这意味着对场景的任何更改(例如,解码GltfExtra)都需要在每次生成场景时重复。此外,这种方法与同步生成场景不兼容。

使用bevy_scene_postprocess,你只需注册你的后处理操作,它将在所有操作完成后才分配场景。这意味着你只需在加载你的应用程序时执行一次操作,然后Bevy就只是生成场景而没有任何特殊之处。

另一个类似的crate是bevy_scene_hook,但它是在生成完成后执行操作。注意,即使有后处理,bevy_scene_hook仍然有用。也许你想要执行那些不适合“烘焙”到后处理中的对象操作。

如何使用

  1. 像平时一样加载一个场景。
  2. 调用ScenePostProcessor::process
  3. 像平时一样使用返回的句柄(例如,在SceneBundle中)。

示例

以下示例只生成一次场景,该场景只包含Bar

use std::{
  sync::Arc, time::Duration
};

use bevy::{
  prelude::*, ecs::system::RunSystemOnce, scene::ScenePlugin,
  time::common_conditions::once_after_delay
};
use bevy_scene_postprocess::{ScenePostProcessPlugin, ScenePostProcessor};

fn main() {
  App::new()
    .add_plugins(MinimalPlugins)
    .add_plugins(AssetPlugin::default())
    .add_plugins(ScenePlugin)
    .add_plugins(ScenePostProcessPlugin)
    .add_systems(Startup, register_post_process)
    .add_systems(
      Update,
      fake_load_scene.run_if(once_after_delay(Duration::from_secs_f32(0.1))),
    )
    .add_systems(
      Update,
      (
        move |mut exit: EventWriter<AppExit>| {
          // Quite after loading to let the doctests pass.
          exit.send(AppExit::Success);
        }
      ).run_if(once_after_delay(Duration::from_secs_f32(0.5))),
    )
    .run();
}

fn register_post_process(
  scenes: Res<Assets<Scene>>,
  mut post_processor: ScenePostProcessor,
  mut commands: Commands
) {
  // Pretend we loaded an asset here (loading an asset for real would break
  // doctests).
  let handle = scenes.reserve_handle();
  commands.insert_resource(LoadingHandle(handle.clone()));

  let processed_scene = post_processor.process(handle, vec![
    Arc::new(move |world: &mut World| {
      // For example convenience, just run a system.
      world.run_system_once(replace_foos_with_bar);
      Ok(())
    })
  ]);

  commands.spawn(SceneBundle {
    scene: processed_scene,
    ..Default::default()
  });
}

#[derive(Resource)]
struct LoadingHandle(Handle<Scene>);

#[derive(Component)]
struct Foo;

#[derive(Component)]
struct Bar;

fn replace_foos_with_bar(foos: Query<Entity, With<Foo>>, mut commands: Commands) {
  for entity in foos.iter() {
    commands.entity(entity).remove::<Foo>().insert(Bar);
  }
}

fn fake_load_scene(
  handle: Res<LoadingHandle>,
  mut scenes: ResMut<Assets<Scene>>
) {
  let mut new_scene = Scene {
    world: World::new(),
  };

  // Spawn three entities with `Foo`. They will be replaced with `Bar` by the
  // post processing.
  new_scene.world.spawn(Foo);
  new_scene.world.spawn(Foo);
  new_scene.world.spawn(Foo);

  scenes.insert(&handle.0, new_scene);
}

许可证

根据以下任一许可证许可:

由你选择。

贡献

除非您明确声明,否则您根据Apache-2.0许可证定义的,有意提交以包含在该作品中的任何贡献,应按上述方式双重许可,不得附加任何其他条款或条件。

依赖项

~33–71MB
~1M SLoC