2022-05-16 13:53:20 +00:00
|
|
|
//! This example will display a simple menu using Bevy UI where you can start a new game,
|
|
|
|
//! change some settings or quit. There is no actual game, it will just display the current
|
|
|
|
//! settings for 5 seconds before going back to the menu.
|
2022-01-14 19:09:42 +00:00
|
|
|
|
2022-05-16 13:53:20 +00:00
|
|
|
use bevy::prelude::*;
|
2022-01-14 19:09:42 +00:00
|
|
|
|
|
|
|
const TEXT_COLOR: Color = Color::rgb(0.9, 0.9, 0.9);
|
|
|
|
|
|
|
|
// Enum that will be used as a global state for the game
|
|
|
|
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
|
|
|
|
enum GameState {
|
|
|
|
Splash,
|
|
|
|
Menu,
|
|
|
|
Game,
|
|
|
|
}
|
|
|
|
|
|
|
|
// One of the two settings that can be set through the menu. It will be a resource in the app
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
#[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)]
|
2022-01-14 19:09:42 +00:00
|
|
|
enum DisplayQuality {
|
|
|
|
Low,
|
|
|
|
Medium,
|
|
|
|
High,
|
|
|
|
}
|
|
|
|
|
|
|
|
// One of the two settings that can be set through the menu. It will be a resource in the app
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
#[derive(Resource, Debug, Component, PartialEq, Eq, Clone, Copy)]
|
2022-01-14 19:09:42 +00:00
|
|
|
struct Volume(u32);
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
App::new()
|
|
|
|
.add_plugins(DefaultPlugins)
|
|
|
|
// Insert as resource the initial value for the settings resources
|
|
|
|
.insert_resource(DisplayQuality::Medium)
|
|
|
|
.insert_resource(Volume(7))
|
|
|
|
.add_startup_system(setup)
|
|
|
|
// Declare the game state, and set its startup value
|
|
|
|
.add_state(GameState::Splash)
|
|
|
|
// Adds the plugins for each state
|
|
|
|
.add_plugin(splash::SplashPlugin)
|
|
|
|
.add_plugin(menu::MenuPlugin)
|
|
|
|
.add_plugin(game::GamePlugin)
|
|
|
|
.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
fn setup(mut commands: Commands) {
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
commands.spawn(Camera2dBundle::default());
|
2022-01-14 19:09:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mod splash {
|
|
|
|
use bevy::prelude::*;
|
|
|
|
|
|
|
|
use super::{despawn_screen, GameState};
|
|
|
|
|
|
|
|
// This plugin will display a splash screen with Bevy logo for 1 second before switching to the menu
|
|
|
|
pub struct SplashPlugin;
|
|
|
|
|
|
|
|
impl Plugin for SplashPlugin {
|
2022-01-16 20:49:40 +00:00
|
|
|
fn build(&self, app: &mut App) {
|
2022-01-14 19:09:42 +00:00
|
|
|
// As this plugin is managing the splash screen, it will focus on the state `GameState::Splash`
|
|
|
|
app
|
|
|
|
// When entering the state, spawn everything needed for this screen
|
|
|
|
.add_system_set(SystemSet::on_enter(GameState::Splash).with_system(splash_setup))
|
|
|
|
// While in this state, run the `countdown` system
|
|
|
|
.add_system_set(SystemSet::on_update(GameState::Splash).with_system(countdown))
|
|
|
|
// When exiting the state, despawn everything that was spawned for this screen
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_exit(GameState::Splash)
|
|
|
|
.with_system(despawn_screen::<OnSplashScreen>),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tag component used to tag entities added on the splash screen
|
|
|
|
#[derive(Component)]
|
|
|
|
struct OnSplashScreen;
|
|
|
|
|
|
|
|
// Newtype to use a `Timer` for this screen as a resource
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
#[derive(Resource, Deref, DerefMut)]
|
2022-01-14 19:09:42 +00:00
|
|
|
struct SplashTimer(Timer);
|
|
|
|
|
|
|
|
fn splash_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
|
|
let icon = asset_server.load("branding/icon.png");
|
|
|
|
// Display the logo
|
2022-11-21 14:38:35 +00:00
|
|
|
commands
|
|
|
|
.spawn((
|
|
|
|
NodeBundle {
|
|
|
|
style: Style {
|
|
|
|
align_items: AlignItems::Center,
|
|
|
|
justify_content: JustifyContent::Center,
|
|
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
|
|
|
..default()
|
|
|
|
},
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
2022-11-21 14:38:35 +00:00
|
|
|
OnSplashScreen,
|
|
|
|
))
|
|
|
|
.with_children(|parent| {
|
|
|
|
parent.spawn(ImageBundle {
|
|
|
|
style: Style {
|
|
|
|
// This will set the logo to be 200px wide, and auto adjust its height
|
|
|
|
size: Size::new(Val::Px(200.0), Val::Auto),
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
image: UiImage::new(icon),
|
|
|
|
..default()
|
|
|
|
});
|
|
|
|
});
|
2022-01-14 19:09:42 +00:00
|
|
|
// Insert the timer as a resource
|
Replace the `bool` argument of `Timer` with `TimerMode` (#6247)
As mentioned in #2926, it's better to have an explicit type that clearly communicates the intent of the timer mode rather than an opaque boolean, which can be only understood when knowing the signature or having to look up the documentation.
This also opens up a way to merge different timers, such as `Stopwatch`, and possibly future ones, such as `DiscreteStopwatch` and `DiscreteTimer` from #2683, into one struct.
Signed-off-by: Lena Milizé <me@lvmn.org>
# Objective
Fixes #2926.
## Solution
Introduce `TimerMode` which replaces the `bool` argument of `Timer` constructors. A `Default` value for `TimerMode` is `Once`.
---
## Changelog
### Added
- `TimerMode` enum, along with variants `TimerMode::Once` and `TimerMode::Repeating`
### Changed
- Replace `bool` argument of `Timer::new` and `Timer::from_seconds` with `TimerMode`
- Change `repeating: bool` field of `Timer` with `mode: TimerMode`
## Migration Guide
- Replace `Timer::new(duration, false)` with `Timer::new(duration, TimerMode::Once)`.
- Replace `Timer::new(duration, true)` with `Timer::new(duration, TimerMode::Repeating)`.
- Replace `Timer::from_seconds(seconds, false)` with `Timer::from_seconds(seconds, TimerMode::Once)`.
- Replace `Timer::from_seconds(seconds, true)` with `Timer::from_seconds(seconds, TimerMode::Repeating)`.
- Change `timer.repeating()` to `timer.mode() == TimerMode::Repeating`.
2022-10-17 13:47:01 +00:00
|
|
|
commands.insert_resource(SplashTimer(Timer::from_seconds(1.0, TimerMode::Once)));
|
2022-01-14 19:09:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tick the timer, and change state when finished
|
|
|
|
fn countdown(
|
|
|
|
mut game_state: ResMut<State<GameState>>,
|
|
|
|
time: Res<Time>,
|
|
|
|
mut timer: ResMut<SplashTimer>,
|
|
|
|
) {
|
bevy_derive: Add derives for `Deref` and `DerefMut` (#4328)
# Objective
A common pattern in Rust is the [newtype](https://doc.rust-lang.org/rust-by-example/generics/new_types.html). This is an especially useful pattern in Bevy as it allows us to give common/foreign types different semantics (such as allowing it to implement `Component` or `FromWorld`) or to simply treat them as a "new type" (clever). For example, it allows us to wrap a common `Vec<String>` and do things like:
```rust
#[derive(Component)]
struct Items(Vec<String>);
fn give_sword(query: Query<&mut Items>) {
query.single_mut().0.push(String::from("Flaming Poisoning Raging Sword of Doom"));
}
```
> We could then define another struct that wraps `Vec<String>` without anything clashing in the query.
However, one of the worst parts of this pattern is the ugly `.0` we have to write in order to access the type we actually care about. This is why people often implement `Deref` and `DerefMut` in order to get around this.
Since it's such a common pattern, especially for Bevy, it makes sense to add a derive macro to automatically add those implementations.
## Solution
Added a derive macro for `Deref` and another for `DerefMut` (both exported into the prelude). This works on all structs (including tuple structs) as long as they only contain a single field:
```rust
#[derive(Deref)]
struct Foo(String);
#[derive(Deref, DerefMut)]
struct Bar {
name: String,
}
```
This allows us to then remove that pesky `.0`:
```rust
#[derive(Component, Deref, DerefMut)]
struct Items(Vec<String>);
fn give_sword(query: Query<&mut Items>) {
query.single_mut().push(String::from("Flaming Poisoning Raging Sword of Doom"));
}
```
### Alternatives
There are other alternatives to this such as by using the [`derive_more`](https://crates.io/crates/derive_more) crate. However, it doesn't seem like we need an entire crate just yet since we only need `Deref` and `DerefMut` (for now).
### Considerations
One thing to consider is that the Rust std library recommends _not_ using `Deref` and `DerefMut` for things like this: "`Deref` should only be implemented for smart pointers to avoid confusion" ([reference](https://doc.rust-lang.org/std/ops/trait.Deref.html)). Personally, I believe it makes sense to use it in the way described above, but others may disagree.
### Additional Context
Discord: https://discord.com/channels/691052431525675048/692572690833473578/956648422163746827 (controversiality discussed [here](https://discord.com/channels/691052431525675048/692572690833473578/956711911481835630))
---
## Changelog
- Add `Deref` derive macro (exported to prelude)
- Add `DerefMut` derive macro (exported to prelude)
- Updated most newtypes in examples to use one or both derives
Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-03-29 02:10:06 +00:00
|
|
|
if timer.tick(time.delta()).finished() {
|
2022-01-14 19:09:42 +00:00
|
|
|
game_state.set(GameState::Menu).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mod game {
|
|
|
|
use bevy::prelude::*;
|
|
|
|
|
|
|
|
use super::{despawn_screen, DisplayQuality, GameState, Volume, TEXT_COLOR};
|
|
|
|
|
|
|
|
// This plugin will contain the game. In this case, it's just be a screen that will
|
|
|
|
// display the current settings for 5 seconds before returning to the menu
|
|
|
|
pub struct GamePlugin;
|
|
|
|
|
|
|
|
impl Plugin for GamePlugin {
|
|
|
|
fn build(&self, app: &mut App) {
|
|
|
|
app.add_system_set(SystemSet::on_enter(GameState::Game).with_system(game_setup))
|
|
|
|
.add_system_set(SystemSet::on_update(GameState::Game).with_system(game))
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_exit(GameState::Game).with_system(despawn_screen::<OnGameScreen>),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tag component used to tag entities added on the game screen
|
|
|
|
#[derive(Component)]
|
|
|
|
struct OnGameScreen;
|
|
|
|
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
#[derive(Resource, Deref, DerefMut)]
|
2022-01-14 19:09:42 +00:00
|
|
|
struct GameTimer(Timer);
|
|
|
|
|
|
|
|
fn game_setup(
|
|
|
|
mut commands: Commands,
|
|
|
|
asset_server: Res<AssetServer>,
|
|
|
|
display_quality: Res<DisplayQuality>,
|
|
|
|
volume: Res<Volume>,
|
|
|
|
) {
|
|
|
|
let font = asset_server.load("fonts/FiraSans-Bold.ttf");
|
|
|
|
|
|
|
|
commands
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
.spawn((
|
|
|
|
NodeBundle {
|
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
|
|
|
// center children
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
align_items: AlignItems::Center,
|
2022-11-21 14:38:35 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
..default()
|
|
|
|
},
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
OnGameScreen,
|
|
|
|
))
|
2022-01-14 19:09:42 +00:00
|
|
|
.with_children(|parent| {
|
2022-11-21 14:38:35 +00:00
|
|
|
// First create a `NodeBundle` for centering what we want to display
|
|
|
|
parent
|
|
|
|
.spawn(NodeBundle {
|
|
|
|
style: Style {
|
|
|
|
// This will display its children in a column, from top to bottom
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
// `align_items` will align children on the cross axis. Here the main axis is
|
|
|
|
// vertical (column), so the cross axis is horizontal. This will center the
|
|
|
|
// children
|
|
|
|
align_items: AlignItems::Center,
|
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
2022-11-21 14:38:35 +00:00
|
|
|
background_color: Color::BLACK.into(),
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-11-21 14:38:35 +00:00
|
|
|
})
|
|
|
|
.with_children(|parent| {
|
|
|
|
// Display two lines of text, the second one with the current settings
|
|
|
|
parent.spawn(
|
|
|
|
TextBundle::from_section(
|
|
|
|
"Will be back to the menu shortly...",
|
|
|
|
TextStyle {
|
|
|
|
font: font.clone(),
|
|
|
|
font_size: 80.0,
|
|
|
|
color: TEXT_COLOR,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.with_style(Style {
|
|
|
|
margin: UiRect::all(Val::Px(50.0)),
|
|
|
|
..default()
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
parent.spawn(
|
|
|
|
TextBundle::from_sections([
|
|
|
|
TextSection::new(
|
|
|
|
format!("quality: {:?}", *display_quality),
|
|
|
|
TextStyle {
|
|
|
|
font: font.clone(),
|
|
|
|
font_size: 60.0,
|
|
|
|
color: Color::BLUE,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
TextSection::new(
|
|
|
|
" - ",
|
|
|
|
TextStyle {
|
|
|
|
font: font.clone(),
|
|
|
|
font_size: 60.0,
|
|
|
|
color: TEXT_COLOR,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
TextSection::new(
|
|
|
|
format!("volume: {:?}", *volume),
|
|
|
|
TextStyle {
|
|
|
|
font: font.clone(),
|
|
|
|
font_size: 60.0,
|
|
|
|
color: Color::GREEN,
|
|
|
|
},
|
|
|
|
),
|
|
|
|
])
|
|
|
|
.with_style(Style {
|
|
|
|
margin: UiRect::all(Val::Px(50.0)),
|
|
|
|
..default()
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
});
|
2022-01-14 19:09:42 +00:00
|
|
|
});
|
|
|
|
// Spawn a 5 seconds timer to trigger going back to the menu
|
Replace the `bool` argument of `Timer` with `TimerMode` (#6247)
As mentioned in #2926, it's better to have an explicit type that clearly communicates the intent of the timer mode rather than an opaque boolean, which can be only understood when knowing the signature or having to look up the documentation.
This also opens up a way to merge different timers, such as `Stopwatch`, and possibly future ones, such as `DiscreteStopwatch` and `DiscreteTimer` from #2683, into one struct.
Signed-off-by: Lena Milizé <me@lvmn.org>
# Objective
Fixes #2926.
## Solution
Introduce `TimerMode` which replaces the `bool` argument of `Timer` constructors. A `Default` value for `TimerMode` is `Once`.
---
## Changelog
### Added
- `TimerMode` enum, along with variants `TimerMode::Once` and `TimerMode::Repeating`
### Changed
- Replace `bool` argument of `Timer::new` and `Timer::from_seconds` with `TimerMode`
- Change `repeating: bool` field of `Timer` with `mode: TimerMode`
## Migration Guide
- Replace `Timer::new(duration, false)` with `Timer::new(duration, TimerMode::Once)`.
- Replace `Timer::new(duration, true)` with `Timer::new(duration, TimerMode::Repeating)`.
- Replace `Timer::from_seconds(seconds, false)` with `Timer::from_seconds(seconds, TimerMode::Once)`.
- Replace `Timer::from_seconds(seconds, true)` with `Timer::from_seconds(seconds, TimerMode::Repeating)`.
- Change `timer.repeating()` to `timer.mode() == TimerMode::Repeating`.
2022-10-17 13:47:01 +00:00
|
|
|
commands.insert_resource(GameTimer(Timer::from_seconds(5.0, TimerMode::Once)));
|
2022-01-14 19:09:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Tick the timer, and change state when finished
|
|
|
|
fn game(
|
|
|
|
time: Res<Time>,
|
|
|
|
mut game_state: ResMut<State<GameState>>,
|
|
|
|
mut timer: ResMut<GameTimer>,
|
|
|
|
) {
|
bevy_derive: Add derives for `Deref` and `DerefMut` (#4328)
# Objective
A common pattern in Rust is the [newtype](https://doc.rust-lang.org/rust-by-example/generics/new_types.html). This is an especially useful pattern in Bevy as it allows us to give common/foreign types different semantics (such as allowing it to implement `Component` or `FromWorld`) or to simply treat them as a "new type" (clever). For example, it allows us to wrap a common `Vec<String>` and do things like:
```rust
#[derive(Component)]
struct Items(Vec<String>);
fn give_sword(query: Query<&mut Items>) {
query.single_mut().0.push(String::from("Flaming Poisoning Raging Sword of Doom"));
}
```
> We could then define another struct that wraps `Vec<String>` without anything clashing in the query.
However, one of the worst parts of this pattern is the ugly `.0` we have to write in order to access the type we actually care about. This is why people often implement `Deref` and `DerefMut` in order to get around this.
Since it's such a common pattern, especially for Bevy, it makes sense to add a derive macro to automatically add those implementations.
## Solution
Added a derive macro for `Deref` and another for `DerefMut` (both exported into the prelude). This works on all structs (including tuple structs) as long as they only contain a single field:
```rust
#[derive(Deref)]
struct Foo(String);
#[derive(Deref, DerefMut)]
struct Bar {
name: String,
}
```
This allows us to then remove that pesky `.0`:
```rust
#[derive(Component, Deref, DerefMut)]
struct Items(Vec<String>);
fn give_sword(query: Query<&mut Items>) {
query.single_mut().push(String::from("Flaming Poisoning Raging Sword of Doom"));
}
```
### Alternatives
There are other alternatives to this such as by using the [`derive_more`](https://crates.io/crates/derive_more) crate. However, it doesn't seem like we need an entire crate just yet since we only need `Deref` and `DerefMut` (for now).
### Considerations
One thing to consider is that the Rust std library recommends _not_ using `Deref` and `DerefMut` for things like this: "`Deref` should only be implemented for smart pointers to avoid confusion" ([reference](https://doc.rust-lang.org/std/ops/trait.Deref.html)). Personally, I believe it makes sense to use it in the way described above, but others may disagree.
### Additional Context
Discord: https://discord.com/channels/691052431525675048/692572690833473578/956648422163746827 (controversiality discussed [here](https://discord.com/channels/691052431525675048/692572690833473578/956711911481835630))
---
## Changelog
- Add `Deref` derive macro (exported to prelude)
- Add `DerefMut` derive macro (exported to prelude)
- Updated most newtypes in examples to use one or both derives
Co-authored-by: MrGVSV <49806985+MrGVSV@users.noreply.github.com>
2022-03-29 02:10:06 +00:00
|
|
|
if timer.tick(time.delta()).finished() {
|
2022-01-14 19:09:42 +00:00
|
|
|
game_state.set(GameState::Menu).unwrap();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mod menu {
|
|
|
|
use bevy::{app::AppExit, prelude::*};
|
|
|
|
|
|
|
|
use super::{despawn_screen, DisplayQuality, GameState, Volume, TEXT_COLOR};
|
|
|
|
|
|
|
|
// This plugin manages the menu, with 5 different screens:
|
|
|
|
// - a main menu with "New Game", "Settings", "Quit"
|
|
|
|
// - a settings menu with two submenus and a back button
|
|
|
|
// - two settings screen with a setting that can be set and a back button
|
|
|
|
pub struct MenuPlugin;
|
|
|
|
|
|
|
|
impl Plugin for MenuPlugin {
|
2022-01-16 20:49:40 +00:00
|
|
|
fn build(&self, app: &mut App) {
|
2022-01-14 19:09:42 +00:00
|
|
|
app
|
|
|
|
// At start, the menu is not enabled. This will be changed in `menu_setup` when
|
|
|
|
// entering the `GameState::Menu` state.
|
|
|
|
// Current screen in the menu is handled by an independent state from `GameState`
|
|
|
|
.add_state(MenuState::Disabled)
|
|
|
|
.add_system_set(SystemSet::on_enter(GameState::Menu).with_system(menu_setup))
|
|
|
|
// Systems to handle the main menu screen
|
|
|
|
.add_system_set(SystemSet::on_enter(MenuState::Main).with_system(main_menu_setup))
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_exit(MenuState::Main)
|
|
|
|
.with_system(despawn_screen::<OnMainMenuScreen>),
|
|
|
|
)
|
|
|
|
// Systems to handle the settings menu screen
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_enter(MenuState::Settings).with_system(settings_menu_setup),
|
|
|
|
)
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_exit(MenuState::Settings)
|
|
|
|
.with_system(despawn_screen::<OnSettingsMenuScreen>),
|
|
|
|
)
|
|
|
|
// Systems to handle the display settings screen
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_enter(MenuState::SettingsDisplay)
|
|
|
|
.with_system(display_settings_menu_setup),
|
|
|
|
)
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_update(MenuState::SettingsDisplay)
|
|
|
|
.with_system(setting_button::<DisplayQuality>),
|
|
|
|
)
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_exit(MenuState::SettingsDisplay)
|
|
|
|
.with_system(despawn_screen::<OnDisplaySettingsMenuScreen>),
|
|
|
|
)
|
|
|
|
// Systems to handle the sound settings screen
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_enter(MenuState::SettingsSound)
|
|
|
|
.with_system(sound_settings_menu_setup),
|
|
|
|
)
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_update(MenuState::SettingsSound)
|
|
|
|
.with_system(setting_button::<Volume>),
|
|
|
|
)
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_exit(MenuState::SettingsSound)
|
|
|
|
.with_system(despawn_screen::<OnSoundSettingsMenuScreen>),
|
|
|
|
)
|
|
|
|
// Common systems to all screens that handles buttons behaviour
|
|
|
|
.add_system_set(
|
|
|
|
SystemSet::on_update(GameState::Menu)
|
|
|
|
.with_system(menu_action)
|
|
|
|
.with_system(button_system),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// State used for the current menu screen
|
|
|
|
#[derive(Clone, Eq, PartialEq, Debug, Hash)]
|
|
|
|
enum MenuState {
|
|
|
|
Main,
|
|
|
|
Settings,
|
|
|
|
SettingsDisplay,
|
|
|
|
SettingsSound,
|
|
|
|
Disabled,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Tag component used to tag entities added on the main menu screen
|
|
|
|
#[derive(Component)]
|
|
|
|
struct OnMainMenuScreen;
|
|
|
|
|
|
|
|
// Tag component used to tag entities added on the settings menu screen
|
|
|
|
#[derive(Component)]
|
|
|
|
struct OnSettingsMenuScreen;
|
|
|
|
|
|
|
|
// Tag component used to tag entities added on the display settings menu screen
|
|
|
|
#[derive(Component)]
|
|
|
|
struct OnDisplaySettingsMenuScreen;
|
|
|
|
|
|
|
|
// Tag component used to tag entities added on the sound settings menu screen
|
|
|
|
#[derive(Component)]
|
|
|
|
struct OnSoundSettingsMenuScreen;
|
|
|
|
|
|
|
|
const NORMAL_BUTTON: Color = Color::rgb(0.15, 0.15, 0.15);
|
|
|
|
const HOVERED_BUTTON: Color = Color::rgb(0.25, 0.25, 0.25);
|
|
|
|
const HOVERED_PRESSED_BUTTON: Color = Color::rgb(0.25, 0.65, 0.25);
|
|
|
|
const PRESSED_BUTTON: Color = Color::rgb(0.35, 0.75, 0.35);
|
|
|
|
|
|
|
|
// Tag component used to mark wich setting is currently selected
|
|
|
|
#[derive(Component)]
|
|
|
|
struct SelectedOption;
|
|
|
|
|
|
|
|
// All actions that can be triggered from a button click
|
|
|
|
#[derive(Component)]
|
|
|
|
enum MenuButtonAction {
|
|
|
|
Play,
|
|
|
|
Settings,
|
|
|
|
SettingsDisplay,
|
|
|
|
SettingsSound,
|
|
|
|
BackToMainMenu,
|
|
|
|
BackToSettings,
|
|
|
|
Quit,
|
|
|
|
}
|
|
|
|
|
|
|
|
// This system handles changing all buttons color based on mouse interaction
|
|
|
|
fn button_system(
|
|
|
|
mut interaction_query: Query<
|
2022-09-25 00:39:17 +00:00
|
|
|
(&Interaction, &mut BackgroundColor, Option<&SelectedOption>),
|
2022-01-14 19:09:42 +00:00
|
|
|
(Changed<Interaction>, With<Button>),
|
|
|
|
>,
|
|
|
|
) {
|
2022-07-11 15:28:50 +00:00
|
|
|
for (interaction, mut color, selected) in &mut interaction_query {
|
2022-01-14 19:09:42 +00:00
|
|
|
*color = match (*interaction, selected) {
|
2022-05-31 01:38:07 +00:00
|
|
|
(Interaction::Clicked, _) | (Interaction::None, Some(_)) => PRESSED_BUTTON.into(),
|
2022-01-14 19:09:42 +00:00
|
|
|
(Interaction::Hovered, Some(_)) => HOVERED_PRESSED_BUTTON.into(),
|
|
|
|
(Interaction::Hovered, None) => HOVERED_BUTTON.into(),
|
|
|
|
(Interaction::None, None) => NORMAL_BUTTON.into(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// This system updates the settings when a new value for a setting is selected, and marks
|
|
|
|
// the button as the one currently selected
|
Make `Resource` trait opt-in, requiring `#[derive(Resource)]` V2 (#5577)
*This PR description is an edited copy of #5007, written by @alice-i-cecile.*
# Objective
Follow-up to https://github.com/bevyengine/bevy/pull/2254. The `Resource` trait currently has a blanket implementation for all types that meet its bounds.
While ergonomic, this results in several drawbacks:
* it is possible to make confusing, silent mistakes such as inserting a function pointer (Foo) rather than a value (Foo::Bar) as a resource
* it is challenging to discover if a type is intended to be used as a resource
* we cannot later add customization options (see the [RFC](https://github.com/bevyengine/rfcs/blob/main/rfcs/27-derive-component.md) for the equivalent choice for Component).
* dependencies can use the same Rust type as a resource in invisibly conflicting ways
* raw Rust types used as resources cannot preserve privacy appropriately, as anyone able to access that type can read and write to internal values
* we cannot capture a definitive list of possible resources to display to users in an editor
## Notes to reviewers
* Review this commit-by-commit; there's effectively no back-tracking and there's a lot of churn in some of these commits.
*ira: My commits are not as well organized :')*
* I've relaxed the bound on Local to Send + Sync + 'static: I don't think these concerns apply there, so this can keep things simple. Storing e.g. a u32 in a Local is fine, because there's a variable name attached explaining what it does.
* I think this is a bad place for the Resource trait to live, but I've left it in place to make reviewing easier. IMO that's best tackled with https://github.com/bevyengine/bevy/issues/4981.
## Changelog
`Resource` is no longer automatically implemented for all matching types. Instead, use the new `#[derive(Resource)]` macro.
## Migration Guide
Add `#[derive(Resource)]` to all types you are using as a resource.
If you are using a third party type as a resource, wrap it in a tuple struct to bypass orphan rules. Consider deriving `Deref` and `DerefMut` to improve ergonomics.
`ClearColor` no longer implements `Component`. Using `ClearColor` as a component in 0.8 did nothing.
Use the `ClearColorConfig` in the `Camera3d` and `Camera2d` components instead.
Co-authored-by: Alice <alice.i.cecile@gmail.com>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
Co-authored-by: devil-ira <justthecooldude@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
2022-08-08 21:36:35 +00:00
|
|
|
fn setting_button<T: Resource + Component + PartialEq + Copy>(
|
2022-01-14 19:09:42 +00:00
|
|
|
interaction_query: Query<(&Interaction, &T, Entity), (Changed<Interaction>, With<Button>)>,
|
2022-09-25 00:39:17 +00:00
|
|
|
mut selected_query: Query<(Entity, &mut BackgroundColor), With<SelectedOption>>,
|
2022-01-14 19:09:42 +00:00
|
|
|
mut commands: Commands,
|
|
|
|
mut setting: ResMut<T>,
|
|
|
|
) {
|
2022-07-11 15:28:50 +00:00
|
|
|
for (interaction, button_setting, entity) in &interaction_query {
|
2022-01-14 19:09:42 +00:00
|
|
|
if *interaction == Interaction::Clicked && *setting != *button_setting {
|
|
|
|
let (previous_button, mut previous_color) = selected_query.single_mut();
|
|
|
|
*previous_color = NORMAL_BUTTON.into();
|
|
|
|
commands.entity(previous_button).remove::<SelectedOption>();
|
|
|
|
commands.entity(entity).insert(SelectedOption);
|
|
|
|
*setting = *button_setting;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn menu_setup(mut menu_state: ResMut<State<MenuState>>) {
|
|
|
|
let _ = menu_state.set(MenuState::Main);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn main_menu_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
|
|
let font = asset_server.load("fonts/FiraSans-Bold.ttf");
|
|
|
|
// Common style for all buttons on the screen
|
|
|
|
let button_style = Style {
|
|
|
|
size: Size::new(Val::Px(250.0), Val::Px(65.0)),
|
2022-04-25 19:20:38 +00:00
|
|
|
margin: UiRect::all(Val::Px(20.0)),
|
2022-01-14 19:09:42 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
|
|
|
align_items: AlignItems::Center,
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
};
|
|
|
|
let button_icon_style = Style {
|
|
|
|
size: Size::new(Val::Px(30.0), Val::Auto),
|
2022-06-09 20:57:43 +00:00
|
|
|
// This takes the icons out of the flexbox flow, to be positioned exactly
|
2022-01-14 19:09:42 +00:00
|
|
|
position_type: PositionType::Absolute,
|
|
|
|
// The icon will be close to the left border of the button
|
2022-04-25 19:20:38 +00:00
|
|
|
position: UiRect {
|
2022-01-14 19:09:42 +00:00
|
|
|
left: Val::Px(10.0),
|
|
|
|
right: Val::Auto,
|
|
|
|
top: Val::Auto,
|
|
|
|
bottom: Val::Auto,
|
|
|
|
},
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
};
|
|
|
|
let button_text_style = TextStyle {
|
|
|
|
font: font.clone(),
|
|
|
|
font_size: 40.0,
|
|
|
|
color: TEXT_COLOR,
|
|
|
|
};
|
|
|
|
|
|
|
|
commands
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
.spawn((
|
|
|
|
NodeBundle {
|
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
align_items: AlignItems::Center,
|
2022-11-21 14:38:35 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
..default()
|
|
|
|
},
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
OnMainMenuScreen,
|
|
|
|
))
|
2022-01-14 19:09:42 +00:00
|
|
|
.with_children(|parent| {
|
|
|
|
parent
|
2022-11-21 14:38:35 +00:00
|
|
|
.spawn(NodeBundle {
|
|
|
|
style: Style {
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
align_items: AlignItems::Center,
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
..default()
|
|
|
|
},
|
2022-11-21 14:38:35 +00:00
|
|
|
background_color: Color::CRIMSON.into(),
|
|
|
|
..default()
|
|
|
|
})
|
2022-01-14 19:09:42 +00:00
|
|
|
.with_children(|parent| {
|
2022-11-21 14:38:35 +00:00
|
|
|
// Display the game name
|
|
|
|
parent.spawn(
|
|
|
|
TextBundle::from_section(
|
|
|
|
"Bevy Game Menu UI",
|
|
|
|
TextStyle {
|
|
|
|
font: font.clone(),
|
|
|
|
font_size: 80.0,
|
|
|
|
color: TEXT_COLOR,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
.with_style(Style {
|
|
|
|
margin: UiRect::all(Val::Px(50.0)),
|
|
|
|
..default()
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
|
|
|
|
// Display three buttons for each action available from the main menu:
|
|
|
|
// - new game
|
|
|
|
// - settings
|
|
|
|
// - quit
|
|
|
|
parent
|
|
|
|
.spawn((
|
|
|
|
ButtonBundle {
|
|
|
|
style: button_style.clone(),
|
|
|
|
background_color: NORMAL_BUTTON.into(),
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
MenuButtonAction::Play,
|
|
|
|
))
|
|
|
|
.with_children(|parent| {
|
|
|
|
let icon = asset_server.load("textures/Game Icons/right.png");
|
|
|
|
parent.spawn(ImageBundle {
|
|
|
|
style: button_icon_style.clone(),
|
|
|
|
image: UiImage::new(icon),
|
|
|
|
..default()
|
|
|
|
});
|
|
|
|
parent.spawn(TextBundle::from_section(
|
|
|
|
"New Game",
|
|
|
|
button_text_style.clone(),
|
|
|
|
));
|
|
|
|
});
|
|
|
|
parent
|
|
|
|
.spawn((
|
|
|
|
ButtonBundle {
|
|
|
|
style: button_style.clone(),
|
|
|
|
background_color: NORMAL_BUTTON.into(),
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
MenuButtonAction::Settings,
|
|
|
|
))
|
|
|
|
.with_children(|parent| {
|
|
|
|
let icon = asset_server.load("textures/Game Icons/wrench.png");
|
|
|
|
parent.spawn(ImageBundle {
|
|
|
|
style: button_icon_style.clone(),
|
|
|
|
image: UiImage::new(icon),
|
|
|
|
..default()
|
|
|
|
});
|
|
|
|
parent.spawn(TextBundle::from_section(
|
|
|
|
"Settings",
|
|
|
|
button_text_style.clone(),
|
|
|
|
));
|
|
|
|
});
|
|
|
|
parent
|
|
|
|
.spawn((
|
|
|
|
ButtonBundle {
|
|
|
|
style: button_style,
|
|
|
|
background_color: NORMAL_BUTTON.into(),
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
MenuButtonAction::Quit,
|
|
|
|
))
|
|
|
|
.with_children(|parent| {
|
|
|
|
let icon = asset_server.load("textures/Game Icons/exitRight.png");
|
|
|
|
parent.spawn(ImageBundle {
|
|
|
|
style: button_icon_style,
|
|
|
|
image: UiImage::new(icon),
|
|
|
|
..default()
|
|
|
|
});
|
|
|
|
parent.spawn(TextBundle::from_section("Quit", button_text_style));
|
|
|
|
});
|
2022-01-14 19:09:42 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn settings_menu_setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
|
|
let button_style = Style {
|
|
|
|
size: Size::new(Val::Px(200.0), Val::Px(65.0)),
|
2022-04-25 19:20:38 +00:00
|
|
|
margin: UiRect::all(Val::Px(20.0)),
|
2022-01-14 19:09:42 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
|
|
|
align_items: AlignItems::Center,
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
};
|
2022-07-20 14:14:29 +00:00
|
|
|
|
2022-01-14 19:09:42 +00:00
|
|
|
let button_text_style = TextStyle {
|
|
|
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
|
|
|
font_size: 40.0,
|
|
|
|
color: TEXT_COLOR,
|
|
|
|
};
|
|
|
|
|
|
|
|
commands
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
.spawn((
|
|
|
|
NodeBundle {
|
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
align_items: AlignItems::Center,
|
2022-11-21 14:38:35 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
..default()
|
|
|
|
},
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
OnSettingsMenuScreen,
|
|
|
|
))
|
2022-01-14 19:09:42 +00:00
|
|
|
.with_children(|parent| {
|
2022-11-21 14:38:35 +00:00
|
|
|
parent
|
|
|
|
.spawn(NodeBundle {
|
|
|
|
style: Style {
|
|
|
|
flex_direction: FlexDirection::Column,
|
|
|
|
align_items: AlignItems::Center,
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
background_color: Color::CRIMSON.into(),
|
|
|
|
..default()
|
|
|
|
})
|
|
|
|
.with_children(|parent| {
|
|
|
|
for (action, text) in [
|
|
|
|
(MenuButtonAction::SettingsDisplay, "Display"),
|
|
|
|
(MenuButtonAction::SettingsSound, "Sound"),
|
|
|
|
(MenuButtonAction::BackToMainMenu, "Back"),
|
|
|
|
] {
|
|
|
|
parent
|
|
|
|
.spawn((
|
|
|
|
ButtonBundle {
|
|
|
|
style: button_style.clone(),
|
|
|
|
background_color: NORMAL_BUTTON.into(),
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
action,
|
|
|
|
))
|
|
|
|
.with_children(|parent| {
|
|
|
|
parent.spawn(TextBundle::from_section(
|
|
|
|
text,
|
|
|
|
button_text_style.clone(),
|
|
|
|
));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
2022-01-14 19:09:42 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn display_settings_menu_setup(
|
|
|
|
mut commands: Commands,
|
|
|
|
asset_server: Res<AssetServer>,
|
|
|
|
display_quality: Res<DisplayQuality>,
|
|
|
|
) {
|
|
|
|
let button_style = Style {
|
|
|
|
size: Size::new(Val::Px(200.0), Val::Px(65.0)),
|
2022-04-25 19:20:38 +00:00
|
|
|
margin: UiRect::all(Val::Px(20.0)),
|
2022-01-14 19:09:42 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
|
|
|
align_items: AlignItems::Center,
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
};
|
|
|
|
let button_text_style = TextStyle {
|
|
|
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
|
|
|
font_size: 40.0,
|
|
|
|
color: TEXT_COLOR,
|
|
|
|
};
|
|
|
|
|
|
|
|
commands
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
.spawn((
|
|
|
|
NodeBundle {
|
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
align_items: AlignItems::Center,
|
2022-11-21 14:38:35 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
..default()
|
|
|
|
},
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
OnDisplaySettingsMenuScreen,
|
|
|
|
))
|
2022-01-14 19:09:42 +00:00
|
|
|
.with_children(|parent| {
|
|
|
|
parent
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
.spawn(NodeBundle {
|
2022-01-14 19:09:42 +00:00
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
flex_direction: FlexDirection::Column,
|
2022-01-14 19:09:42 +00:00
|
|
|
align_items: AlignItems::Center,
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
2022-09-25 00:39:17 +00:00
|
|
|
background_color: Color::CRIMSON.into(),
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
})
|
|
|
|
.with_children(|parent| {
|
2022-11-21 14:38:35 +00:00
|
|
|
// Create a new `NodeBundle`, this time not setting its `flex_direction`. It will
|
|
|
|
// use the default value, `FlexDirection::Row`, from left to right.
|
|
|
|
parent
|
|
|
|
.spawn(NodeBundle {
|
2022-01-14 19:09:42 +00:00
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
align_items: AlignItems::Center,
|
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
2022-11-21 14:38:35 +00:00
|
|
|
background_color: Color::CRIMSON.into(),
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-11-21 14:38:35 +00:00
|
|
|
})
|
|
|
|
.with_children(|parent| {
|
|
|
|
// Display a label for the current setting
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
parent.spawn(TextBundle::from_section(
|
2022-11-21 14:38:35 +00:00
|
|
|
"Display Quality",
|
2022-07-20 14:14:29 +00:00
|
|
|
button_text_style.clone(),
|
|
|
|
));
|
2022-11-21 14:38:35 +00:00
|
|
|
// Display a button for each possible value
|
|
|
|
for quality_setting in [
|
|
|
|
DisplayQuality::Low,
|
|
|
|
DisplayQuality::Medium,
|
|
|
|
DisplayQuality::High,
|
|
|
|
] {
|
|
|
|
let mut entity = parent.spawn(ButtonBundle {
|
|
|
|
style: Style {
|
|
|
|
size: Size::new(Val::Px(150.0), Val::Px(65.0)),
|
|
|
|
..button_style.clone()
|
|
|
|
},
|
|
|
|
background_color: NORMAL_BUTTON.into(),
|
|
|
|
..default()
|
|
|
|
});
|
|
|
|
entity.insert(quality_setting).with_children(|parent| {
|
|
|
|
parent.spawn(TextBundle::from_section(
|
|
|
|
format!("{quality_setting:?}"),
|
|
|
|
button_text_style.clone(),
|
|
|
|
));
|
|
|
|
});
|
|
|
|
if *display_quality == quality_setting {
|
|
|
|
entity.insert(SelectedOption);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
// Display the back button to return to the settings screen
|
|
|
|
parent
|
|
|
|
.spawn((
|
|
|
|
ButtonBundle {
|
|
|
|
style: button_style,
|
|
|
|
background_color: NORMAL_BUTTON.into(),
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
MenuButtonAction::BackToSettings,
|
|
|
|
))
|
|
|
|
.with_children(|parent| {
|
|
|
|
parent.spawn(TextBundle::from_section("Back", button_text_style));
|
2022-01-14 19:09:42 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn sound_settings_menu_setup(
|
|
|
|
mut commands: Commands,
|
|
|
|
asset_server: Res<AssetServer>,
|
|
|
|
volume: Res<Volume>,
|
|
|
|
) {
|
|
|
|
let button_style = Style {
|
|
|
|
size: Size::new(Val::Px(200.0), Val::Px(65.0)),
|
2022-04-25 19:20:38 +00:00
|
|
|
margin: UiRect::all(Val::Px(20.0)),
|
2022-01-14 19:09:42 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
|
|
|
align_items: AlignItems::Center,
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
};
|
|
|
|
let button_text_style = TextStyle {
|
|
|
|
font: asset_server.load("fonts/FiraSans-Bold.ttf"),
|
|
|
|
font_size: 40.0,
|
|
|
|
color: TEXT_COLOR,
|
|
|
|
};
|
|
|
|
|
|
|
|
commands
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
.spawn((
|
|
|
|
NodeBundle {
|
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
align_items: AlignItems::Center,
|
2022-11-21 14:38:35 +00:00
|
|
|
justify_content: JustifyContent::Center,
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
..default()
|
|
|
|
},
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
OnSoundSettingsMenuScreen,
|
|
|
|
))
|
2022-01-14 19:09:42 +00:00
|
|
|
.with_children(|parent| {
|
|
|
|
parent
|
Spawn now takes a Bundle (#6054)
# Objective
Now that we can consolidate Bundles and Components under a single insert (thanks to #2975 and #6039), almost 100% of world spawns now look like `world.spawn().insert((Some, Tuple, Here))`. Spawning an entity without any components is an extremely uncommon pattern, so it makes sense to give spawn the "first class" ergonomic api. This consolidated api should be made consistent across all spawn apis (such as World and Commands).
## Solution
All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input:
```rust
// before:
commands
.spawn()
.insert((A, B, C));
world
.spawn()
.insert((A, B, C);
// after
commands.spawn((A, B, C));
world.spawn((A, B, C));
```
All existing instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api. A new `spawn_empty` has been added, replacing the old `spawn` api.
By allowing `world.spawn(some_bundle)` to replace `world.spawn().insert(some_bundle)`, this opened the door to removing the initial entity allocation in the "empty" archetype / table done in `spawn()` (and subsequent move to the actual archetype in `.insert(some_bundle)`).
This improves spawn performance by over 10%:
![image](https://user-images.githubusercontent.com/2694663/191627587-4ab2f949-4ccd-4231-80eb-80dd4d9ad6b9.png)
To take this measurement, I added a new `world_spawn` benchmark.
Unfortunately, optimizing `Commands::spawn` is slightly less trivial, as Commands expose the Entity id of spawned entities prior to actually spawning. Doing the optimization would (naively) require assurances that the `spawn(some_bundle)` command is applied before all other commands involving the entity (which would not necessarily be true, if memory serves). Optimizing `Commands::spawn` this way does feel possible, but it will require careful thought (and maybe some additional checks), which deserves its own PR. For now, it has the same performance characteristics of the current `Commands::spawn_bundle` on main.
**Note that 99% of this PR is simple renames and refactors. The only code that needs careful scrutiny is the new `World::spawn()` impl, which is relatively straightforward, but it has some new unsafe code (which re-uses battle tested BundlerSpawner code path).**
---
## Changelog
- All `spawn` apis (`World::spawn`, `Commands:;spawn`, `ChildBuilder::spawn`, and `WorldChildBuilder::spawn`) now accept a bundle as input
- All instances of `spawn_bundle` have been deprecated in favor of the new `spawn` api
- World and Commands now have `spawn_empty()`, which is equivalent to the old `spawn()` behavior.
## Migration Guide
```rust
// Old (0.8):
commands
.spawn()
.insert_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
commands.spawn_bundle((A, B, C));
// New (0.9)
commands.spawn((A, B, C));
// Old (0.8):
let entity = commands.spawn().id();
// New (0.9)
let entity = commands.spawn_empty().id();
// Old (0.8)
let entity = world.spawn().id();
// New (0.9)
let entity = world.spawn_empty();
```
2022-09-23 19:55:54 +00:00
|
|
|
.spawn(NodeBundle {
|
2022-01-14 19:09:42 +00:00
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
flex_direction: FlexDirection::Column,
|
2022-01-14 19:09:42 +00:00
|
|
|
align_items: AlignItems::Center,
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
2022-09-25 00:39:17 +00:00
|
|
|
background_color: Color::CRIMSON.into(),
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
})
|
|
|
|
.with_children(|parent| {
|
2022-11-21 14:38:35 +00:00
|
|
|
parent
|
|
|
|
.spawn(NodeBundle {
|
2022-01-14 19:09:42 +00:00
|
|
|
style: Style {
|
2022-11-21 14:38:35 +00:00
|
|
|
align_items: AlignItems::Center,
|
|
|
|
..default()
|
2022-01-14 19:09:42 +00:00
|
|
|
},
|
2022-11-21 14:38:35 +00:00
|
|
|
background_color: Color::CRIMSON.into(),
|
2022-03-01 20:52:09 +00:00
|
|
|
..default()
|
2022-11-21 14:38:35 +00:00
|
|
|
})
|
|
|
|
.with_children(|parent| {
|
|
|
|
parent.spawn(TextBundle::from_section(
|
|
|
|
"Volume",
|
|
|
|
button_text_style.clone(),
|
|
|
|
));
|
|
|
|
for volume_setting in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] {
|
|
|
|
let mut entity = parent.spawn(ButtonBundle {
|
|
|
|
style: Style {
|
|
|
|
size: Size::new(Val::Px(30.0), Val::Px(65.0)),
|
|
|
|
..button_style.clone()
|
|
|
|
},
|
|
|
|
background_color: NORMAL_BUTTON.into(),
|
|
|
|
..default()
|
|
|
|
});
|
|
|
|
entity.insert(Volume(volume_setting));
|
|
|
|
if *volume == Volume(volume_setting) {
|
|
|
|
entity.insert(SelectedOption);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
parent
|
|
|
|
.spawn((
|
|
|
|
ButtonBundle {
|
|
|
|
style: button_style,
|
|
|
|
background_color: NORMAL_BUTTON.into(),
|
|
|
|
..default()
|
|
|
|
},
|
|
|
|
MenuButtonAction::BackToSettings,
|
|
|
|
))
|
|
|
|
.with_children(|parent| {
|
|
|
|
parent.spawn(TextBundle::from_section("Back", button_text_style));
|
2022-01-14 19:09:42 +00:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
fn menu_action(
|
|
|
|
interaction_query: Query<
|
|
|
|
(&Interaction, &MenuButtonAction),
|
|
|
|
(Changed<Interaction>, With<Button>),
|
|
|
|
>,
|
|
|
|
mut app_exit_events: EventWriter<AppExit>,
|
|
|
|
mut menu_state: ResMut<State<MenuState>>,
|
|
|
|
mut game_state: ResMut<State<GameState>>,
|
|
|
|
) {
|
2022-07-11 15:28:50 +00:00
|
|
|
for (interaction, menu_button_action) in &interaction_query {
|
2022-01-14 19:09:42 +00:00
|
|
|
if *interaction == Interaction::Clicked {
|
|
|
|
match menu_button_action {
|
|
|
|
MenuButtonAction::Quit => app_exit_events.send(AppExit),
|
|
|
|
MenuButtonAction::Play => {
|
|
|
|
game_state.set(GameState::Game).unwrap();
|
2022-02-13 22:33:55 +00:00
|
|
|
menu_state.set(MenuState::Disabled).unwrap();
|
2022-01-14 19:09:42 +00:00
|
|
|
}
|
|
|
|
MenuButtonAction::Settings => menu_state.set(MenuState::Settings).unwrap(),
|
|
|
|
MenuButtonAction::SettingsDisplay => {
|
2022-02-13 22:33:55 +00:00
|
|
|
menu_state.set(MenuState::SettingsDisplay).unwrap();
|
2022-01-14 19:09:42 +00:00
|
|
|
}
|
|
|
|
MenuButtonAction::SettingsSound => {
|
2022-02-13 22:33:55 +00:00
|
|
|
menu_state.set(MenuState::SettingsSound).unwrap();
|
2022-01-14 19:09:42 +00:00
|
|
|
}
|
|
|
|
MenuButtonAction::BackToMainMenu => menu_state.set(MenuState::Main).unwrap(),
|
|
|
|
MenuButtonAction::BackToSettings => {
|
2022-02-13 22:33:55 +00:00
|
|
|
menu_state.set(MenuState::Settings).unwrap();
|
2022-01-14 19:09:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generic system that takes a component as a parameter, and will despawn all entities with that component
|
|
|
|
fn despawn_screen<T: Component>(to_despawn: Query<Entity, With<T>>, mut commands: Commands) {
|
2022-07-11 15:28:50 +00:00
|
|
|
for entity in &to_despawn {
|
2022-01-14 19:09:42 +00:00
|
|
|
commands.entity(entity).despawn_recursive();
|
|
|
|
}
|
|
|
|
}
|