diff --git a/changes.md b/changes.md deleted file mode 100644 index 3f2804b035..0000000000 --- a/changes.md +++ /dev/null @@ -1,126 +0,0 @@ -## Release TODO -* bevy_ecs relicense (not required ... tbd) -* re-count prs + contributors -* match typed contributor names to auto-gen contributor list (sanity check) -* update docs (especially tutorial) - -## Changes - - -### WASM - -* WASM / WebGL2 - * internal renderer changes mrk-its - * delegate buffer aligning to render_resource_context - * reflection to renderresourcecontext - * auto-reflect dynamic bindings - * non-spirv shader specializatoin - * instant - * plugin - -### Write once run anywhere - -* Cross platform main - -### Live Shader Reloading -* Live shader reloading @yrns - -### ECS - -* Flexible ECS Params -* Query Filters -* System Inputs, Outputs, Chaining, Registration Ergo @cart -* bevy_ecs + bevy_hecs merger -* upsrteam hecs improvements (@Veykril, upstream contribs) - * better Bundle derive macro (generics, tuple, unit structs) -* Check for conflicting system resource parameters @memoryruins -* ECS Change Bitflags @cart -* Schedule V2 - * improve usablityl of systemsage - -### GLTF -* gltf improvements - * Camera and Hierarchy @FuriouZz - * Pixel format conversion @iwikal - * Default material loading @rod-salazar -### Scene Usability -* Scene usability - * Spawn scenes as children @mockersf - -### Dynamic Linking - -* Dynamic Linking @bjorn3 @cart - -### Text Improvements - -* Text Improvements @AlisCode - * use glyph_brush_layout for text layout - * text alignment - * fixes a number of text releated bugs (such as the infamous bouncing text) - -### Performance Improvements - -* Renderer Optimization @cart - * w/ help from profiling changes - * round 1 - * Text Rendering / Shared Buffers - * Asset GPU data transfer -* Dont draw text when it isn't visible @marius851000 -* mailbox when possible @cart - -### Reflection -* Reflection @cart - -### 3D Texture Assets - -* 3D texture asset support @bonsairobo - -### Logging and Profiling - -* Tracing @superdump @cart - * logging - * profiling - * enabled by default - * tracing-chrome @superdump - * Log Plugin @cart - * cross platform logging - * custom Android tracing logger - * Helpful span names tracing-chrome @superdump - -### Task Scheduler Improvements -* Task scheduler deadlock fix (and perf improvements) @aclysma - -### HIDPI -* HiDPI - * use logical units by default @mockersf - * swap chain scaling @cart - * float width/height @blunted2night - * handle rounding issues @blunted2night - * stretch hidpi @blunted2night - -### Timer Improvements -* Timer improvements - * pausing and encapsulation @amberkowalski - * Timer ergo @marcusbuffett - * Timer ergo and tests @CleanCut - * Timer polishing @CleanCut - * Refactor @amberkowalski - -### Apple Silicon Support -* Apple Silicon Support - * use shaderc + winit + testing @frewsxcv - * upstream - * coreaudo-sys @wyhaya - * winit @scoopr - -### Examples -* contributors example @karoffel -* bevymark example @robdavenport - - -### MISC -* receivedchar event -* Controllable ambient light color no1hitjam -* Color constants @milkybit -* EventId for events @bjorn3 -* set cursor position @smokku diff --git a/content/learn/book/migration-guides/0.4-0.5/_index.md b/content/learn/book/migration-guides/0.4-0.5/_index.md index d6bf825d5e..a9a86f9bb6 100644 --- a/content/learn/book/migration-guides/0.4-0.5/_index.md +++ b/content/learn/book/migration-guides/0.4-0.5/_index.md @@ -10,7 +10,7 @@ long_title = "Migration Guide: 0.4 to 0.5" -## `commands: &mut Commands` SystemParam is now `mut commands: Commands` +### "commands: &mut Commands" SystemParam is now "mut commands: Commands" ```rust // 0.4 @@ -30,7 +30,7 @@ reference to enable safe entity allocations. Note: The internal {{rust_type(type="struct" crate="bevy_ecs" version="0.5.0" name="World" no_mod=true)}} reference requires two lifetime parameters to pass Commands into a non-system function: ```commands: &'a mut Commands<'b>``` -## {{rust_type(type="struct" crate="bevy_ecs" version="0.5.0" name="Commands" no_mod=true)}} `insert()` API is now used for a single component +### Commands::insert() API is now used for a single component ```rust // 0.4 @@ -54,7 +54,7 @@ This means that `commands.insert()` will no longer accept a bundle as an argumen This change helps to clarify the difference between components and bundles, and brings {{rust_type(type="struct" crate="bevy_ecs" version="0.5.0" name="Commands" no_mod=true)}} into alignment with other Bevy APIs. It also eliminates the confusion associated with calling `commands.insert()` on a tuple for the single-component case. -## {{rust_type(type="struct" crate="bevy_core" version="0.5.0" name="Timer" no_mod=true)}} uses `Duration` +### Timer now uses Duration ```rust // 0.4 @@ -73,7 +73,7 @@ This change allows timers to have consistent, high precision. For convenience, t `elapsed_secs` method that returns `f32`. Otherwise, when you need an `f32`, use the `as_secs_f32()` method on `Duration` to make the conversion. -## Simplified Events +### Simplified Events ```rust // 0.4 @@ -112,11 +112,11 @@ fn event_writer_system( } ``` -## `AppBuilder::add_resource` is now called `AppBuilder::insert_resource` +### AppBuilder::add_resource is now called AppBuilder::insert_resource This is a small change to have function names on `AppBuilder` consistent with the `Commands` API. -## TextBundle +### TextBundle This bundle has been reworked to allow multiple differently-styled sections of text within a single bundle. `Text::with_section` was added to simplify the common case where you're only interested in one text section. diff --git a/content/news/2021-04-06-bevy-0.5/2d_text.mp4 b/content/news/2021-04-06-bevy-0.5/2d_text.mp4 new file mode 100644 index 0000000000..d97733d796 Binary files /dev/null and b/content/news/2021-04-06-bevy-0.5/2d_text.mp4 differ diff --git a/content/news/2021-04-06-bevy-0.5/add_remove_big.svg b/content/news/2021-04-06-bevy-0.5/add_remove_big.svg new file mode 100644 index 0000000000..3be4eb8dc0 --- /dev/null +++ b/content/news/2021-04-06-bevy-0.5/add_remove_big.svg @@ -0,0 +1,496 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/news/2021-04-06-bevy-0.5/alien_cake_addict.png b/content/news/2021-04-06-bevy-0.5/alien_cake_addict.png new file mode 100644 index 0000000000..41cfbc5ba6 Binary files /dev/null and b/content/news/2021-04-06-bevy-0.5/alien_cake_addict.png differ diff --git a/content/news/2021-04-06-bevy-0.5/ante.png b/content/news/2021-04-06-bevy-0.5/ante.png new file mode 100644 index 0000000000..c92dfe6be8 Binary files /dev/null and b/content/news/2021-04-06-bevy-0.5/ante.png differ diff --git a/content/news/2021-04-06-bevy-0.5/flighthelmet.mp4 b/content/news/2021-04-06-bevy-0.5/flighthelmet.mp4 new file mode 100644 index 0000000000..a1c928a00b Binary files /dev/null and b/content/news/2021-04-06-bevy-0.5/flighthelmet.mp4 differ diff --git a/content/news/2021-04-06-bevy-0.5/frag_iter.svg b/content/news/2021-04-06-bevy-0.5/frag_iter.svg new file mode 100644 index 0000000000..729aa5d1f9 --- /dev/null +++ b/content/news/2021-04-06-bevy-0.5/frag_iter.svg @@ -0,0 +1,743 @@ + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/content/news/2021-04-06-bevy-0.5/hidpi_text.png b/content/news/2021-04-06-bevy-0.5/hidpi_text.png new file mode 100644 index 0000000000..5c087b8d6c Binary files /dev/null and b/content/news/2021-04-06-bevy-0.5/hidpi_text.png differ diff --git a/content/news/2021-04-06-bevy-0.5/index.md b/content/news/2021-04-06-bevy-0.5/index.md new file mode 100644 index 0000000000..c30c4f7d1b --- /dev/null +++ b/content/news/2021-04-06-bevy-0.5/index.md @@ -0,0 +1,1478 @@ ++++ +title = "Bevy 0.5" +date = 2021-04-06 +[extra] +author = "Carter Anderson" +twitter = "cart_cart" +github = "cart" +youtube = "cartdev" +image = "ante.png" +show_image = true +image_subtitle = "Screenshot of Ante: a voxel builder game being developed in Bevy by @TheNeikos" +image_subtitle_link = "" ++++ + +Thanks to **88** contributors, **283** pull requests, and our [**generous sponsors**](https://github.com/sponsors/cart), I'm happy to announce the **Bevy 0.5** release on [crates.io](https://crates.io/crates/bevy)! + +For those who don't know, Bevy is a refreshingly simple data-driven game engine built in Rust. You can check out [Quick Start Guide](/learn/book/getting-started/) to get started. Bevy is also free and open source forever! You can grab the full [source code](https://github.com/bevyengine/bevy) on GitHub. + +**Bevy 0.5** is quite a bit bigger than our past few releases (and took a bit longer) as we have made a number of foundational changes. If you plan on updating your App or Plugin to **Bevy 0.5**, check out our [0.4 to 0.5 Migration Guide](/learn/book/migration-guides/0.4-0.5/). + +Here are some of the highlights from this release: + + + + +## Physically Based Rendering (PBR) + +
authors: @StarArawn, @mtsr, @mockersf, @IngmarBitter, @Josh015, @norgate, @cart
+ +Bevy now uses PBR shaders when rendering. PBR is a semi-standard approach to rendering that attempts to use approximations of real-world "physically based" lighting and material properties. We largely use techniques from the [Filament](https://github.com/google/filament/) PBR implementation, but we also incorporate some ideas from [Unreal](https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile) and [Disney](https://google.github.io/filament/Filament.html#citation-burley12). + +Bevy's `StandardMaterial` now has `base_color`, `roughness`, `metallic`, `reflection`, and `emissive` properties. It also now supports textures for `base_color`, `normal_map`, `metallic_roughness`, `emissive`, and `occlusion` properties. + +The new PBR example helps visualize these new material properties: + +![pbr](pbr.png) + +## GLTF Improvements + +### PBR Textures + +
authors: @mtsr, @mockersf
+ +The GLTF loader now supports normal maps, metallic/roughness, occlusion, and emissive textures. Our "flight helmet" gltf example utilizes the new PBR texture support and looks much nicer as a result: + + + +### Top-Level GLTF Asset + +
authors: @mockersf
+ +Previously it was hard to interact with GLTF assets because scenes / meshes / textures / and materials were only loaded as "sub assets". Thanks to the new top level {{rust_type(type="struct" crate="bevy_gltf" version="0.5.0" name="Gltf" no_mod=true)}} asset type, it is now possible to navigate the contents of the GLTF asset: + +```rust +// load GLTF asset on startup +fn setup(mut commands: Commands, assets: Res) { + let handle = assets.load("flight_helmet.gltf"); + commands.insert_resource(handle); +} + +// access GLTF asset at some later point in time +fn system(handle: Res>, gltfs: Res>, materials: Res>) { + let gltf = gltfs.get(&handle).unwrap(); + let material_handle = gltf.named_materials.get("MetalPartsMat").unwrap(); + let material = materials.get(material_handle).unwrap(); +} +``` + +## Bevy ECS V2 + +This release marks a huge step forward for Bevy's ECS. It has significant implications for how Bevy Apps are composed and how well they perform: + +* **[A full rewrite of the ECS core:](#ecs-core-rewrite)** + * Massively improved performance across the board + * "Hybrid" component storage + * An "Archetype Graph" for faster archetype changes + * Stateful queries that cache results across runs +* **[A brand new parallel System executor:](#new-parallel-system-executor)** + * Support for explicit system ordering + * System Labels + * System Sets + * Improved system "run criteria" + * Increased system parallelism +* **["Reliable" change detection:](#reliable-change-detection)** + * Systems will now always detect component changes, even across frames +* **[A rewrite of the State system:](#states-v2)** + * A much more natural "stack-based state machine" model + * Direct integration with the new scheduler + * Improved "state lifecycle" events + +Read on for the details! + +## ECS Core Rewrite + +
authors: @cart
+ +Up until this point, Bevy used a heavily forked version of [hecs](https://github.com/Ralith/hecs) for our ECS core. Since Bevy's first release, we've learned a lot about Bevy's ECS needs. We've also collaborated with other ECS project leaders, such as [Sander Mertens](https://github.com/SanderMertens) (lead [flecs](https://github.com/SanderMertens/flecs) developer) and [Gijs-Jan Roelofs](https://github.com/gjroelofs) (Xenonauts ECS framework developer). As an "ECS community", we've started to zero in on what the future of ECS could be. + +Bevy ECS v2 is our first step into that future. It also means that Bevy ECS is no longer a "hecs fork". We are going out on our own! + +### Component Storage (The Problem) + +Two ECS storage paradigms have gained a lot of traction over the years: + +* **Archetypal ECS**: + * Stores components in "tables" with static schemas. Each "column" stores components of a given type. Each "row" is an entity. + * Each "archetype" has its own table. Adding/removing an entity's component changes the archetype. + * Enables super-fast Query iteration due to its cache-friendly data layout + * Comes at the cost of more expensive add/remove operations for an Entity's components, because all components need to be copied to the new archetype's "table" + * Parallelism-friendly: entities only exist in one archetype at a time so systems that access the same components but in different archetypes can run in parallel + * Frameworks: Old Bevy ECS, hecs, legion, flecs, Unity DOTS +* **Sparse Set ECS**: + * Stores components of the same type in densely packed arrays, which are sparsely indexed by densely packed unsigned integers (entity ids) + * Query iteration is slower than Archetypal ECS (by default) because each entity's component could be at any position in the sparse set. This "random access" pattern isn't cache friendly. Additionally, there is an extra layer of indirection because you must first map the entity id to an index in the component array. + * Adding/removing components is a cheap, constant time operation + * "Component Packs" are used to optimize iteration performance on a case by case basis (but packs conflict with each other) + * Less parallelism friendly: systems need to either lock a whole component storage (not granular) or individual entities (expensive) + * Frameworks: Shipyard, EnTT + +Developers selecting an ECS framework are stuck with a hard choice. Select an "archetypal" framework with "fast iteration everywhere" but without the ability to cheaply add/remove components, or select a "sparse set" framework to cheaply add/remove components but with slower iteration performance or manual (and conflicting) pack optimizations. + +### Hybrid Component Storage (The Solution) + +In Bevy ECS V2, we get to have our cake and eat it too. It now has _both_ of the component storage types above (and more can be added later if needed): + +* **Tables** (aka "archetypal" storage in other frameworks) + * The default storage. If you don't configure anything, this is what you get + * Fast iteration by default + * Slower add/remove operations +* **Sparse Sets** + * Opt-in + * Slower iteration + * Faster add/remove operations + +These storage types complement each other perfectly. By default Query iteration is fast. If developers know that they want to add/remove a component at high frequencies, they can set the storage to "sparse set": + +```rust +app.register_component( + ComponentDescriptor::new::(StorageType::SparseSet) +); +``` + +#### Component Add/Remove Benchmark (in milliseconds, less is better) + +This benchmark illustrates adding and removing a single 4x4 matrix component 10,000 times from an entity that has 5 other 4x4 matrix components. The "other" components are included to help illustrate the cost of "table storage" (used by Bevy 0.4, Bevy 0.5 (Table), and Legion), which requires moving the "other" components to a new table. + +![component add/remove](add_remove_big.svg) + +You may have noticed that **Bevy 0.5 (Table)** is also _way_ faster than **Bevy 0.4**, even though they both use "table storage". This is largely a result of the new [Archetype Graph](https://github.com/bevyengine/bevy/pull/1525), which significantly cuts the cost of archetype changes. + +### Stateful Queries and System Parameters + +{{rust_type(type="struct" crate="bevy_ecs" mod="world" version="0.5.0" name="World" no_mod=true)}} queries (and other system parameters) are now stateful. This allows us to: + +1. Cache archetype (and table) matches + * This resolves another issue with (naive) archetypal ECS: query performance getting worse as the number of archetypes goes up (and fragmentation occurs). +2. Cache Query Fetch and Filter state + * The expensive parts of fetch/filter operations (such as hashing the TypeId to find the ComponentId) now only happen once when the Query is first constructed +3. Incrementally build up state + * When new archetypes are added, we only process the new archetypes (no need to rebuild state for old archetypes) + +As a result, the direct {{rust_type(type="struct" crate="bevy_ecs" mod="world" version="0.5.0" name="World" no_mod=true)}} query api now looks like this: + +```rust +let mut query = world.query::<(&A, &mut B)>(); +for (a, mut b) in query.iter_mut(&mut world) { +} +``` + +However for {{rust_type(type="trait" crate="bevy_ecs" mod="system" version="0.5.0" name="System" no_mod=true plural=true)}} this is a non-breaking change. Query state management is done internally by the relevant SystemParam. + +We have achieved some pretty significant performance wins as a result of the new Query system. + +#### "Sparse" Fragmented Iterator Benchmark (in nanoseconds, less is better) + +This benchmark runs a query that matches 5 entities within a single archetype and _doesn't_ match 100 other archetypes. This is a reasonable test of "real world" queries in games, which generally have many different entity "types", most of which _don't_ match a given query. This test uses "table storage" across the board. + +![sparse_frag_iter](sparse_frag_iter.svg) + + +**Bevy 0.5** marks a huge improvement for cases like this, thanks to the new "stateful queries". **Bevy 0.4** needs to check every archetype each time the iterator is run, whereas **Bevy 0.5** amortizes that cost to zero. + +#### Fragmented Iterator Benchmark (in milliseconds, less is better) + +This is the [ecs_bench_suite](https://github.com/rust-gamedev/ecs_bench_suite) `frag_iter` benchmark. It runs a query on 27 archetypes with 20 entities each. However unlike the "Sparse Fragmented Iterator Benchmark", there are no "unmatched" archetypes. This test uses "table storage" across the board. + +![frag_iter](frag_iter.svg) + +The gains here compared to the last benchmark are smaller because there aren't any unmatched archetypes. However **Bevy 0.5** still gets a nice boost due to better iterator/query impls, amortizing the cost of matched archetypes to zero, and for_each iterators. + +### Uber Fast "for_each" Query Iterators + +Developers now have the choice to use a fast {{rust_type(type="struct" crate="bevy_ecs" mod="system" version="0.5.0" name="Query" no_mod=true method="for_each")}} iterator, which yields ~1.5-3x iteration speed improvements for "fragmented iteration", and minor ~1.2x iteration speed improvements for unfragmented iteration. + +```rust +fn system(query: Query<(&A, &mut B)>) { + // you now have the option to do this for a speed boost + query.for_each_mut(|(a, mut b)| { + }); + + // however normal iterators are still available + for (a, mut b) in query.iter_mut() { + } +} +``` + +We will continue to encourage "normal" iterators as they are more flexible and more "rust idiomatic". But when that extra "oomf" is needed, `for_each` will be there ... waiting for you :) + +## New Parallel System Executor + +
authors: @Ratysz
+ +Bevy's old parallel executor had a number of fundamental limitations: + +1. The only way to explicitly define system order was to create new stages. This was both boilerplate-ey and prevented parallelism (because stages run "one by one" in order). We've noticed that system ordering is a common requirement and stages just weren't cutting it. +2. Systems had "implicit" orderings when they accessed conflicting resources. These orderings were hard to reason about. +3. The "implicit orderings" produced execution strategies that often left a lot of parallelism potential on the table. + +Fortunately @Ratysz has been [doing](https://ratysz.github.io/article/scheduling-1/) a lot of [research](https://github.com/Ratysz/yaks/) in this area and volunteered to contribute a new executor. The new executor solves all of the issues above and also adds a bunch of new usability improvements. The "ordering" rules are now dead-simple: + +1. Systems run in parallel by default +2. Systems with explicit orderings defined will respect those orderings + +### Explicit System Dependencies and System Labels + +
authors: @Ratysz, @TheRawMeatball
+ +Systems can now be assigned one or more {{rust_type(type="trait" crate="bevy_ecs" mod="schedule" version="0.5.0" name="SystemLabel" no_mod=true plural=true)}}. These labels can then be referenced by other systems (within a stage) to run before or after systems with that label: + +```rust +app + .add_system(update_velocity.system().label("velocity")) + // The "movement" system will run after "update_velocity" + .add_system(movement.system().after("velocity")) +``` + +This produces an equivalent ordering, but it uses `before()` instead. + +```rust +app + // The "update_velocity" system will run before "movement" + .add_system(update_velocity.system().before("movement")) + .add_system(movement.system().label("movement")); +``` + +Any type that implements the {{rust_type(type="trait" crate="bevy_ecs" mod="schedule" version="0.5.0" name="SystemLabel" no_mod=true)}} trait can be used. In most cases we recommend defining custom types and deriving {{rust_type(type="trait" crate="bevy_ecs" mod="schedule" version="0.5.0" name="SystemLabel" no_mod=true)}} for them. This prevents typos, allows for encapsulation (when needed), and allows IDEs to autocomplete labels: + +```rust +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] +pub enum PhysicsSystem { + UpdateVelocity, + Movement, +} + +app + .add_system(update_velocity.system().label(PhysicsSystem::UpdateVelocity)) + .add_system(movement.system() + .label(PhysicsSystem::Movement) + .after(PhysicsSystem::UpdateVelocity) + ); +``` + +### Many-to-Many System Labels + +Many-to-many labels is a powerful concept that makes it easy to take a dependency on many systems that produce a given behavior/outcome. For example, if you have a system that needs to run after all "physics" has finished updating (see the example above), you could label all "physics systems" with the same `Physics` label: + +```rust +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] +pub struct Physics; + +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemLabel)] +pub enum PhysicsSystem { + UpdateVelocity, + Movement, +} + +app + .add_system(update_velocity.system() + .label(PhysicsSystem::UpdateVelocity) + .label(Physics) + ) + .add_system(movement.system() + .label(PhysicsSystem::Movement) + .label(Physics) + .after(PhysicsSystem::UpdateVelocity) + ) + .add_system(runs_after_physics.system().after(Physics)); +``` + +Bevy plugin authors should export labels like this in their public APIs to enable their users to insert systems before/after logic provided by the plugin. + +### System Sets + +{{rust_type(type="struct" crate="bevy_ecs" mod="schedule" version="0.5.0" name="SystemSet" no_mod=true plural=true)}} are a new way to apply the same configuration to a group of systems, which significantly cuts down on boilerplate. The "physics" example above could be rephrased like this: + +```rust +app + .add_system_set(SystemSet::new() + // this label is added to all systems in the set + .label(Physics) + .with_system(update_velocity.system().label(PhysicsSystem::UpdateVelocity)) + .with_system(movement.system() + .label(PhysicsSystem::Movement) + .after(PhysicsSystem::UpdateVelocity) + ) + ) +``` + +SystemSets can also use `before(Label)` and `after(Label)` to run all systems in the set before/after the given label. + +This is also very useful for groups of systems that need to run with the same {{rust_type(type="struct" crate="bevy_ecs" mod="schedule" version="0.5.0" name="RunCriteria" no_mod=true)}}. + +```rust +app + // all systems in this set will run once every two seconds + .add_system_set(SystemSet::new() + .with_run_criteria(FixedTimestep::step(2.0)) + .with_system(foo.system()) + .with_system(bar.system()) + ) +``` + +### Improved Run Criteria + +Run Criteria are now decoupled from systems and will be re-used when possible. For example, the FixedTimestep criteria in the example above will only be run once per stage run. The executor will re-use the criteria's result for both the `foo` and `bar` system. + +Run Criteria can now also be labeled and referenced by other systems: + + +```rust +fn every_other_time(mut has_ran: Local) -> ShouldRun { + *has_ran = !*has_ran; + if *has_ran { + ShouldRun::Yes + } else { + ShouldRun::No + } +} + +app.add_stage(SystemStage::parallel() + .with_system_run_criteria(every_other_time.system().label("every_other_time"))) + .add_system(foo.system().with_run_criteria("every_other_time")) +``` + +Results from Run Criteria can also be "piped" into other criteria, which enables interesting composed behaviors: + +```rust +fn once_in_a_blue_moon(In(input): In, moon: Res) -> ShouldRun { + if moon.is_blue() { + input + } else { + ShouldRun::No + } +} + +app + .add_system(foo.with_run_criteria( + "every_other_time".pipe(once_in_a_blue_moon.system()) + ) +``` + +### Ambiguity Detection and Resolution + +While the new executor is now much easier to reason about, it does introduce a new class of error: "system order ambiguities". When two systems interact with the same data, but have no explicit ordering defined, the output they produce is non-deterministic (and often not what the author intended). + +Consider the following app: + +```rust +fn increment_counter(mut counter: ResMut) { + *counter += 1; +} + +fn print_every_other_time(counter: Res) { + if *counter % 2 == 0 { + println!("ran"); + } +} + +app + .add_system(increment_counter.system()) + .add_system(print_every_other_time.system()) +``` + +The author clearly intended `print_every_other_time` to run every other update. However, due to the fact that these systems have no order defined, they could run in a different order each update and create a situation where nothing is printed over the course of two updates: + +``` +UPDATE +- increment_counter (counter now equals 1) +- print_every_other_time (nothing printed) +UPDATE +- print_every_other_time (nothing printed) +- increment_counter (counter now equals 2) +``` + +The old executor would have implicitly forced `increment_counter` to run first because it conflicts with `print_every_other_time` and it was inserted first. But the new executor requires you to be explicit here (which we believe is a good thing). + +To help detect this class of error, we built an opt-in tool that detects these ambiguities and logs them: + +```rust +// add this resource to your App to enable ambiguity detection +app.insert_resource(ReportExecutionOrderAmbiguities) +``` + +Then when we run our App, we will see the following message printed to our terminal: + +``` +Execution order ambiguities detected, you might want to add an explicit dependency relation between some of these systems: + * Parallel systems: + -- "&app::increment_counter" and "&app::print_every_other_time" + conflicts: ["usize"] +``` + +The ambiguity detector found a conflict and mentions that adding an explicit dependency would resolve the conflict: + +```rust +app + .add_system(increment_counter.system().label("increment")) + .add_system(print_every_other_time.system().after("increment")) +``` + +There _are_ some cases where ambiguities are _not_ a bug, such as operations on unordered collection like `Assets`. This is why we don't enable the detector by default. You are free to just ignore these ambiguities, but if you want to suppress the messages in the detector (without defining a dependency), you can add your systems to an "ambiguity set": + +```rust +app + .add_system(a.system().in_ambiguity_set("foo")) + .add_system(b.system().in_ambiguity_set("foo")) +``` + +I want to stress that this is totally optional. Bevy code should be ergonomic and "fun" to write. If sprinkling ambiguity sets everywhere isn't your cup of tea, just don't worry about it! + +We are also actively seeking feedback on the new executor. We believe that the new implementation is easier to understand and encourages self-documenting code. The improved parallelism is also nice! But we want to hear from users (both new users starting fresh and old users porting their codebases to the new executor). This space is all about design tradeoffs and feedback will help us ensure we made the right calls. + +## Reliable change detection + +
authors: @Davier, @bjorn3, @alice-i-cecile, @cart
+ +Global change detection, the ability to run queries on the Changed/Added status of any ECS component or resource, just got a major usability boost: changes are now detected across frames/updates: + +```rust +// This is still the same change detection api we all know and love, +// the only difference is that it "just works" in every situation. +fn system(query: Query>) { + // iterates all entities whose A component has changed since + // the last run of this system + for e in query.iter() { + } +} +``` + +Global change detection was already a feature that set Bevy apart from other ECS frameworks, but now it is completely "fool proof". It works as expected regardless of system ordering, stage membership, or system run criteria. + +The old behavior was "systems detect changes that ocurred in systems that ran before them this frame". This was because we used a `bool` to track when each component/resource is added/modified. This flag was cleared for each component at the end of the frame. As a result, users had to be very careful about order of operations, and using features like "system run criteria" could result in dropped changes if systems didn't run on a given update. + +We now use a clever "world tick" design that allows systems to detect changes that happened at _any_ point in time since their last run. + +## States V2 + +
authors: @TheRawMeatball
+ +The [last Bevy release](https://bevyengine.org/news/bevy-0-4) added States, which enabled developers to run groups of ECS systems according to the value of a `State` resource. Systems could be run according to "state lifecycle events", such as on_enter, on_update, and on_exit. States make things like separate "loading screen" and "in game" logic easier to encode in Bevy ECS. + +The old implementation largely worked, but it had a number of quirks and limitations. First and foremost, it required adding a new `StateStage`, which cut down on parallelism, increased boilerplate, and forced ordering where it wasn't required. Additionally, some of the lifecycle events didn't always behave as expected. + +The new {{rust_type(type="struct" crate="bevy_ecs" mod="schedule" version="0.5.0" name="State" no_mod=true)}} implementation is built on top of the new parallel executor's SystemSet and RunCriteria features, for a much more natural, flexible, and parallel api that builds on existing concepts instead of creating new ones: + +```rust +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +enum AppState { + Menu, + InGame, +} + +fn main() { + App::build() + .add_state(AppState::Menu) + .add_system_set(SystemSet::on_enter(AppState::Menu).with_system(setup_menu.system())) + .add_system_set(SystemSet::on_update(AppState::Menu).with_system(menu_logic.system())) + .add_system_set(SystemSet::on_exit(AppState::Menu).with_system(cleanup_menu.system())) + .add_system_set(SystemSet::on_enter(AppState::InGame).with_system(setup_game.system())) + .add_system_set( + SystemSet::on_update(AppState::InGame) + .with_system(game_logic.system()) + .with_system(more_game_logic.system()) + ) + .run(); +} +``` + +States now use a "stack-based state machine" model. This opens up a number of options for state transitions: + +```rust +fn system(mut state: ResMut>) { + // Queues up a state change that pushes a new state on to the + // stack (preserving previous states) + state.push(AppState::InGame).unwrap(); + + // Queues up a state change that removes the current state on + // the stack and reverts to the previous state + state.pop().unwrap(); + + // Queues up a state change that overwrites the current state at + // the "top" of the stack + state.set(AppState::InGame).unwrap(); + + // Queues up a state change that replaces the entire stack of states + state.replace(AppState::InGame).unwrap(); +} +``` + +Just like the old implementation, state changes are applied in the same frame. This means it is possible to transition from states `A->B->C` and run the relevant state lifecycle events without skipping frames. This builds on top of "looping run criteria", which we also use for our "fixed timestep" implementation (and which you can use for your own run criteria logic). + +## Event Ergonomics + +
authors: @TheRawMeatball
+ +Events now have a first-class shorthand syntax for easier consumption: + +```rust +// Old Bevy 0.4 syntax +fn system(mut reader: Local>, events: Res>) { + for event in reader.iter(&events) { + } +} + +// New Bevy 0.5 syntax +fn system(mut reader: EventReader) { + for event in reader.iter() { + } +} +``` + +There is also now a symmetrical `EventWriter` api: + +```rust +fn system(mut writer: EventWriter) { + writer.send(SomeEvent { ... }) +} +``` + +The old "manual" approach is still possible via `ManualEventReader`: + +```rust +fn system(mut reader: Local>, events: Res>) { + for event in reader.iter(&events) { + } +} +``` + +## Rich Text + +
authors: @tigregalis
+ +Text can now have "sections", each with their own style / formatting. This makes text much more flexible, while still respecting the text layout rules: + +![rich_text](rich_text.png) + +This is accomplished using the new "text section" api: + +```rust +commands + .spawn_bundle(TextBundle { + text: Text { + sections: vec![ + TextSection { + value: "FPS: ".to_string(), + style: TextStyle { + font: asset_server.load("FiraSans-Bold.ttf"), + font_size: 90.0, + color: Color::WHITE, + }, + }, + TextSection { + value: "60.03".to_string(), + style: TextStyle { + font: asset_server.load("FiraMono-Medium.ttf"), + font_size: 90.0, + color: Color::GOLD, + }, + }, + ], + ..Default::default() + }, + ..Default::default() + }) +``` + +## HIDPI Text + +
authors: @blunted2night
+ +Text is now rendered according to the current monitor's scale factor. This gives nice, crisp text at any resolution. + +![hidpi_text](hidpi_text.png) + +## Render Text in 2D World Space + +
authors: @CleanCut, @blunted2night
+ +Text can now be spawned into 2D scenes using the new `Text2dBundle`. This makes it easier to do things like "draw names above players". + + + +## World To Screen Coordinate Conversions + +
authors: @aevyrie
+ +It is now possible to convert world coordinates to a given camera's screen coordinates using the new `Camera::world_to_screen()` function. Here is an example of this feature being used to position a UI element on top of a moving 3d object. + + + +## 3D Orthographic Camera + +
authors: @jamadazi
+ +Orthographic cameras can now be used in 3D! This is useful for things like CAD applications and isometric games. + +![ortho_3d](ortho_3d.png) + +## Orthographic Camera Scaling Modes + +
authors: @jamadazi
+ +Prior to **Bevy 0.5**, Bevy's orthographic camera had only one mode: "window scaling". It would adapt the projection according to the vertical and horizontal size of the window. This works for some styles of games, but other games need arbitrary window-independent scale factors or scale factors defined by either horizontal or vertical window sizes. + +**Bevy 0.5** adds a new `ScalingMode` option to `OrthographicCamera`, which enables developers to customize how the projection is calculated. + +It also adds the ability to "zoom" the camera using `OrthographicProjection::scale`. + +## Flexible Camera Bindings + +
authors: @cart
+ +Bevy used to "hack in" camera bindings for each RenderGraph PassNode. This worked when there was only one binding type (the combined `ViewProj` matrix), but many shaders require other camera properties, such as the world space position. + +In Bevy 0.5 we removed the "hack" in favor of the `RenderResourceBindings` system used elsewhere. This enables shaders to bind arbitrary camera data (with any set or binding index) and only pull in the data they need. + +The new PBR shaders take advantage of this feature, but custom shaders can also use it. + +```glsl +layout(set = 0, binding = 0) uniform CameraViewProj { + mat4 ViewProj; +}; +layout(set = 0, binding = 1) uniform CameraPosition { + vec3 CameraPos; +}; +``` + +## Render Layers + +
authors: @schell
+ +Sometimes you don't want a camera to draw everything in a scene, or you want to temporarily hide a set of things in the scene. **Bevy 0.5** adds a `RenderLayer` system, which gives developers the ability to add entities to layers by adding the `RenderLayers` component. + +Cameras can also have a {{rust_type(type="struct" crate="bevy_render" mod="camera" version="0.5.0" name="RenderLayers" no_mod=true)}} component, which determines what layers they can see. + +```rust +// spawn a sprite on layer 0 +commands + .spawn_bundle(SpriteBundle { + material: materials.add(Color::rgb(1.0, 0.5, 0.5).into()), + transform: Transform::from_xyz(0.0, -50.0, 1.0), + sprite: Sprite::new(Vec2::new(30.0, 30.0)), + }) + .insert(RenderLayers::layer(0)); +// spawn a sprite on layer 1 +commands + .spawn_bundle(SpriteBundle { + material: materials.add(Color::rgb(1.0, 0.5, 0.5).into()), + transform: Transform::from_xyz(0.0, -50.0, 1.0), + sprite: Sprite::new(Vec2::new(30.0, 30.0)), + }) + .insert(RenderLayers::layer(1)); +// spawn a camera that only draws the sprite on layer 1 +commands + .spawn_bundle(OrthographicCameraBundle::new_2d()); + .insert(RenderLayers::layer(1)); +``` + +## Sprite Flipping + +
authors: @zicklag
+ +Sprites can now be easily (and efficiently) flipped along the x or y axis: + +![sprite_flipping](sprite_flipping.png) + +```rust +commands.spawn_bundle(SpriteBundle { + material: material.clone(), + transform: Transform::from_xyz(150.0, 0.0, 0.0), + ..Default::default() +}); +commands.spawn_bundle(SpriteBundle { + material, + transform: Transform::from_xyz(-150.0, 0.0, 0.0), + sprite: Sprite { + // Flip the logo to the left + flip_x: true, + // And don't flip it upside-down ( the default ) + flip_y: false, + ..Default::default() + }, + ..Default::default() +}); +``` + +## Color Spaces + +
authors: @mockersf
+ +{{rust_type(type="enum" crate="bevy_render" mod="color" version="0.5.0" name="Color" no_mod=true)}} is now internally represented as an enum, which enables lossless (and correct) color representation. This is a significant improvement over the previous implementation, which internally converted all colors to linear sRGB (which could cause precision issues). Colors are now only converted to linear sRGB when they are sent to the GPU. We also took this opportunity to fix some incorrect color constants defined in the wrong color space. + +```rust +pub enum Color { + /// sRGBA color + Rgba { + /// Red component. [0.0, 1.0] + red: f32, + /// Green component. [0.0, 1.0] + green: f32, + /// Blue component. [0.0, 1.0] + blue: f32, + /// Alpha component. [0.0, 1.0] + alpha: f32, + }, + /// RGBA color in the Linear sRGB colorspace (often colloquially referred to as "linear", "RGB", or "linear RGB"). + RgbaLinear { + /// Red component. [0.0, 1.0] + red: f32, + /// Green component. [0.0, 1.0] + green: f32, + /// Blue component. [0.0, 1.0] + blue: f32, + /// Alpha component. [0.0, 1.0] + alpha: f32, + }, + /// HSL (hue, saturation, lightness) color with an alpha channel + Hsla { + /// Hue component. [0.0, 360.0] + hue: f32, + /// Saturation component. [0.0, 1.0] + saturation: f32, + /// Lightness component. [0.0, 1.0] + lightness: f32, + /// Alpha component. [0.0, 1.0] + alpha: f32, + }, +} +``` + +## Wireframes + +
authors: @Neo-Zhixing
+ +Bevy can now draw wireframes using the opt-in `WireframePlugin` + +![wireframe](wireframe.png) + +These can either be enabled globally or per-entity by adding the new `Wireframe` component. + +## Simple 3D Game Example: Alien Cake Addict + +
authors: @mockersf
+ +This example serves as a quick introduction to building 3D games in Bevy. It shows how to spawn scenes, respond to input, implement game logic, and handle state transitions. Pick up as many cakes as you can! + +![alien_cake_addict](alien_cake_addict.png) + +## Timer Improvements + +
authors: @kokounet
+ +The {{rust_type(type="struct" crate="bevy_core" version="0.5.0" name="Timer" no_mod=true)}} struct now internally uses {{rust_type(type="struct" crate="std" mod="time" name="Duration" no_mod=true plural=true)}} instead of using `f32` representations of seconds. This both increases precision and makes the api a bit nicer to look at. + +```rust +fn system(mut timer: ResMut, time: Res