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_asset = { path = "../bevy_asset", version = "0.3.0" }
bevy_ecs = { path = "../bevy_ecs", 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_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" } bevy_utils = { path = "../bevy_utils", version = "0.3.0" }
# other # other

View file

@ -1,5 +1,6 @@
use bevy_asset::Handle; 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}; use crate::{Scene, SceneSpawner};
@ -23,3 +24,29 @@ impl SpawnSceneCommands for Commands {
self.add_command(SpawnScene { scene_handle }) 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 use scene_spawner::*;
pub mod prelude { pub mod prelude {
pub use crate::{DynamicScene, Scene, SceneSpawner, SpawnSceneCommands}; pub use crate::{
DynamicScene, Scene, SceneSpawner, SpawnSceneAsChildCommands, SpawnSceneCommands,
};
} }
use bevy_app::prelude::*; use bevy_app::prelude::*;

View file

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

View file

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