can spawn a scene from a ChildBuilder, or directly set its parent when spawning it (#1026)

can spawn a scene from a ChildBuilder, or directly set its parent when spawning one
This commit is contained in:
François 2020-12-09 21:41:49 +01:00 committed by GitHub
parent c54179b182
commit f53ee54eb6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 9 deletions

View file

@ -18,6 +18,7 @@ bevy_app = { path = "../bevy_app", version = "0.3.0" }
bevy_asset = { path = "../bevy_asset", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" }
bevy_reflect = { path = "../bevy_reflect", version = "0.3.0", features = ["bevy"] }
bevy_transform = { path = "../bevy_transform", version = "0.3.0" }
bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other

View file

@ -1,5 +1,6 @@
use bevy_asset::Handle;
use bevy_ecs::{Command, Commands, Resources, World};
use bevy_ecs::{Command, Commands, Entity, Resources, World};
use bevy_transform::hierarchy::ChildBuilder;
use crate::{Scene, SceneSpawner};
@ -23,3 +24,29 @@ impl SpawnSceneCommands for Commands {
self.add_command(SpawnScene { scene_handle })
}
}
pub struct SpawnSceneAsChild {
scene_handle: Handle<Scene>,
parent: Entity,
}
impl Command for SpawnSceneAsChild {
fn write(self: Box<Self>, _world: &mut World, resources: &mut Resources) {
let mut spawner = resources.get_mut::<SceneSpawner>().unwrap();
spawner.spawn_as_child(self.scene_handle, self.parent);
}
}
pub trait SpawnSceneAsChildCommands {
fn spawn_scene(&mut self, scene: Handle<Scene>) -> &mut Self;
}
impl<'a> SpawnSceneAsChildCommands for ChildBuilder<'a> {
fn spawn_scene(&mut self, scene_handle: Handle<Scene>) -> &mut Self {
self.add_command(SpawnSceneAsChild {
scene_handle,
parent: self.parent_entity(),
});
self
}
}

View file

@ -12,7 +12,9 @@ pub use scene_loader::*;
pub use scene_spawner::*;
pub mod prelude {
pub use crate::{DynamicScene, Scene, SceneSpawner, SpawnSceneCommands};
pub use crate::{
DynamicScene, Scene, SceneSpawner, SpawnSceneAsChildCommands, SpawnSceneCommands,
};
}
use bevy_app::prelude::*;

View file

@ -1,8 +1,9 @@
use crate::{DynamicScene, Scene};
use bevy_app::prelude::*;
use bevy_asset::{AssetEvent, Assets, Handle};
use bevy_ecs::{EntityMap, Resources, World};
use bevy_ecs::{Entity, EntityMap, Resources, World};
use bevy_reflect::{ReflectComponent, ReflectMapEntities, TypeRegistryArc};
use bevy_transform::prelude::Parent;
use bevy_utils::HashMap;
use thiserror::Error;
use uuid::Uuid;
@ -28,8 +29,9 @@ pub struct SceneSpawner {
spawned_instances: HashMap<InstanceId, InstanceInfo>,
scene_asset_event_reader: EventReader<AssetEvent<DynamicScene>>,
dynamic_scenes_to_spawn: Vec<Handle<DynamicScene>>,
scenes_to_spawn: Vec<Handle<Scene>>,
scenes_to_spawn: Vec<(Handle<Scene>, InstanceId)>,
scenes_to_despawn: Vec<Handle<DynamicScene>>,
scenes_with_parent: Vec<(InstanceId, Entity)>,
}
#[derive(Error, Debug)]
@ -50,7 +52,14 @@ impl SceneSpawner {
}
pub fn spawn(&mut self, scene_handle: Handle<Scene>) {
self.scenes_to_spawn.push(scene_handle);
let instance_id = InstanceId::new();
self.scenes_to_spawn.push((scene_handle, instance_id));
}
pub fn spawn_as_child(&mut self, scene_handle: Handle<Scene>, parent: Entity) {
let instance_id = InstanceId::new();
self.scenes_to_spawn.push((scene_handle, instance_id));
self.scenes_with_parent.push((instance_id, parent));
}
pub fn despawn(&mut self, scene_handle: Handle<DynamicScene>) {
@ -147,7 +156,16 @@ impl SceneSpawner {
resources: &Resources,
scene_handle: Handle<Scene>,
) -> Result<(), SceneSpawnError> {
let instance_id = InstanceId::new();
self.spawn_sync_internal(world, resources, scene_handle, InstanceId::new())
}
fn spawn_sync_internal(
&mut self,
world: &mut World,
resources: &Resources,
scene_handle: Handle<Scene>,
instance_id: InstanceId,
) -> Result<(), SceneSpawnError> {
let mut instance_info = InstanceInfo {
entity_map: EntityMap::default(),
};
@ -256,11 +274,11 @@ impl SceneSpawner {
let scenes_to_spawn = std::mem::take(&mut self.scenes_to_spawn);
for scene_handle in scenes_to_spawn {
match self.spawn_sync(world, resources, scene_handle) {
for (scene_handle, instance_id) in scenes_to_spawn {
match self.spawn_sync_internal(world, resources, scene_handle, instance_id) {
Ok(_) => {}
Err(SceneSpawnError::NonExistentRealScene { handle }) => {
self.scenes_to_spawn.push(handle)
self.scenes_to_spawn.push((handle, instance_id))
}
Err(err) => return Err(err),
}
@ -268,6 +286,24 @@ impl SceneSpawner {
Ok(())
}
pub(crate) fn set_scene_instance_parent_sync(&mut self, world: &mut World) {
let scenes_with_parent = std::mem::take(&mut self.scenes_with_parent);
for (instance_id, parent) in scenes_with_parent {
if let Some(instance) = self.spawned_instances.get(&instance_id) {
for entity in instance.entity_map.values() {
if let Err(bevy_ecs::ComponentError::MissingComponent(_)) =
world.get::<Parent>(entity)
{
let _ = world.insert_one(entity, Parent(parent));
}
}
} else {
self.scenes_with_parent.push((instance_id, parent));
}
}
}
}
pub fn scene_spawner_system(world: &mut World, resources: &mut Resources) {
@ -293,4 +329,5 @@ pub fn scene_spawner_system(world: &mut World, resources: &mut Resources) {
scene_spawner
.update_spawned_scenes(world, resources, &updated_spawned_scenes)
.unwrap();
scene_spawner.set_scene_instance_parent_sync(world);
}

View file

@ -81,6 +81,10 @@ impl<'a> ChildBuilder<'a> {
self.commands.current_entity()
}
pub fn parent_entity(&self) -> Entity {
self.push_children.parent
}
pub fn with_bundle(
&mut self,
components: impl DynamicBundle + Send + Sync + 'static,
@ -102,6 +106,11 @@ impl<'a> ChildBuilder<'a> {
func(current_entity);
self
}
pub fn add_command<C: Command + 'static>(&mut self, command: C) -> &mut Self {
self.commands.add_command(command);
self
}
}
pub trait BuildChildren {