mirror of
https://github.com/bevyengine/bevy.git
synced 2026-05-06 06:06:42 -04:00
BSN: scene.spawn() system ergonomics (#23868)
# Objective
Spawning a scene on startup is a common pattern. Lets make it easier to
do so!
## Solution
- Add `SpawnSystem` and `SpawnListSystem` traits that are implemented
for functions that return scenes / scene lists, and return a system that
spawns the scene / handles errors.
### Before
```rust
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, setup)
.run();
}
fn setup(world: &mut World) -> Result {
world.spawn_scene_list(bsn_list![Camera2d, ui()])?;
Ok(())
}
```
### After
```rust
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, scene.spawn())
.run();
}
fn scene() -> impl SceneList {
bsn_list![Camera2d, ui()]
}
```
This cuts out some boilerplate. It also further encourages people to
define standalone "scene functions" rather than embedding them in code,
which is generally a good pattern.
This commit is contained in:
@@ -509,7 +509,7 @@ pub mod prelude {
|
||||
pub use crate::{
|
||||
bsn, bsn_list, on, template_value, CommandsSceneExt, EntityCommandsSceneExt,
|
||||
EntityWorldMutSceneExt, PatchFromTemplate, PatchTemplate, Scene, SceneList,
|
||||
ScenePatchInstance, WorldSceneExt,
|
||||
ScenePatchInstance, SpawnListSystem, SpawnSystem, WorldSceneExt,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -523,6 +523,7 @@ mod scene;
|
||||
mod scene_list;
|
||||
mod scene_patch;
|
||||
mod spawn;
|
||||
mod spawn_system;
|
||||
|
||||
pub use bevy_scene_macros::*;
|
||||
pub use resolved_scene::*;
|
||||
@@ -530,6 +531,7 @@ pub use scene::*;
|
||||
pub use scene_list::*;
|
||||
pub use scene_patch::*;
|
||||
pub use spawn::*;
|
||||
pub use spawn_system::*;
|
||||
|
||||
use bevy_app::{App, Plugin, SceneSpawnerSystems, SpawnScene};
|
||||
use bevy_asset::AssetApp;
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use crate::{Scene, SceneList, WorldSceneExt};
|
||||
use bevy_ecs::{error::Result, world::World};
|
||||
|
||||
/// Returns a system that spawns the given [`Scene`]. This should generally only be added to
|
||||
/// schedules that run once, such as [`Startup`](bevy_app::Startup).
|
||||
pub trait SpawnSystem {
|
||||
/// Returns a system that spawns the given [`Scene`]. This should generally only be added to
|
||||
/// schedules that run once, such as [`Startup`](bevy_app::Startup).
|
||||
fn spawn(self) -> impl FnMut(&mut World) -> Result;
|
||||
}
|
||||
|
||||
impl<F: FnMut() -> S + Send + Sync + 'static, S: Scene> SpawnSystem for F {
|
||||
fn spawn(mut self) -> impl FnMut(&mut World) -> Result {
|
||||
move |world: &mut World| -> Result {
|
||||
world.spawn_scene(self())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a system that spawns the given [`SceneList`]. This should generally only be added to
|
||||
/// schedules that run once, such as [`Startup`](bevy_app::Startup).
|
||||
pub trait SpawnListSystem {
|
||||
/// Returns a system that spawns the given [`SceneList`]. This should generally only be added to
|
||||
/// schedules that run once, such as [`Startup`](bevy_app::Startup).
|
||||
fn spawn(self) -> impl FnMut(&mut World) -> Result;
|
||||
}
|
||||
impl<F: FnMut() -> S + Send + Sync + 'static, S: SceneList> SpawnListSystem for F {
|
||||
fn spawn(mut self) -> impl FnMut(&mut World) -> Result {
|
||||
move |world: &mut World| -> Result {
|
||||
world.spawn_scene_list(self())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,12 @@ use bevy::{prelude::*, text::FontSourceTemplate};
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Startup, scene.spawn())
|
||||
.run();
|
||||
}
|
||||
|
||||
fn setup(world: &mut World) -> Result {
|
||||
world.spawn_scene_list(bsn_list![Camera2d, ui()])?;
|
||||
Ok(())
|
||||
fn scene() -> impl SceneList {
|
||||
bsn_list![Camera2d, ui()]
|
||||
}
|
||||
|
||||
fn ui() -> impl Scene {
|
||||
|
||||
@@ -10,7 +10,6 @@ use bevy::{
|
||||
tokens, FeathersPlugins,
|
||||
},
|
||||
prelude::*,
|
||||
scene::prelude::Scene,
|
||||
ui_widgets::Activate,
|
||||
};
|
||||
|
||||
@@ -31,7 +30,7 @@ fn main() {
|
||||
// Configure feathers to use the dark theme
|
||||
.insert_resource(UiTheme(create_dark_theme()))
|
||||
.insert_resource(Counter(0))
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Startup, scene.spawn())
|
||||
.add_systems(
|
||||
Update,
|
||||
update_counter_text.run_if(resource_changed::<Counter>),
|
||||
@@ -39,9 +38,8 @@ fn main() {
|
||||
.run();
|
||||
}
|
||||
|
||||
fn setup(world: &mut World) -> Result {
|
||||
world.spawn_scene_list(bsn_list![Camera2d, demo_root()])?;
|
||||
Ok(())
|
||||
fn scene() -> impl SceneList {
|
||||
bsn_list![Camera2d, demo_root()]
|
||||
}
|
||||
|
||||
fn demo_root() -> impl Scene {
|
||||
|
||||
@@ -26,7 +26,6 @@ use bevy::{
|
||||
},
|
||||
input_focus::{tab_navigation::TabGroup, AutoFocus, InputFocus},
|
||||
prelude::*,
|
||||
scene::prelude::Scene,
|
||||
text::{EditableText, TextEdit, TextEditChange},
|
||||
ui::{Checked, InteractionDisabled},
|
||||
ui_widgets::{
|
||||
@@ -64,14 +63,13 @@ fn main() {
|
||||
rgb_color: palettes::tailwind::EMERALD_800.with_alpha(0.7),
|
||||
hsl_color: palettes::tailwind::AMBER_800.into(),
|
||||
})
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Startup, scene.spawn())
|
||||
.add_systems(Update, update_colors)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn setup(world: &mut World) -> Result {
|
||||
world.spawn_scene_list(bsn_list![Camera2d, demo_root()])?;
|
||||
Ok(())
|
||||
fn scene() -> impl SceneList {
|
||||
bsn_list![Camera2d, demo_root()]
|
||||
}
|
||||
|
||||
fn demo_root() -> impl Scene {
|
||||
|
||||
@@ -15,7 +15,7 @@ fn main() {
|
||||
App::new()
|
||||
.add_plugins((DefaultPlugins, FeathersPlugins))
|
||||
.insert_resource(UiTheme(create_dark_theme()))
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Startup, scene.spawn())
|
||||
.run();
|
||||
}
|
||||
|
||||
@@ -23,9 +23,8 @@ fn on_virtual_key_pressed(virtual_key_pressed: On<VirtualKeyPressed<&'static str
|
||||
println!("key pressed: {}", virtual_key_pressed.key);
|
||||
}
|
||||
|
||||
fn setup(world: &mut World) -> Result {
|
||||
world.spawn_scene_list(bsn_list![Camera2d, keyboard()])?;
|
||||
Ok(())
|
||||
fn scene() -> impl SceneList {
|
||||
bsn_list![Camera2d, keyboard()]
|
||||
}
|
||||
|
||||
fn keyboard() -> impl Scene {
|
||||
|
||||
Reference in New Issue
Block a user