Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

let user run a function on a scene entities #1058

Merged
merged 6 commits into from
Jan 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ path = "examples/2d/contributors.rs"
name = "text2d"
path = "examples/2d/text2d.rs"

[[example]]
name = "3d_scene"
path = "examples/3d/3d_scene.rs"

[[example]]
name = "load_gltf"
path = "examples/3d/load_gltf.rs"
Expand All @@ -118,10 +122,6 @@ path = "examples/3d/msaa.rs"
name = "parenting"
path = "examples/3d/parenting.rs"

[[example]]
name = "3d_scene"
path = "examples/3d/3d_scene.rs"

[[example]]
name = "spawner"
path = "examples/3d/spawner.rs"
Expand All @@ -130,6 +130,10 @@ path = "examples/3d/spawner.rs"
name = "texture"
path = "examples/3d/texture.rs"

[[example]]
name = "update_gltf_scene"
path = "examples/3d/update_gltf_scene.rs"

[[example]]
name = "z_sort_debug"
path = "examples/3d/z_sort_debug.rs"
Expand Down
31 changes: 24 additions & 7 deletions crates/bevy_scene/src/scene_spawner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ struct InstanceInfo {
}

#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
struct InstanceId(Uuid);
pub struct InstanceId(Uuid);

impl InstanceId {
pub fn new() -> Self {
fn new() -> Self {
InstanceId(Uuid::new_v4())
}
}
Expand Down Expand Up @@ -51,15 +51,17 @@ impl SceneSpawner {
self.dynamic_scenes_to_spawn.push(scene_handle);
}

pub fn spawn(&mut self, scene_handle: Handle<Scene>) {
pub fn spawn(&mut self, scene_handle: Handle<Scene>) -> InstanceId {
let instance_id = InstanceId::new();
self.scenes_to_spawn.push((scene_handle, instance_id));
instance_id
}

pub fn spawn_as_child(&mut self, scene_handle: Handle<Scene>, parent: Entity) {
pub fn spawn_as_child(&mut self, scene_handle: Handle<Scene>, parent: Entity) -> InstanceId {
let instance_id = InstanceId::new();
self.scenes_to_spawn.push((scene_handle, instance_id));
self.scenes_with_parent.push((instance_id, parent));
instance_id
}

pub fn despawn(&mut self, scene_handle: Handle<DynamicScene>) {
Expand Down Expand Up @@ -155,7 +157,7 @@ impl SceneSpawner {
world: &mut World,
resources: &Resources,
scene_handle: Handle<Scene>,
) -> Result<(), SceneSpawnError> {
) -> Result<InstanceId, SceneSpawnError> {
self.spawn_sync_internal(world, resources, scene_handle, InstanceId::new())
}

Expand All @@ -165,7 +167,7 @@ impl SceneSpawner {
resources: &Resources,
scene_handle: Handle<Scene>,
instance_id: InstanceId,
) -> Result<(), SceneSpawnError> {
) -> Result<InstanceId, SceneSpawnError> {
let mut instance_info = InstanceInfo {
entity_map: EntityMap::default(),
};
Expand Down Expand Up @@ -220,7 +222,7 @@ impl SceneSpawner {
.entry(scene_handle)
.or_insert_with(Vec::new);
spawned.push(instance_id);
Ok(())
Ok(instance_id)
}

pub fn update_spawned_scenes(
Expand Down Expand Up @@ -304,6 +306,21 @@ impl SceneSpawner {
}
}
}

/// Check that an scene instance spawned previously is ready to use
pub fn instance_is_ready(&self, instance_id: InstanceId) -> bool {
self.spawned_instances.contains_key(&instance_id)
}

/// Get an iterator over the entities in an instance, once it's spawned
pub fn iter_instance_entities(
&'_ self,
instance_id: InstanceId,
) -> Option<impl Iterator<Item = Entity> + '_> {
self.spawned_instances
.get(&instance_id)
.map(|instance| instance.entity_map.values())
}
}

pub fn scene_spawner_system(world: &mut World, resources: &mut Resources) {
Expand Down
93 changes: 93 additions & 0 deletions examples/3d/update_gltf_scene.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use bevy::{prelude::*, scene::InstanceId};

fn main() {
App::build()
.add_resource(Msaa { samples: 4 })
.add_plugins(DefaultPlugins)
.add_resource(SceneInstance::default())
.add_startup_system(setup.system())
.add_system(scene_update.system())
.add_system(move_scene_entities.system())
.run();
}

// Resource to hold the scene `instance_id` until it is loaded
#[derive(Default)]
struct SceneInstance(Option<InstanceId>);

// Component that will be used to tag entities in the scene
struct EntityInMyScene;

fn setup(
commands: &mut Commands,
asset_server: Res<AssetServer>,
mut scene_spawner: ResMut<SceneSpawner>,
mut scene_instance: ResMut<SceneInstance>,
) {
commands
.spawn(LightBundle {
transform: Transform::from_translation(Vec3::new(4.0, 5.0, 4.0)),
..Default::default()
})
.spawn(Camera3dBundle {
transform: Transform::from_translation(Vec3::new(1.05, 0.9, 1.5))
.looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::unit_y()),
..Default::default()
});

// Spawn the scene as a child of another entity. This first scene will be translated backward
// with its parent
commands
.spawn((
Transform::from_translation(Vec3::new(0.0, 0.0, -1.0)),
GlobalTransform::default(),
))
.with_children(|parent| {
parent.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf"));
});

// Spawn a second scene, and keep its `instance_id`
let instance_id =
scene_spawner.spawn(asset_server.load("models/FlightHelmet/FlightHelmet.gltf"));
scene_instance.0 = Some(instance_id);
}

// This system will wait for the scene to be ready, and then tag entities from
// the scene with `EntityInMyScene`. All entities from the second scene will be
// tagged
fn scene_update(
commands: &mut Commands,
scene_spawner: Res<SceneSpawner>,
scene_instance: Res<SceneInstance>,
mut done: Local<bool>,
) {
if !*done {
if let Some(instance_id) = scene_instance.0 {
if let Some(entity_iter) = scene_spawner.iter_instance_entities(instance_id) {
entity_iter.for_each(|entity| {
commands.insert_one(entity, EntityInMyScene);
});
*done = true;
}
}
}
}

// This system will move all entities with component `EntityInMyScene`, so all
// entities from the second scene
fn move_scene_entities(
time: Res<Time>,
mut scene_entities: Query<&mut Transform, With<EntityInMyScene>>,
) {
let mut direction = 1.;
let mut scale = 1.;
for mut transform in scene_entities.iter_mut() {
transform.translation = Vec3::new(
scale * direction * time.seconds_since_startup().sin() as f32 / 20.,
0.,
time.seconds_since_startup().cos() as f32 / 20.,
);
direction *= -1.;
scale += 0.5;
}
}
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ Example | File | Description
`parenting` | [`3d/parenting.rs`](./3d/parenting.rs) | Demonstrates parent->child relationships and relative transformations
`spawner` | [`3d/spawner.rs`](./3d/spawner.rs) | Renders a large number of cubes with changing position and material
`texture` | [`3d/texture.rs`](./3d/texture.rs) | Shows configuration of texture materials
`update_gltf_scene` | [`3d/update_gltf_scene.rs`](./3d/update_gltf_scene.rs) | Update a scene from a gltf file, either by spawning the scene as a child of another entity, or by accessing the entities of the scene
`z_sort_debug` | [`3d/z_sort_debug.rs`](./3d/z_sort_debug.rs) | Visualizes camera Z-ordering

## Application
Expand Down