Skip to content

Commit c25b41a

Browse files
authored
add scene instance entity iteration (bevyengine#1058)
add scene instance entity iteration
1 parent 030ccf1 commit c25b41a

File tree

4 files changed

+126
-11
lines changed

4 files changed

+126
-11
lines changed

Cargo.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ path = "examples/2d/contributors.rs"
106106
name = "text2d"
107107
path = "examples/2d/text2d.rs"
108108

109+
[[example]]
110+
name = "3d_scene"
111+
path = "examples/3d/3d_scene.rs"
112+
109113
[[example]]
110114
name = "load_gltf"
111115
path = "examples/3d/load_gltf.rs"
@@ -118,10 +122,6 @@ path = "examples/3d/msaa.rs"
118122
name = "parenting"
119123
path = "examples/3d/parenting.rs"
120124

121-
[[example]]
122-
name = "3d_scene"
123-
path = "examples/3d/3d_scene.rs"
124-
125125
[[example]]
126126
name = "spawner"
127127
path = "examples/3d/spawner.rs"
@@ -130,6 +130,10 @@ path = "examples/3d/spawner.rs"
130130
name = "texture"
131131
path = "examples/3d/texture.rs"
132132

133+
[[example]]
134+
name = "update_gltf_scene"
135+
path = "examples/3d/update_gltf_scene.rs"
136+
133137
[[example]]
134138
name = "z_sort_debug"
135139
path = "examples/3d/z_sort_debug.rs"

crates/bevy_scene/src/scene_spawner.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ struct InstanceInfo {
1414
}
1515

1616
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
17-
struct InstanceId(Uuid);
17+
pub struct InstanceId(Uuid);
1818

1919
impl InstanceId {
20-
pub fn new() -> Self {
20+
fn new() -> Self {
2121
InstanceId(Uuid::new_v4())
2222
}
2323
}
@@ -51,15 +51,17 @@ impl SceneSpawner {
5151
self.dynamic_scenes_to_spawn.push(scene_handle);
5252
}
5353

54-
pub fn spawn(&mut self, scene_handle: Handle<Scene>) {
54+
pub fn spawn(&mut self, scene_handle: Handle<Scene>) -> InstanceId {
5555
let instance_id = InstanceId::new();
5656
self.scenes_to_spawn.push((scene_handle, instance_id));
57+
instance_id
5758
}
5859

59-
pub fn spawn_as_child(&mut self, scene_handle: Handle<Scene>, parent: Entity) {
60+
pub fn spawn_as_child(&mut self, scene_handle: Handle<Scene>, parent: Entity) -> InstanceId {
6061
let instance_id = InstanceId::new();
6162
self.scenes_to_spawn.push((scene_handle, instance_id));
6263
self.scenes_with_parent.push((instance_id, parent));
64+
instance_id
6365
}
6466

6567
pub fn despawn(&mut self, scene_handle: Handle<DynamicScene>) {
@@ -155,7 +157,7 @@ impl SceneSpawner {
155157
world: &mut World,
156158
resources: &Resources,
157159
scene_handle: Handle<Scene>,
158-
) -> Result<(), SceneSpawnError> {
160+
) -> Result<InstanceId, SceneSpawnError> {
159161
self.spawn_sync_internal(world, resources, scene_handle, InstanceId::new())
160162
}
161163

@@ -165,7 +167,7 @@ impl SceneSpawner {
165167
resources: &Resources,
166168
scene_handle: Handle<Scene>,
167169
instance_id: InstanceId,
168-
) -> Result<(), SceneSpawnError> {
170+
) -> Result<InstanceId, SceneSpawnError> {
169171
let mut instance_info = InstanceInfo {
170172
entity_map: EntityMap::default(),
171173
};
@@ -220,7 +222,7 @@ impl SceneSpawner {
220222
.entry(scene_handle)
221223
.or_insert_with(Vec::new);
222224
spawned.push(instance_id);
223-
Ok(())
225+
Ok(instance_id)
224226
}
225227

226228
pub fn update_spawned_scenes(
@@ -304,6 +306,21 @@ impl SceneSpawner {
304306
}
305307
}
306308
}
309+
310+
/// Check that an scene instance spawned previously is ready to use
311+
pub fn instance_is_ready(&self, instance_id: InstanceId) -> bool {
312+
self.spawned_instances.contains_key(&instance_id)
313+
}
314+
315+
/// Get an iterator over the entities in an instance, once it's spawned
316+
pub fn iter_instance_entities(
317+
&'_ self,
318+
instance_id: InstanceId,
319+
) -> Option<impl Iterator<Item = Entity> + '_> {
320+
self.spawned_instances
321+
.get(&instance_id)
322+
.map(|instance| instance.entity_map.values())
323+
}
307324
}
308325

309326
pub fn scene_spawner_system(world: &mut World, resources: &mut Resources) {

examples/3d/update_gltf_scene.rs

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use bevy::{prelude::*, scene::InstanceId};
2+
3+
fn main() {
4+
App::build()
5+
.add_resource(Msaa { samples: 4 })
6+
.add_plugins(DefaultPlugins)
7+
.add_resource(SceneInstance::default())
8+
.add_startup_system(setup.system())
9+
.add_system(scene_update.system())
10+
.add_system(move_scene_entities.system())
11+
.run();
12+
}
13+
14+
// Resource to hold the scene `instance_id` until it is loaded
15+
#[derive(Default)]
16+
struct SceneInstance(Option<InstanceId>);
17+
18+
// Component that will be used to tag entities in the scene
19+
struct EntityInMyScene;
20+
21+
fn setup(
22+
commands: &mut Commands,
23+
asset_server: Res<AssetServer>,
24+
mut scene_spawner: ResMut<SceneSpawner>,
25+
mut scene_instance: ResMut<SceneInstance>,
26+
) {
27+
commands
28+
.spawn(LightBundle {
29+
transform: Transform::from_translation(Vec3::new(4.0, 5.0, 4.0)),
30+
..Default::default()
31+
})
32+
.spawn(Camera3dBundle {
33+
transform: Transform::from_translation(Vec3::new(1.05, 0.9, 1.5))
34+
.looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::unit_y()),
35+
..Default::default()
36+
});
37+
38+
// Spawn the scene as a child of another entity. This first scene will be translated backward
39+
// with its parent
40+
commands
41+
.spawn((
42+
Transform::from_translation(Vec3::new(0.0, 0.0, -1.0)),
43+
GlobalTransform::default(),
44+
))
45+
.with_children(|parent| {
46+
parent.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf"));
47+
});
48+
49+
// Spawn a second scene, and keep its `instance_id`
50+
let instance_id =
51+
scene_spawner.spawn(asset_server.load("models/FlightHelmet/FlightHelmet.gltf"));
52+
scene_instance.0 = Some(instance_id);
53+
}
54+
55+
// This system will wait for the scene to be ready, and then tag entities from
56+
// the scene with `EntityInMyScene`. All entities from the second scene will be
57+
// tagged
58+
fn scene_update(
59+
commands: &mut Commands,
60+
scene_spawner: Res<SceneSpawner>,
61+
scene_instance: Res<SceneInstance>,
62+
mut done: Local<bool>,
63+
) {
64+
if !*done {
65+
if let Some(instance_id) = scene_instance.0 {
66+
if let Some(entity_iter) = scene_spawner.iter_instance_entities(instance_id) {
67+
entity_iter.for_each(|entity| {
68+
commands.insert_one(entity, EntityInMyScene);
69+
});
70+
*done = true;
71+
}
72+
}
73+
}
74+
}
75+
76+
// This system will move all entities with component `EntityInMyScene`, so all
77+
// entities from the second scene
78+
fn move_scene_entities(
79+
time: Res<Time>,
80+
mut scene_entities: Query<&mut Transform, With<EntityInMyScene>>,
81+
) {
82+
let mut direction = 1.;
83+
let mut scale = 1.;
84+
for mut transform in scene_entities.iter_mut() {
85+
transform.translation = Vec3::new(
86+
scale * direction * time.seconds_since_startup().sin() as f32 / 20.,
87+
0.,
88+
time.seconds_since_startup().cos() as f32 / 20.,
89+
);
90+
direction *= -1.;
91+
scale += 0.5;
92+
}
93+
}

examples/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Example | File | Description
7373
`parenting` | [`3d/parenting.rs`](./3d/parenting.rs) | Demonstrates parent->child relationships and relative transformations
7474
`spawner` | [`3d/spawner.rs`](./3d/spawner.rs) | Renders a large number of cubes with changing position and material
7575
`texture` | [`3d/texture.rs`](./3d/texture.rs) | Shows configuration of texture materials
76+
`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
7677
`z_sort_debug` | [`3d/z_sort_debug.rs`](./3d/z_sort_debug.rs) | Visualizes camera Z-ordering
7778

7879
## Application

0 commit comments

Comments
 (0)