 eb51b4c28e
			
		
	
	
		eb51b4c28e
		
			
		
	
	
	
	
		
			
			# Objective A step in the migration to required components: scenes! ## Solution As per the [selected proposal](https://hackmd.io/@bevy/required_components/%2FPJtNGVMMQhyM0zIvCJSkbA): - Deprecate `SceneBundle` and `DynamicSceneBundle`. - Add `SceneRoot` and `DynamicSceneRoot` components, which wrap a `Handle<Scene>` and `Handle<DynamicScene>` respectively. ## Migration Guide Asset handles for scenes and dynamic scenes must now be wrapped in the `SceneRoot` and `DynamicSceneRoot` components. Raw handles as components no longer spawn scenes. Additionally, `SceneBundle` and `DynamicSceneBundle` have been deprecated. Instead, use the scene components directly. Previously: ```rust let model_scene = asset_server.load(GltfAssetLabel::Scene(0).from_asset("model.gltf")); commands.spawn(SceneBundle { scene: model_scene, transform: Transform::from_xyz(-4.0, 0.0, -3.0), ..default() }); ``` Now: ```rust let model_scene = asset_server.load(GltfAssetLabel::Scene(0).from_asset("model.gltf")); commands.spawn(( SceneRoot(model_scene), Transform::from_xyz(-4.0, 0.0, -3.0), )); ```
		
			
				
	
	
		
			108 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			108 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| #![cfg_attr(docsrs, feature(doc_auto_cfg))]
 | |
| #![forbid(unsafe_code)]
 | |
| #![doc(
 | |
|     html_logo_url = "https://bevyengine.org/assets/icon.png",
 | |
|     html_favicon_url = "https://bevyengine.org/assets/icon.png"
 | |
| )]
 | |
| 
 | |
| //! Provides scene definition, instantiation and serialization/deserialization.
 | |
| //!
 | |
| //! Scenes are collections of entities and their associated components that can be
 | |
| //! instantiated or removed from a world to allow composition. Scenes can be serialized/deserialized,
 | |
| //! for example to save part of the world state to a file.
 | |
| 
 | |
| extern crate alloc;
 | |
| 
 | |
| mod bundle;
 | |
| mod components;
 | |
| mod dynamic_scene;
 | |
| mod dynamic_scene_builder;
 | |
| mod scene;
 | |
| mod scene_filter;
 | |
| mod scene_loader;
 | |
| mod scene_spawner;
 | |
| 
 | |
| #[cfg(feature = "serialize")]
 | |
| pub mod serde;
 | |
| 
 | |
| /// Rusty Object Notation, a crate used to serialize and deserialize bevy scenes.
 | |
| pub use bevy_asset::ron;
 | |
| 
 | |
| use bevy_ecs::schedule::IntoSystemConfigs;
 | |
| pub use bundle::*;
 | |
| pub use components::*;
 | |
| pub use dynamic_scene::*;
 | |
| pub use dynamic_scene_builder::*;
 | |
| pub use scene::*;
 | |
| pub use scene_filter::*;
 | |
| pub use scene_loader::*;
 | |
| pub use scene_spawner::*;
 | |
| 
 | |
| /// The scene prelude.
 | |
| ///
 | |
| /// This includes the most common types in this crate, re-exported for your convenience.
 | |
| #[expect(deprecated)]
 | |
| pub mod prelude {
 | |
|     #[doc(hidden)]
 | |
|     pub use crate::{
 | |
|         DynamicScene, DynamicSceneBuilder, DynamicSceneBundle, DynamicSceneRoot, Scene,
 | |
|         SceneBundle, SceneFilter, SceneRoot, SceneSpawner,
 | |
|     };
 | |
| }
 | |
| 
 | |
| use bevy_app::prelude::*;
 | |
| use bevy_asset::AssetApp;
 | |
| 
 | |
| /// Plugin that provides scene functionality to an [`App`].
 | |
| #[derive(Default)]
 | |
| pub struct ScenePlugin;
 | |
| 
 | |
| #[cfg(feature = "serialize")]
 | |
| impl Plugin for ScenePlugin {
 | |
|     fn build(&self, app: &mut App) {
 | |
|         app.init_asset::<DynamicScene>()
 | |
|             .init_asset::<Scene>()
 | |
|             .init_asset_loader::<SceneLoader>()
 | |
|             .init_resource::<SceneSpawner>()
 | |
|             .register_type::<SceneRoot>()
 | |
|             .register_type::<DynamicSceneRoot>()
 | |
|             .add_systems(SpawnScene, (scene_spawner, scene_spawner_system).chain());
 | |
| 
 | |
|         // Register component hooks for DynamicSceneRoot
 | |
|         app.world_mut()
 | |
|             .register_component_hooks::<DynamicSceneRoot>()
 | |
|             .on_remove(|mut world, entity, _| {
 | |
|                 let Some(handle) = world.get::<DynamicSceneRoot>(entity) else {
 | |
|                     return;
 | |
|                 };
 | |
|                 let id = handle.id();
 | |
|                 if let Some(&SceneInstance(scene_instance)) = world.get::<SceneInstance>(entity) {
 | |
|                     let Some(mut scene_spawner) = world.get_resource_mut::<SceneSpawner>() else {
 | |
|                         return;
 | |
|                     };
 | |
|                     if let Some(instance_ids) = scene_spawner.spawned_dynamic_scenes.get_mut(&id) {
 | |
|                         instance_ids.remove(&scene_instance);
 | |
|                     }
 | |
|                     scene_spawner.despawn_instance(scene_instance);
 | |
|                 }
 | |
|             });
 | |
| 
 | |
|         // Register component hooks for SceneRoot
 | |
|         app.world_mut()
 | |
|             .register_component_hooks::<SceneRoot>()
 | |
|             .on_remove(|mut world, entity, _| {
 | |
|                 if let Some(&SceneInstance(scene_instance)) = world.get::<SceneInstance>(entity) {
 | |
|                     let Some(mut scene_spawner) = world.get_resource_mut::<SceneSpawner>() else {
 | |
|                         return;
 | |
|                     };
 | |
|                     scene_spawner.despawn_instance(scene_instance);
 | |
|                 }
 | |
|             });
 | |
|     }
 | |
| }
 | |
| 
 | |
| #[cfg(not(feature = "serialize"))]
 | |
| impl Plugin for ScenePlugin {
 | |
|     fn build(&self, _: &mut App) {}
 | |
| }
 |