mirror of
https://github.com/bevyengine/bevy
synced 2024-11-10 07:04:33 +00:00
add a SceneBundle
to spawn a scene (#2424)
# Objective - Spawning a scene is handled as a special case with a command `spawn_scene` that takes an handle but doesn't let you specify anything else. This is the only handle that works that way. - Workaround for this have been to add the `spawn_scene` on `ChildBuilder` to be able to specify transform of parent, or to make the `SceneSpawner` available to be able to select entities from a scene by their instance id ## Solution Add a bundle ```rust pub struct SceneBundle { pub scene: Handle<Scene>, pub transform: Transform, pub global_transform: GlobalTransform, pub instance_id: Option<InstanceId>, } ``` and instead of ```rust commands.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0")); ``` you can do ```rust commands.spawn_bundle(SceneBundle { scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"), ..Default::default() }); ``` The scene will be spawned as a child of the entity with the `SceneBundle` ~I would like to remove the command `spawn_scene` in favor of this bundle but didn't do it yet to get feedback first~ Co-authored-by: François <8672791+mockersf@users.noreply.github.com> Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
parent
cdb62af4bf
commit
c6958b3056
18 changed files with 264 additions and 189 deletions
|
@ -25,7 +25,11 @@ impl FromWorld for Parent {
|
|||
|
||||
impl MapEntities for Parent {
|
||||
fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> {
|
||||
self.0 = entity_map.get(self.0)?;
|
||||
// Parent of an entity in the new world can be in outside world, in which case it
|
||||
// should not be mapped.
|
||||
if let Ok(mapped_entity) = entity_map.get(self.0) {
|
||||
self.0 = mapped_entity;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -51,7 +55,11 @@ pub struct PreviousParent(pub(crate) Entity);
|
|||
|
||||
impl MapEntities for PreviousParent {
|
||||
fn map_entities(&mut self, entity_map: &EntityMap) -> Result<(), MapEntitiesError> {
|
||||
self.0 = entity_map.get(self.0)?;
|
||||
// PreviousParent of an entity in the new world can be in outside world, in which
|
||||
// case it should not be mapped.
|
||||
if let Ok(mapped_entity) = entity_map.get(self.0) {
|
||||
self.0 = mapped_entity;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,9 +12,11 @@ keywords = ["bevy"]
|
|||
# bevy
|
||||
bevy_app = { path = "../bevy_app", version = "0.8.0-dev" }
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.8.0-dev" }
|
||||
bevy_derive = { path = "../bevy_derive", version = "0.8.0-dev" }
|
||||
bevy_ecs = { path = "../bevy_ecs", version = "0.8.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.8.0-dev", features = ["bevy"] }
|
||||
bevy_hierarchy = { path = "../bevy_hierarchy", version = "0.8.0-dev" }
|
||||
bevy_transform = { path = "../bevy_transform", version = "0.8.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.8.0-dev" }
|
||||
|
||||
# other
|
||||
|
|
74
crates/bevy_scene/src/bundle.rs
Normal file
74
crates/bevy_scene/src/bundle.rs
Normal file
|
@ -0,0 +1,74 @@
|
|||
use bevy_asset::Handle;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
bundle::Bundle,
|
||||
change_detection::ResMut,
|
||||
entity::Entity,
|
||||
prelude::{Changed, Component, Without},
|
||||
system::{Commands, Query},
|
||||
};
|
||||
use bevy_transform::components::{GlobalTransform, Transform};
|
||||
|
||||
use crate::{DynamicScene, InstanceId, Scene, SceneSpawner};
|
||||
|
||||
/// [`InstanceId`] of a spawned scene. It can be used with the [`SceneSpawner`] to
|
||||
/// interact with the spawned scene.
|
||||
#[derive(Component, Deref, DerefMut)]
|
||||
pub struct SceneInstance(InstanceId);
|
||||
|
||||
/// A component bundle for a [`Scene`] root.
|
||||
///
|
||||
/// The scene from `scene` will be spawn as a child of the entity with this component.
|
||||
/// Once it's spawned, the entity will have a [`SceneInstance`] component.
|
||||
#[derive(Default, Bundle)]
|
||||
pub struct SceneBundle {
|
||||
/// Handle to the scene to spawn
|
||||
pub scene: Handle<Scene>,
|
||||
pub transform: Transform,
|
||||
pub global_transform: GlobalTransform,
|
||||
}
|
||||
|
||||
/// A component bundle for a [`DynamicScene`] root.
|
||||
///
|
||||
/// The dynamic scene from `scene` will be spawn as a child of the entity with this component.
|
||||
/// Once it's spawned, the entity will have a [`SceneInstance`] component.
|
||||
#[derive(Default, Bundle)]
|
||||
pub struct DynamicSceneBundle {
|
||||
/// Handle to the scene to spawn
|
||||
pub scene: Handle<DynamicScene>,
|
||||
pub transform: Transform,
|
||||
pub global_transform: GlobalTransform,
|
||||
}
|
||||
|
||||
/// System that will spawn scenes from [`SceneBundle`].
|
||||
pub fn scene_spawner(
|
||||
mut commands: Commands,
|
||||
mut scene_to_spawn: Query<
|
||||
(Entity, &Handle<Scene>, Option<&mut SceneInstance>),
|
||||
(Changed<Handle<Scene>>, Without<Handle<DynamicScene>>),
|
||||
>,
|
||||
mut dynamic_scene_to_spawn: Query<
|
||||
(Entity, &Handle<DynamicScene>, Option<&mut SceneInstance>),
|
||||
(Changed<Handle<DynamicScene>>, Without<Handle<Scene>>),
|
||||
>,
|
||||
mut scene_spawner: ResMut<SceneSpawner>,
|
||||
) {
|
||||
for (entity, scene, instance) in scene_to_spawn.iter_mut() {
|
||||
let new_instance = scene_spawner.spawn_as_child(scene.clone(), entity);
|
||||
if let Some(mut old_instance) = instance {
|
||||
scene_spawner.despawn_instance(**old_instance);
|
||||
*old_instance = SceneInstance(new_instance);
|
||||
} else {
|
||||
commands.entity(entity).insert(SceneInstance(new_instance));
|
||||
}
|
||||
}
|
||||
for (entity, dynamic_scene, instance) in dynamic_scene_to_spawn.iter_mut() {
|
||||
let new_instance = scene_spawner.spawn_dynamic_as_child(dynamic_scene.clone(), entity);
|
||||
if let Some(mut old_instance) = instance {
|
||||
scene_spawner.despawn_instance(**old_instance);
|
||||
*old_instance = SceneInstance(new_instance);
|
||||
} else {
|
||||
commands.entity(entity).insert(SceneInstance(new_instance));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
use bevy_asset::Handle;
|
||||
use bevy_ecs::{
|
||||
entity::Entity,
|
||||
system::{Command, Commands},
|
||||
world::World,
|
||||
};
|
||||
use bevy_hierarchy::ChildBuilder;
|
||||
|
||||
use crate::{Scene, SceneSpawner};
|
||||
|
||||
pub struct SpawnScene {
|
||||
scene_handle: Handle<Scene>,
|
||||
}
|
||||
|
||||
impl Command for SpawnScene {
|
||||
fn write(self, world: &mut World) {
|
||||
let mut spawner = world.resource_mut::<SceneSpawner>();
|
||||
spawner.spawn(self.scene_handle);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SpawnSceneCommands {
|
||||
fn spawn_scene(&mut self, scene: Handle<Scene>);
|
||||
}
|
||||
|
||||
impl<'w, 's> SpawnSceneCommands for Commands<'w, 's> {
|
||||
fn spawn_scene(&mut self, scene_handle: Handle<Scene>) {
|
||||
self.add(SpawnScene { scene_handle });
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SpawnSceneAsChild {
|
||||
scene_handle: Handle<Scene>,
|
||||
parent: Entity,
|
||||
}
|
||||
|
||||
impl Command for SpawnSceneAsChild {
|
||||
fn write(self, world: &mut World) {
|
||||
let mut spawner = world.resource_mut::<SceneSpawner>();
|
||||
spawner.spawn_as_child(self.scene_handle, self.parent);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait SpawnSceneAsChildCommands {
|
||||
fn spawn_scene(&mut self, scene: Handle<Scene>) -> &mut Self;
|
||||
}
|
||||
|
||||
impl<'w, 's, 'a> SpawnSceneAsChildCommands for ChildBuilder<'w, 's, 'a> {
|
||||
fn spawn_scene(&mut self, scene_handle: Handle<Scene>) -> &mut Self {
|
||||
self.add_command(SpawnSceneAsChild {
|
||||
scene_handle,
|
||||
parent: self.parent_entity(),
|
||||
});
|
||||
self
|
||||
}
|
||||
}
|
|
@ -9,6 +9,12 @@ use bevy_reflect::{Reflect, TypeRegistryArc, TypeUuid};
|
|||
use serde::Serialize;
|
||||
|
||||
/// A collection of serializable dynamic entities, each with its own run-time defined set of components.
|
||||
/// To spawn a dynamic scene, you can use either:
|
||||
/// * [`SceneSpawner::spawn_dynamic`](crate::SceneSpawner::spawn_dynamic)
|
||||
/// * adding the [`DynamicSceneBundle`](crate::DynamicSceneBundle) to an entity
|
||||
/// * adding the [`Handle<DynamicScene>`](bevy_asset::Handle) to an entity (the scene will only be
|
||||
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
|
||||
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
|
||||
#[derive(Default, TypeUuid)]
|
||||
#[uuid = "749479b1-fb8c-4ff8-a775-623aa76014f5"]
|
||||
pub struct DynamicScene {
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
mod command;
|
||||
mod bundle;
|
||||
mod dynamic_scene;
|
||||
mod scene;
|
||||
mod scene_loader;
|
||||
mod scene_spawner;
|
||||
pub mod serde;
|
||||
|
||||
pub use command::*;
|
||||
pub use bundle::*;
|
||||
pub use dynamic_scene::*;
|
||||
pub use scene::*;
|
||||
pub use scene_loader::*;
|
||||
|
@ -13,9 +13,7 @@ pub use scene_spawner::*;
|
|||
|
||||
pub mod prelude {
|
||||
#[doc(hidden)]
|
||||
pub use crate::{
|
||||
DynamicScene, Scene, SceneSpawner, SpawnSceneAsChildCommands, SpawnSceneCommands,
|
||||
};
|
||||
pub use crate::{DynamicScene, DynamicSceneBundle, Scene, SceneBundle, SceneSpawner};
|
||||
}
|
||||
|
||||
use bevy_app::prelude::*;
|
||||
|
@ -34,6 +32,8 @@ impl Plugin for ScenePlugin {
|
|||
.add_system_to_stage(
|
||||
CoreStage::PreUpdate,
|
||||
scene_spawner_system.exclusive_system().at_end(),
|
||||
);
|
||||
)
|
||||
// Systems `*_bundle_spawner` must run before `scene_spawner_system`
|
||||
.add_system_to_stage(CoreStage::PreUpdate, scene_spawner);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
use bevy_ecs::world::World;
|
||||
use bevy_reflect::TypeUuid;
|
||||
|
||||
/// To spawn a scene, you can use either:
|
||||
/// * [`SceneSpawner::spawn`](crate::SceneSpawner::spawn)
|
||||
/// * adding the [`SceneBundle`](crate::SceneBundle) to an entity
|
||||
/// * adding the [`Handle<Scene>`](bevy_asset::Handle) to an entity (the scene will only be
|
||||
/// visible if the entity already has [`Transform`](bevy_transform::components::Transform) and
|
||||
/// [`GlobalTransform`](bevy_transform::components::GlobalTransform) components)
|
||||
#[derive(Debug, TypeUuid)]
|
||||
#[uuid = "c156503c-edd9-4ec7-8d33-dab392df03cd"]
|
||||
pub struct Scene {
|
||||
|
|
|
@ -33,9 +33,10 @@ pub struct SceneSpawner {
|
|||
spawned_dynamic_scenes: HashMap<Handle<DynamicScene>, Vec<InstanceId>>,
|
||||
spawned_instances: HashMap<InstanceId, InstanceInfo>,
|
||||
scene_asset_event_reader: ManualEventReader<AssetEvent<DynamicScene>>,
|
||||
dynamic_scenes_to_spawn: Vec<Handle<DynamicScene>>,
|
||||
dynamic_scenes_to_spawn: Vec<(Handle<DynamicScene>, InstanceId)>,
|
||||
scenes_to_spawn: Vec<(Handle<Scene>, InstanceId)>,
|
||||
scenes_to_despawn: Vec<Handle<DynamicScene>>,
|
||||
instances_to_despawn: Vec<InstanceId>,
|
||||
scenes_with_parent: Vec<(InstanceId, Entity)>,
|
||||
}
|
||||
|
||||
|
@ -53,7 +54,21 @@ pub enum SceneSpawnError {
|
|||
|
||||
impl SceneSpawner {
|
||||
pub fn spawn_dynamic(&mut self, scene_handle: Handle<DynamicScene>) {
|
||||
self.dynamic_scenes_to_spawn.push(scene_handle);
|
||||
let instance_id = InstanceId::new();
|
||||
self.dynamic_scenes_to_spawn
|
||||
.push((scene_handle, instance_id));
|
||||
}
|
||||
|
||||
pub fn spawn_dynamic_as_child(
|
||||
&mut self,
|
||||
scene_handle: Handle<DynamicScene>,
|
||||
parent: Entity,
|
||||
) -> InstanceId {
|
||||
let instance_id = InstanceId::new();
|
||||
self.dynamic_scenes_to_spawn
|
||||
.push((scene_handle, instance_id));
|
||||
self.scenes_with_parent.push((instance_id, parent));
|
||||
instance_id
|
||||
}
|
||||
|
||||
pub fn spawn(&mut self, scene_handle: Handle<Scene>) -> InstanceId {
|
||||
|
@ -73,26 +88,31 @@ impl SceneSpawner {
|
|||
self.scenes_to_despawn.push(scene_handle);
|
||||
}
|
||||
|
||||
pub fn despawn_instance(&mut self, instance_id: InstanceId) {
|
||||
self.instances_to_despawn.push(instance_id);
|
||||
}
|
||||
|
||||
pub fn despawn_sync(
|
||||
&mut self,
|
||||
world: &mut World,
|
||||
scene_handle: Handle<DynamicScene>,
|
||||
) -> Result<(), SceneSpawnError> {
|
||||
if let Some(instance_ids) = self.spawned_dynamic_scenes.get(&scene_handle) {
|
||||
if let Some(instance_ids) = self.spawned_dynamic_scenes.remove(&scene_handle) {
|
||||
for instance_id in instance_ids {
|
||||
if let Some(instance) = self.spawned_instances.get(instance_id) {
|
||||
for entity in instance.entity_map.values() {
|
||||
let _ = world.despawn(entity); // Ignore the result, despawn only cares if
|
||||
// it exists.
|
||||
}
|
||||
}
|
||||
self.despawn_instance_sync(world, &instance_id);
|
||||
}
|
||||
|
||||
self.spawned_dynamic_scenes.remove(&scene_handle);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn despawn_instance_sync(&mut self, world: &mut World, instance_id: &InstanceId) {
|
||||
if let Some(instance) = self.spawned_instances.remove(instance_id) {
|
||||
for entity in instance.entity_map.values() {
|
||||
let _ = world.despawn(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_dynamic_sync(
|
||||
&mut self,
|
||||
world: &mut World,
|
||||
|
@ -235,14 +255,33 @@ impl SceneSpawner {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn despawn_queued_instances(&mut self, world: &mut World) {
|
||||
let instances_to_despawn = std::mem::take(&mut self.instances_to_despawn);
|
||||
|
||||
for instance_id in instances_to_despawn {
|
||||
self.despawn_instance_sync(world, &instance_id);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn spawn_queued_scenes(&mut self, world: &mut World) -> Result<(), SceneSpawnError> {
|
||||
let scenes_to_spawn = std::mem::take(&mut self.dynamic_scenes_to_spawn);
|
||||
|
||||
for scene_handle in scenes_to_spawn {
|
||||
match self.spawn_dynamic_sync(world, &scene_handle) {
|
||||
Ok(_) => {}
|
||||
for (scene_handle, instance_id) in scenes_to_spawn {
|
||||
let mut entity_map = EntityMap::default();
|
||||
|
||||
match Self::spawn_dynamic_internal(world, &scene_handle, &mut entity_map) {
|
||||
Ok(_) => {
|
||||
self.spawned_instances
|
||||
.insert(instance_id, InstanceInfo { entity_map });
|
||||
let spawned = self
|
||||
.spawned_dynamic_scenes
|
||||
.entry(scene_handle.clone())
|
||||
.or_insert_with(Vec::new);
|
||||
spawned.push(instance_id);
|
||||
}
|
||||
Err(SceneSpawnError::NonExistentScene { .. }) => {
|
||||
self.dynamic_scenes_to_spawn.push(scene_handle);
|
||||
self.dynamic_scenes_to_spawn
|
||||
.push((scene_handle, instance_id));
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
@ -327,6 +366,7 @@ pub fn scene_spawner_system(world: &mut World) {
|
|||
}
|
||||
|
||||
scene_spawner.despawn_queued_scenes(world).unwrap();
|
||||
scene_spawner.despawn_queued_instances(world);
|
||||
scene_spawner
|
||||
.spawn_queued_scenes(world)
|
||||
.unwrap_or_else(|err| panic!("{}", err));
|
||||
|
|
|
@ -15,7 +15,6 @@ fn main() {
|
|||
}
|
||||
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
commands.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"));
|
||||
commands.spawn_bundle(Camera3dBundle {
|
||||
transform: Transform::from_xyz(0.7, 0.7, 1.0).looking_at(Vec3::new(0.0, 0.3, 0.0), Vec3::Y),
|
||||
..default()
|
||||
|
@ -37,6 +36,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
},
|
||||
..default()
|
||||
});
|
||||
commands.spawn_bundle(SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
||||
fn animate_light_direction(
|
||||
|
|
|
@ -29,7 +29,10 @@ fn setup(
|
|||
..default()
|
||||
});
|
||||
|
||||
commands.spawn_scene(asset_server.load("models/animated/Fox.glb#Scene0"));
|
||||
commands.spawn_bundle(SceneBundle {
|
||||
scene: asset_server.load("models/animated/Fox.glb#Scene0"),
|
||||
..default()
|
||||
});
|
||||
|
||||
// Light
|
||||
commands.spawn_bundle(DirectionalLightBundle {
|
||||
|
|
|
@ -1,32 +1,20 @@
|
|||
//! 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.
|
||||
|
||||
use bevy::{prelude::*, scene::InstanceId};
|
||||
use bevy::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.init_resource::<SceneInstance>()
|
||||
.add_startup_system(setup)
|
||||
.add_system(scene_update)
|
||||
.add_system(move_scene_entities)
|
||||
.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
|
||||
#[derive(Component)]
|
||||
struct EntityInMyScene;
|
||||
struct MovedScene;
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut scene_spawner: ResMut<SceneSpawner>,
|
||||
mut scene_instance: ResMut<SceneInstance>,
|
||||
) {
|
||||
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
commands.spawn_bundle(PointLightBundle {
|
||||
transform: Transform::from_xyz(4.0, 5.0, 4.0),
|
||||
..default()
|
||||
|
@ -37,56 +25,49 @@ fn setup(
|
|||
..default()
|
||||
});
|
||||
|
||||
// Spawn the scene as a child of another entity. This first scene will be translated backward
|
||||
// with its parent
|
||||
commands
|
||||
.spawn_bundle(TransformBundle::from(Transform::from_xyz(0.0, 0.0, -1.0)))
|
||||
.with_children(|parent| {
|
||||
parent.spawn_scene(asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"));
|
||||
});
|
||||
// Spawn the scene as a child of this entity at the given transform
|
||||
commands.spawn_bundle(SceneBundle {
|
||||
transform: Transform::from_xyz(0.0, 0.0, -1.0),
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
..default()
|
||||
});
|
||||
|
||||
// Spawn a second scene, and keep its `instance_id`
|
||||
let instance_id =
|
||||
scene_spawner.spawn(asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"));
|
||||
scene_instance.0 = Some(instance_id);
|
||||
// Spawn a second scene, and add a tag component to be able to target it later
|
||||
commands
|
||||
.spawn_bundle(SceneBundle {
|
||||
scene: asset_server.load("models/FlightHelmet/FlightHelmet.gltf#Scene0"),
|
||||
..default()
|
||||
})
|
||||
.insert(MovedScene);
|
||||
}
|
||||
|
||||
// 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(
|
||||
mut commands: Commands,
|
||||
scene_spawner: Res<SceneSpawner>,
|
||||
scene_instance: Res<SceneInstance>,
|
||||
mut done: Local<bool>,
|
||||
// This system will move all entities that are descendants of MovedScene (which will be all entities spawned in the scene)
|
||||
fn move_scene_entities(
|
||||
time: Res<Time>,
|
||||
moved_scene: Query<Entity, With<MovedScene>>,
|
||||
children: Query<&Children>,
|
||||
mut transforms: Query<&mut Transform>,
|
||||
) {
|
||||
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.entity(entity).insert(EntityInMyScene);
|
||||
});
|
||||
*done = true;
|
||||
for moved_scene_entity in moved_scene.iter() {
|
||||
let mut offset = 0.;
|
||||
iter_hierarchy(moved_scene_entity, &children, &mut |entity| {
|
||||
if let Ok(mut transform) = transforms.get_mut(entity) {
|
||||
transform.translation = Vec3::new(
|
||||
offset * time.seconds_since_startup().sin() as f32 / 20.,
|
||||
0.,
|
||||
time.seconds_since_startup().cos() as f32 / 20.,
|
||||
);
|
||||
offset += 1.0;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn iter_hierarchy(entity: Entity, children_query: &Query<&Children>, f: &mut impl FnMut(Entity)) {
|
||||
(f)(entity);
|
||||
if let Ok(children) = children_query.get(entity) {
|
||||
for child in children.iter().copied() {
|
||||
iter_hierarchy(child, children_query, f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ struct Animations(Vec<Handle<AnimationClip>>);
|
|||
fn setup(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut scene_spawner: ResMut<SceneSpawner>,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
) {
|
||||
|
@ -61,7 +60,10 @@ fn setup(
|
|||
});
|
||||
|
||||
// Fox
|
||||
scene_spawner.spawn(asset_server.load("models/animated/Fox.glb#Scene0"));
|
||||
commands.spawn_bundle(SceneBundle {
|
||||
scene: asset_server.load("models/animated/Fox.glb#Scene0"),
|
||||
..default()
|
||||
});
|
||||
|
||||
println!("Animation controls:");
|
||||
println!(" - spacebar: play / pause");
|
||||
|
|
|
@ -25,7 +25,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
});
|
||||
|
||||
// Spawn the first scene in `models/SimpleSkin/SimpleSkin.gltf`
|
||||
commands.spawn_scene(asset_server.load::<Scene, _>("models/SimpleSkin/SimpleSkin.gltf#Scene0"));
|
||||
commands.spawn_bundle(SceneBundle {
|
||||
scene: asset_server.load("models/SimpleSkin/SimpleSkin.gltf#Scene0"),
|
||||
..default()
|
||||
});
|
||||
}
|
||||
|
||||
/// The scene hierarchy currently looks somewhat like this:
|
||||
|
|
|
@ -24,7 +24,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|||
// You should see the changes immediately show up in your app.
|
||||
|
||||
// mesh
|
||||
commands.spawn_scene(scene_handle);
|
||||
commands.spawn_bundle(SceneBundle {
|
||||
scene: scene_handle,
|
||||
..default()
|
||||
});
|
||||
// light
|
||||
commands.spawn_bundle(PointLightBundle {
|
||||
transform: Transform::from_xyz(4.0, 5.0, 4.0),
|
||||
|
|
|
@ -116,15 +116,11 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
(0..BOARD_SIZE_I)
|
||||
.map(|i| {
|
||||
let height = rand::thread_rng().gen_range(-0.1..0.1);
|
||||
commands
|
||||
.spawn_bundle(TransformBundle::from(Transform::from_xyz(
|
||||
i as f32,
|
||||
height - 0.2,
|
||||
j as f32,
|
||||
)))
|
||||
.with_children(|cell| {
|
||||
cell.spawn_scene(cell_scene.clone());
|
||||
});
|
||||
commands.spawn_bundle(SceneBundle {
|
||||
transform: Transform::from_xyz(i as f32, height - 0.2, j as f32),
|
||||
scene: cell_scene.clone(),
|
||||
..default()
|
||||
});
|
||||
Cell { height }
|
||||
})
|
||||
.collect()
|
||||
|
@ -134,17 +130,18 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut game: ResMu
|
|||
// spawn the game character
|
||||
game.player.entity = Some(
|
||||
commands
|
||||
.spawn_bundle(TransformBundle::from(Transform {
|
||||
translation: Vec3::new(
|
||||
game.player.i as f32,
|
||||
game.board[game.player.j][game.player.i].height,
|
||||
game.player.j as f32,
|
||||
),
|
||||
rotation: Quat::from_rotation_y(-std::f32::consts::FRAC_PI_2),
|
||||
.spawn_bundle(SceneBundle {
|
||||
transform: Transform {
|
||||
translation: Vec3::new(
|
||||
game.player.i as f32,
|
||||
game.board[game.player.j][game.player.i].height,
|
||||
game.player.j as f32,
|
||||
),
|
||||
rotation: Quat::from_rotation_y(-std::f32::consts::FRAC_PI_2),
|
||||
..default()
|
||||
},
|
||||
scene: asset_server.load("models/AlienCake/alien.glb#Scene0"),
|
||||
..default()
|
||||
}))
|
||||
.with_children(|cell| {
|
||||
cell.spawn_scene(asset_server.load("models/AlienCake/alien.glb#Scene0"));
|
||||
})
|
||||
.id(),
|
||||
);
|
||||
|
@ -322,11 +319,15 @@ fn spawn_bonus(
|
|||
}
|
||||
game.bonus.entity = Some(
|
||||
commands
|
||||
.spawn_bundle(TransformBundle::from(Transform::from_xyz(
|
||||
game.bonus.i as f32,
|
||||
game.board[game.bonus.j][game.bonus.i].height + 0.2,
|
||||
game.bonus.j as f32,
|
||||
)))
|
||||
.spawn_bundle(SceneBundle {
|
||||
transform: Transform::from_xyz(
|
||||
game.bonus.i as f32,
|
||||
game.board[game.bonus.j][game.bonus.i].height + 0.2,
|
||||
game.bonus.j as f32,
|
||||
),
|
||||
scene: game.bonus.handle.clone(),
|
||||
..default()
|
||||
})
|
||||
.with_children(|children| {
|
||||
children.spawn_bundle(PointLightBundle {
|
||||
point_light: PointLight {
|
||||
|
@ -338,7 +339,6 @@ fn spawn_bonus(
|
|||
transform: Transform::from_xyz(0.0, 2.0, 0.0),
|
||||
..default()
|
||||
});
|
||||
children.spawn_scene(game.bonus.handle.clone());
|
||||
})
|
||||
.id(),
|
||||
);
|
||||
|
|
|
@ -49,14 +49,14 @@ impl FromWorld for ComponentB {
|
|||
}
|
||||
}
|
||||
|
||||
fn load_scene_system(asset_server: Res<AssetServer>, mut scene_spawner: ResMut<SceneSpawner>) {
|
||||
// Scenes are loaded just like any other asset.
|
||||
let scene_handle: Handle<DynamicScene> = asset_server.load("scenes/load_scene_example.scn.ron");
|
||||
|
||||
// SceneSpawner can "spawn" scenes. "Spawning" a scene creates a new instance of the scene in
|
||||
// the World with new entity ids. This guarantees that it will not overwrite existing
|
||||
// entities.
|
||||
scene_spawner.spawn_dynamic(scene_handle);
|
||||
fn load_scene_system(mut commands: Commands, asset_server: Res<AssetServer>) {
|
||||
// "Spawning" a scene bundle creates a new entity and spawns new instances
|
||||
// of the given scene's entities as children of that entity.
|
||||
commands.spawn_bundle(DynamicSceneBundle {
|
||||
// Scenes are loaded just like any other asset.
|
||||
scene: asset_server.load("scenes/load_scene_example.scn.ron"),
|
||||
..default()
|
||||
});
|
||||
|
||||
// This tells the AssetServer to watch for changes to assets.
|
||||
// It enables our scenes to automatically reload in game when we modify their files
|
||||
|
|
|
@ -67,7 +67,6 @@ struct Ring {
|
|||
fn setup(
|
||||
mut commands: Commands,
|
||||
asset_server: Res<AssetServer>,
|
||||
mut scene_spawner: ResMut<SceneSpawner>,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<StandardMaterial>>,
|
||||
foxes: Res<Foxes>,
|
||||
|
@ -121,15 +120,13 @@ fn setup(
|
|||
let (x, z) = (radius * c, radius * s);
|
||||
|
||||
commands.entity(ring_parent).with_children(|builder| {
|
||||
let fox_parent = builder
|
||||
.spawn_bundle((
|
||||
Transform::from_xyz(x as f32, 0.0, z as f32)
|
||||
.with_scale(Vec3::splat(0.01))
|
||||
.with_rotation(base_rotation * Quat::from_rotation_y(-fox_angle)),
|
||||
GlobalTransform::default(),
|
||||
))
|
||||
.id();
|
||||
scene_spawner.spawn_as_child(fox_handle.clone(), fox_parent);
|
||||
builder.spawn_bundle(SceneBundle {
|
||||
scene: fox_handle.clone(),
|
||||
transform: Transform::from_xyz(x as f32, 0.0, z as f32)
|
||||
.with_scale(Vec3::splat(0.01))
|
||||
.with_rotation(base_rotation * Quat::from_rotation_y(-fox_angle)),
|
||||
..default()
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,10 @@ fn setup(
|
|||
mut create_window_events: EventWriter<CreateWindow>,
|
||||
) {
|
||||
// add entities to the world
|
||||
commands.spawn_scene(asset_server.load("models/monkey/Monkey.gltf#Scene0"));
|
||||
commands.spawn_bundle(SceneBundle {
|
||||
scene: asset_server.load("models/monkey/Monkey.gltf#Scene0"),
|
||||
..default()
|
||||
});
|
||||
// light
|
||||
commands.spawn_bundle(PointLightBundle {
|
||||
transform: Transform::from_xyz(4.0, 5.0, 4.0),
|
||||
|
|
Loading…
Reference in a new issue