Bevy 0.14
Posted on July 4, 2024 by Bevy Contributors
Thanks to 256 contributors, 993 pull requests, community reviewers, and our generous donors, we're happy to announce the Bevy 0.14 release on crates.io!
For those who don't know, Bevy is a refreshingly simple data-driven game engine built in Rust. You can check out our Quick Start Guide to try it today. It's free and open source forever! You can grab the full source code on GitHub. Check out Bevy Assets for a collection of community-developed plugins, games, and learning resources.
To update an existing Bevy App or Plugin to Bevy 0.14, check out our 0.13 to 0.14 Migration Guide.
Since our last release a few months ago we've added a ton of new features, bug fixes, and quality of life tweaks, but here are some of the highlights:
- Virtual Geometry: Preprocess meshes into "meshlets", enabling efficient rendering of huge amounts of geometry
- Sharp Screen Space Reflections: Approximate real time raymarched screen space reflections
- Depth of Field: Cause objects at specific depths to go "out of focus", mimicking the behavior of physical lenses
- Per-Object Motion Blur: Blur objects moving fast relative to the camera
- Volumetric Fog / Lighting: Simulates fog in 3d space, enabling lights to produce beautiful "god rays"
- Filmic Color Grading: Fine tune tonemapping in your game with a complete set of filmic color grading tools
- PBR Anisotropy: Improve rendering of surfaces whose roughness varies along the tangent and bitangent directions of a mesh, such as brushed metal and hair
- Auto Exposure: Configure cameras to dynamically adjust their exposure based on what they are looking at
- PCF for Point Lights: Smooth out point light shadows, improving their quality
- Animation blending: Our new low-level animation graph adds support for animation blending, and sets the stage for first- and third-party graphical, asset-driven animation tools.
- ECS Hooks and Observers: Automatically (and immediately) respond to arbitrary events, such as component addition and removal
- Better colors: type-safe colors make it clear which color space you're operating in, and offer an awesome array of useful methods.
- Computed states and substates: Modeling complex app state is a breeze with these type-safe extensions to our
States
abstraction. - Rounded corners: Rounding off one of
bevy_ui
's roughest edges, you can now procedurally set the corner radius on your UI elements.
For the first time, Bevy 0.14 was prepared using a release candidate process to help ensure that you can upgrade right away with peace of mind. We've worked closely with both plugin authors and ordinary users to catch critical bugs, round the rough corners off our new features, and refine the migration guide. As we prepared fixes, we've shipped new release candidates on crates.io, letting core ecosystem crates update and listening closely for show-stopping problems. Thank you so much to everyone who helped out: these efforts are a vital step towards making Bevy something that teams large and small can trust to work reliably.
Virtual Geometry (Experimental) #
- Authors: @JMS55, @atlv24, @zeux, @ricky26
- PR #10164
After several months of hard work, we're super excited to bring you the experimental release of a new virtual geometry feature!
This new rendering feature works much like Unreal Engine 5's Nanite renderer. You can take a very high-poly mesh, preprocess it to generate a MeshletMesh
during build time, and then at runtime render huge amounts of geometry - much more than Bevy's standard renderer can support. No explicit LODs are needed - it's all automatic, and near seamless.
This feature is still a WIP, and comes with several constraints compared to Bevy's standard renderer, so be sure to read the docs and report any bugs you encounter. We still have a lot left to do, so look forward to more performance improvements (and associated breaking changes) in future releases!
Note that this feature does not use GPU "mesh shaders", so older GPUs are compatible for now. However, they are not recommended, and are likely to become unsupported in the near future.
In addition to the below user guide, checkout:
Users wanting to use virtual geometry should compile with the meshlet
cargo feature at runtime, and meshlet_processor
cargo feature at build time for preprocessing meshes into the special meshlet-specific format (MeshletMesh
) the meshlet renderer uses.
Enabling the meshlet feature unlocks a new module: bevy::pbr::experimental::meshlet
.
First step, add MeshletPlugin
to your app:
app.add_plugins(MeshletPlugin);
Next, preprocess your Mesh
into a MeshletMesh
. Currently, this needs to be done manually via MeshletMesh::from_mesh()
(again, you need the meshlet_processor
feature enabled). This step is fairly slow, and should be done once ahead of time, and then saved to an asset file. Note that there are limitations on the types of meshes and materials supported, make sure to read the docs.
Automatic GLTF/scene conversions via Bevy's asset preprocessing system is planned, but unfortunately did not make the cut in time for this release. For now, you'll have to come up with your own asset conversion and management system. If you come up with a good system, let us know!
Now, spawn your entities. In the same vein as MaterialMeshBundle
, there's a MaterialMeshletMeshBundle
, which uses a MeshletMesh
instead of the typical Mesh
.
commands.spawn(MaterialMeshletMeshBundle {
meshlet_mesh: meshlet_mesh_handle.clone(),
material: material_handle.clone(),
transform,
..default()
});
Lastly, a note on materials. Meshlet entities use the same Material
trait as regular mesh entities, however, the standard material methods are not used. Instead there are 3 new methods: meshlet_mesh_fragment_shader
, meshlet_mesh_prepass_fragment_shader
, and meshlet_mesh_deferred_fragment_shader
. All 3 methods of forward, forward with prepasses, and deferred rendering are supported.
Notice however that there is no access to vertex shaders. Meshlet rendering uses a hardcoded vertex shader that cannot be changed.
The actual fragment shader code for meshlet materials are mostly the same as fragment shaders for regular mesh entities. The key difference is that instead of this:
@fragment
fn fragment(vertex_output: VertexOutput) -> @location(0) vec4<f32> {
// ...
}
You should use this:
#import bevy_pbr::meshlet_visibility_buffer_resolve::resolve_vertex_output
@fragment
fn fragment(@builtin(position) frag_coord: vec4<f32>) -> @location(0) vec4<f32> {
let vertex_output = resolve_vertex_output(frag_coord);
// ...
}
Sharp Screen-Space Reflections #
- Authors: @pcwalton
- PR #13418
Drag this image to compare
Screen-space reflections (SSR) approximate real-time reflections by raymarching through the depth buffer and copying samples from the final rendered frame. Our initial implementation is relatively minimal, to provide a flexible base to build on, but is based on the production-quality raymarching code by Tomasz Stachowiak, one of the creators of the indie darling Bevy game Tiny Glade. As a result, there are a few caveats to bear in mind:
- Currently, this feature is built on top of the deferred renderer and is currently only supported in that mode. Forward screen-space reflections are possible albeit uncommon (though e.g. Doom Eternal uses them); however, they require tracing from the previous frame, which would add complexity. This patch leaves the door open to implementing SSR in the forward rendering path but doesn't itself have such an implementation.
- Screen-space reflections aren't supported in WebGL 2, because they require sampling from the depth buffer, which
naga
can't do because of a bug (sampler2DShadow
is incorrectly generated instead ofsampler2D
; this is the same reason why depth of field is disabled on that platform). - No temporal filtering or blurring is performed at all. For this reason, SSR currently only operates on very low-roughness / smooth surfaces.
- We don't perform acceleration via the hierarchical Z-buffer and reflections are traced at full resolution. As a result, you may notice performance issues depending on your scene and hardware.
To add screen-space reflections to a camera, insert the ScreenSpaceReflectionsSettings
component. In addition to ScreenSpaceReflectionsSettings
, DepthPrepass
, and DeferredPrepass
must also be present for the reflections to show up. Conveniently, the ScreenSpaceReflectionsBundle
bundles these all up for you! While the ScreenSpaceReflectionsSettings
comes with sensible defaults, it also contains several settings that artists can tweak.
Volumetric Fog and Volumetric Lighting (light shafts / god rays) #
- Authors: @pcwalton
- PR #13057
Not all fog is created equal. Bevy's existing implementation covers distance fog, which is fast, simple, and not particularly realistic.
In Bevy 0.14, this is supplemented with volumetric fog, based on volumetric lighting, which simulates fog using actual 3D space, rather than simply distance from the camera. As you might expect, this is both prettier and more computationally expensive!
In particular, this allows for the creation of stunningly beautiful "god rays" (more properly, crepuscular rays) shining through the fog.
Drag this image to compare
Bevy's algorithm, which is implemented as a postprocessing effect, is a combination of the techniques described in Scratchapixel and Alexandre Pestana's blog post. It uses raymarching (ported to WGSL by h3r2tic) in screen space, transformed into shadow map space for sampling and combined with physically-based modeling of absorption and scattering. Bevy employs the widely-used Henyey-Greenstein phase function to model asymmetry; this essentially allows light shafts to fade into and out of existence as the user views them.
To add volumetric fog to a scene, add VolumetricFogSettings
to the camera, and add VolumetricLight
to directional lights that you wish to be volumetric. VolumetricFogSettings
has numerous settings that allow you to define the accuracy of the simulation, as well as the look of the fog. Currently, only interaction with directional lights that have shadow maps is supported. Note that the overhead of the effect scales directly with the number of directional lights in use, so apply VolumetricLight
sparingly for the best results.
Try it hands on with our volumetric_fog
example.
Per-Object Motion Blur #
- Authors: @aevyrie, @torsteingrindvik
- PR #9924
We've added a post-processing effect that blurs fast-moving objects in the direction of motion. Our implementation uses motion vectors, which means it works with Bevy's built in PBR materials, skinned meshes, or anything else that writes motion vectors and depth. The effect is used to convey high speed motion, which can otherwise look like flickering or teleporting when the image is perfectly sharp.
Blur scales with the motion of objects relative to the camera. If the camera is tracking a fast moving object, like a vehicle, the vehicle will remain sharp, while stationary objects will be blurred. Conversely, if the camera is pointing at a stationary object, and a fast moving vehicle moves through the frame, only the fast moving object will be blurred.
The implementation is configured with camera shutter angle, which corresponds to how long the virtual shutter is open during a frame. In practice, this means the effect scales with framerate, so users running at high refresh rates aren't subjected to over-blurring.
You can enable motion blur by adding MotionBlurBundle
to your camera entity, as shown in our motion blur
example.
Filmic Color Grading #
- Authors: @pcwalton
- PR #13121
Artists want to get exactly the right look for their game, and color plays a huge role.
To support this, Bevy's existing tonemapping tools have been extended to include a complete set of filmic color grading tools. In addition to a base tonemap, you can now configure:
- White point adjustment. This is inspired by Unity's implementation of the feature, but simplified and optimized. Temperature and tint control the adjustments to the x and y chromaticity values of CIE 1931. Following Unity, the adjustments are made relative to the D65 standard illuminant in the LMS color space.
- Hue rotation: converts the RGB value to HSV, alters the hue, and converts back.
- Color correction: allows the gamma, gain, and lift values to be adjusted according to the standard ASC CDL combined function. This can be done separately for shadows, midtones and highlights To avoid abrupt color changes, a small crossfade is used between the different sections of the image.
We've followed Blender's implementation as closely as possible to ensure that what you see in your modelling software matches what you see in the game.
We've provided a new, color_grading
example, with a shiny GUI to change all the color grading settings. Perfect for copy-pasting into your own game's dev tools and playing with the settings! Note that these settings can all be changed at runtime: giving artists control over the exact mood of the scene, or shift it dynamically based on weather or time of day.
Auto Exposure #
- Authors: @Kurble, @alice-i-cecile
- PR #12792
Since Bevy 0.13, you can configure the EV100 of a camera, which allows you to adjust the exposure of the camera in a physically based way. This also allows you to dynamically change the exposure values for various effects. However, this is a manual process and requires you to adjust the exposure values yourself.
Bevy 0.14 introduces Auto Exposure, which automatically adjusts the exposure of your camera based on the brightness of the scene. This can be useful when you want to create the feeling of a very high dynamic range, since your eyes also adjust to large changes in brightness. Note that this is not a replacement for hand-tuning the exposure values, rather an additional tool that you can use to create dramatic effects when brightness changes rapidly. Check out this video recorded from the example to see it in action!
Bevy's Auto Exposure is implemented by making a histogram of the scene's brightness in a post processing step. The exposure is then adjusted based on the average of the histogram. Because the histogram is calculated using a compute shader, Auto Exposure is not available on WebGL. It's also not enabled by default, so you need to add the AutoExposurePlugin
to your app.
Auto Exposure is controlled by the AutoExposureSettings
component, which you can add to your camera entity. You can configure a few things:
- A relative range of F-stops that the exposure can change by.
- The speed at which the exposure changes.
- An optional metering mask, which allows you to, for example, give more weight to the center of the image.
- An optional histogram filter, which allows you to ignore very bright or very dark pixels.
Fast Depth of Field #
- Authors: @pcwalton, @alice-i-cecile, @Kurble
- PR #13009
In rendering, depth of field is an effect that mimics the limitations of physical lenses. By virtue of the way light works, lenses (like that of the human eye or a film camera) can only focus on objects that are within a specific range (depth) from them, causing all others to be blurry and out of focus.
Bevy now ships with this effect, implemented as a post-processing shader. There are two options available: a fast Gaussian blur or a more physically accurate hexagonal bokeh technique. The bokeh blur is generally more aesthetically pleasing than the Gaussian blur, as it simulates the effect of a camera more accurately. The shape of the bokeh circles are determined by the number of blades of the aperture. In our case, we use a hexagon, which is usually considered specific to lower-quality cameras.
Drag this image to compare
The blur amount is generally specified by the f-number, which we use to compute the focal length from the film size and field-of-view. By default, we simulate standard cinematic cameras with an f/1 f-number and a film size corresponding to the classic Super 35 film format. The developer can customize these values as desired.
To see how this new API, please check out the dedicated depth_of_field
example.
PBR Anisotropy #
- Authors: @pcwalton
- PR #13450
Anisotropic materials change based on the axis of motion, such as how wood behaves very differently when working with versus against the grain. But in the context of physically-based rendering, anisotropy refers specifically to a feature that allows roughness to vary along the tangent and bitangent directions of a mesh. In effect, this causes the specular light to stretch out into lines instead of a round lobe. This is useful for modeling brushed metal, hair, and similar surfaces. Support for anisotropy is a common feature in major game and graphics engines; Unity, Unreal, Godot, three.js, and Blender all support it to varying degrees.
Drag this image to compare
Two new parameters have been added to StandardMaterial
: anisotropy_strength
and anisotropy_rotation
. Anisotropy strength, which ranges from 0 to 1, represents how much the roughness differs between the tangent and the bitangent of the mesh. In effect, it controls how stretched the specular highlight is. Anisotropy rotation allows the roughness direction to differ from the tangent of the model.
In addition to these two fixed parameters, an anisotropy texture can be supplied, in the linear texture format specified by KHR_materials_anisotropy
.
Like always, give it a spin at the corresponding anisotropy
example.
Percentage-Closer Filtering (PCF) for Point Lights #
- Authors: @pcwalton
- PR #12910
Percentage-closer filtering is a standard anti-aliasing technique used to get softer, less jagged shadows. To do so, we sample from the shadow map near the pixel of interest using a Gaussian kernel, averaging the results to reduce sudden transitions as we move in / out of the shadow.
As a result, Bevy's point lights now look softer and more natural, without any changes to end user code. As before, you can configure the exact strategy used to anti-alias your shadows by setting the ShadowFilteringMethod
component on your 3D cameras.
Drag this image to compare
Full support for percentage-closer shadows is in the works: testing and reviews for this are, like always, extremely welcome.
Subpixel Morphological Antialiasing (SMAA) #
- Authors: @pcwalton, @alice-i-cecile
- PR #13423
Jagged edges are the bane of game developers' existence: a wide variety of anti-aliasing techniques have been invented and are still in use to fix them without degrading image quality. In addition to MSAA, FXAA, and TAA, Bevy now implements SMAA: subpixel morphological antialiasing.
SMAA is a 2011 antialiasing technique that detects borders in the image, then averages nearby border pixels, eliminating the dreaded jaggies. Despite its age, it's been a continual staple of games for over a decade. Four quality presets are available: low, medium, high, and ultra. Due to advancements in consumer hardware, Bevy's default is high.
You can see how it compares to no anti-aliasing in the pair of images below:
Drag this image to compare
The best way to get a sense for the tradeoffs of the various anti-aliasing methods is to experiment with a test scene using the anti_aliasing
example or by simply trying it out in your own game.
Visibility Ranges (hierarchical levels of detail / HLODs) #
- Authors: @pcwalton, @cart
- PR #12916
When looking at objects far away, it's hard to make out the details! This obvious fact is just as true in rendering as it is in real life. As a result, using complex, high-fidelity models for distant objects is a waste: we can replace their meshes with simplified equivalents.
By automatically varying the level-of-detail (LOD) of our models in this way, we can render much larger scenes (or the same open world with a higher draw distance), swapping out meshes on the fly based on their proximity to the player. Bevy now supports one of the most foundational tools for this: visibility ranges (sometimes called hierarchical levels of detail, as it allows users to replace multiple meshes with a single object).
By setting the VisibilityRange
component on your mesh entities, developers can automatically control the range from the camera at which their meshes will appear and disappear, automatically fading between the two options using dithering. Hiding meshes happens early in the rendering pipeline, so this feature can be efficiently used for level of detail optimization. As a bonus, this feature is properly evaluated per-view, so different views can show different levels of detail.
Note that this feature differs from proper mesh LODs (where the geometry itself is simplified automatically), which will come later. While mesh LODs are useful for optimization and don't require any additional setup, they're less flexible than visibility ranges. Games often want to use objects other than meshes to replace distant models, such as octahedral or billboard imposters: implementing visibility ranges first gives users the flexibility to start implementing these solutions today.
You can see how this feature is used in the visibility_range
example.
ECS Hooks and Observers #
- Authors: @james-j-obrien, @cart
- PR #10839
As much as we love churning through homogeneous blocks of data in a tight loop here at Bevy, not every task is a perfect fit for the straightforward ECS model. Responding to changes and/or processing events are vital tasks in any application, and games are no exception.
Bevy already has a number of distinct tools to handle this:
- Buffered
Event
s: Multiple-producer, multiple-consumer queues. Flexible and efficient, but requires regular polling as part of a schedule. Events are dropped after two frames. - Change detection via
Added
andChanged
: Enable writing queries that can respond to added or changed components. These queries linearly scan the change state of components that match the query to see if they have been added or changed. RemovedComponents
: A special form of event that is triggered when a component is removed from an entity, or an entity with that component is despawned.
All of these (and systems themselves!) use a "pull"-style mechanism: events are sent regardless of whether or not anyone is listening, and listeners must periodically poll to ask if anything has changed. This is a useful pattern, and one we intend to keep around! By polling, we can process events in batch, getting more context and improving data locality (which makes the CPU go brr).
But it comes with some limitations:
- There is an unavoidable delay between an event being triggered and the response being processed
- Polling introduces a small (but non-zero) overhead every frame
This delay is the critical problem:
- Data (like indexes or hierarchies) can exist, even momentarily, in an invalid state
- We can't process arbitrary chain of events of recursive logic within a single cycle
To overcome these limitations, Bevy 0.14 introduces Component Lifecycle Hooks and Observers: two complementary "push"-style mechanisms inspired by the ever-wonderful flecs ECS.
Component Lifecycle Hooks
Component Hooks are functions (capable of interacting with the ECS World) registered for a specific component type (as part of the Component
trait impl), which are run automatically in response to "component lifecycle events", such as when that component is added, overwritten, or removed.
For a given component type, only one hook can be registered for a given lifecycle event, and it cannot be overwritten.
Hooks exist to enforce invariants tied to that component (ex: maintaining indices or hierarchy correctness). Hooks cannot be removed and always take priority over observers: they run before any on-add / on-insert observers, but after any on-remove observers. As a result, they can be thought of as something closer to constructors & destructors, and are more suitable for maintaining critical safety or correctness invariants. Hooks are also somewhat faster than observers, as their reduced flexibility means that fewer lookups are involved.
Let's examine a simple example where we care about maintaining invariants: one entity (with a Target
component) targeting another entity (with a Targetable
component).
#[derive(Component)]
struct Target(Option<Entity>);
#[derive(Component)]
struct Targetable {
targeted_by: Vec<Entity>
};
We want to automatically clear the Target
when the target entity is despawned: how do we do this?
If we were to use the pull-based approach (RemovedComponents
in this case), there could be a delay between the entity being despawned and the Target
component being updated. We can remove that delay with hooks!
Let's see what this looks like with a hook on Targetable
:
// Rather than a derive, let's configure the hooks with a custom
// implementation of Component
impl Component for Targetable {
const STORAGE_TYPE: StorageType = StorageType::Table;
fn register_component_hooks(hooks: &mut ComponentHooks) {
// Whenever this component is removed, or an entity with
// this component is despawned...
hooks.on_remove(|mut world, targeted_entity, _component_id|{
// Grab the data that's about to be removed
let targetable = world.get::<Targetable>(targeted_entity).unwrap();
for targeting_entity in targetable.targeted_by {
// Track down the entity that's targeting us
let mut targeting = world.get_mut::<Target>(targeting_entity).unwrap();
// And clear its target, cleaning up any dangling references
targeting.0 = None;
}
})
}
}
Observers
Observers are on-demand systems that listen to "triggered" events. These events can be triggered for specific entities or they can be triggered "globally" (no entity target).
In contrast to hooks, observers are a flexible tool intended for higher level application logic. They can watch for when user-defined events are triggered.
#[derive(Event)]
struct Message {
text: String
}
world.observe(|trigger: Trigger<Message>| {
println!("{}", trigger.event().message.text);
});
Observers are run immediately when an event they are watching for is triggered:
// All registered `Message` observers are immediately run here
world.trigger(Message { text: "Hello".to_string() });
If an event is triggered via a Command
, the observers will run when the Command
is flushed:
fn send_message(mut commands: Commands) {
// This will trigger all `Message` observers when this system's commands are flushed
commands.trigger(Message { text: "Hello".to_string() } );
}
Events can also be triggered with an entity target:
#[derive(Event)]
struct Resize { size: usize }
commands.trigger_targets(Resize { size: 10 }, some_entity);
You can trigger an event for more than one entity at the same time:
commands.trigger_targets(Resize { size: 10 }, [e1, e2]);
A "global" observer will be executed when any target is triggered:
fn main() {
App::new()
.observe(on_resize)
.run()
}
fn on_resize(trigger: Trigger<Resize>, query: Query<&mut Size>) {
let size = query.get_mut(trigger.entity()).unwrap();
size.value = trigger.event().size;
}
Notice that observers can use system parameters like Query
, just like a normal system.
You can also add observers that only run for specific entities:
commands
.spawn(Widget)
.observe(|trigger: Trigger<Resize>| {
println!("This specific widget entity was resized!");
});
Observers are actually just an entity with the Observer
component. All of the observe()
methods used above are just shorthand for spawning a new observer entity. This is what a "global" observer entity looks like:
commands.spawn(Observer::new(|trigger: Trigger<Message>| {}));
Likewise, an observer watching a specific entity looks like this
commands.spawn(
Observer::new(|trigger: Trigger<Resize>| {})
.with_entity(some_entity)
);
This API makes it easy to manage and clean up observers. It also enables advanced use cases, such as sharing observers across multiple targets!
Now that we know a bit about observers, lets examine the API through a simple gameplay-flavored example:Click to expand...
use bevy::prelude::*;
#[derive(Event)]
struct DealDamage {
damage: u8,
}
#[derive(Event)]
struct LoseLife {
life_lost: u8,
}
#[derive(Event)]
struct PlayerDeath;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Life(u8);
#[derive(Component)]
struct Defense(u8);
#[derive(Component, Deref, DerefMut)]
struct Damage(u8);
#[derive(Component)]
struct Monster;
fn main() {
App::new()
.add_systems(Startup, spawn_player)
.add_systems(Update, attack_player)
.observe(on_player_death);
}
fn spawn_player(mut commands: Commands) {
commands
.spawn((Player, Life(10), Defense(2)))
.observe(on_damage_taken)
.observe(on_losing_life);
}
fn attack_player(
mut commands: Commands,
monster_query: Query<&Damage, With<Monster>>,
player_query: Query<Entity, With<Player>>,
) {
let player_entity = player_query.single();
for damage in &monster_query {
commands.trigger_targets(DealDamage { damage: damage.0 }, player_entity);
}
}
fn on_damage_taken(
trigger: Trigger<DealDamage>,
mut commands: Commands,
query: Query<&Defense>,
) {
let defense = query.get(trigger.entity()).unwrap();
let damage = trigger.event().damage;
let life_lost = damage.saturating_sub(defense.0);
// Observers can be chained into each other by sending more triggers using commands.
// This is what makes observers so powerful ... this chain of events is evaluated
// as a single transaction when the first event is triggered.
commands.trigger_targets(LoseLife { life_lost }, trigger.entity());
}
fn on_losing_life(
trigger: Trigger<LoseLife>,
mut commands: Commands,
mut life_query: Query<&mut Life>,
player_query: Query<Entity, With<Player>>,
) {
let mut life = life_query.get_mut(trigger.entity()).unwrap();
let life_lost = trigger.event().life_lost;
life.0 = life.0.saturating_sub(life_lost);
if life.0 == 0 && player_query.contains(trigger.entity()) {
commands.trigger(PlayerDeath);
}
}
fn on_player_death(_trigger: Trigger<PlayerDeath>, mut app_exit: EventWriter<AppExit>) {
println!("You died. Game over!");
app_exit.send_default();
}
In the future, we intend to use hooks and observers to replace RemovedComponents
, make our hierarchy management more robust, create a first-party replacement for bevy_eventlistener
as part of our UI work, and build out relations. These are powerful, general-purpose tools: we can't wait to see the mad science the community cooks up with them!
When you're ready to get started, check out the component hooks
and observers
examples for more API details.
glTF KHR_texture_transform Support #
- Authors: @janhohenheim, @yrns, @Kanabenki
- PR #11904
The GLTF extension KHR_texture_transform
is used to transform a texture before applying it. By reading this extension, Bevy can now support a variety of new workflows. The one we want to highlight here is the ability to easily repeat textures a set number of times. This is useful for creating textures that are meant to be tiled across a surface. We will show how to do this using Blender, but the same principles apply to any 3D modeling software.
Let's look at an example scene that we've prepared in Blender, exported as a GLTF file and loaded into Bevy. We will first use the most basic shader node setup available in Blender:
The result is the following scene in Bevy:
Oh no! Everything is stretched! This is because we have set up our UVs in a way that maps the texture exactly once onto the mesh. There are a few ways to deal with this, but the most convenient is to add shader nodes that scale the texture so that it repeats:
The data of the Mapping
node is the one exported to KHR_texture_transform
. Look at the part in red. These scaling factors determine how often the texture should be repeated in the material. Tweaking this value for all textures results in a much nicer render:
UI Node Border Radius #
- Authors: @chompaa, @pablo-lua, @alice-i-cecile, @bushrat011899
- PR #12500
Border radius for UI nodes has been a long-requested feature for Bevy. Now it's supported!
To apply border radius to a UI node, there is a new component BorderRadius
. NodeBundle
and ButtonBundle
now have a field for this component called border_radius
:
commands.spawn(NodeBundle {
style: Style {
width: Val::Px(50.0),
height: Val::Px(50.0),
// We need a border to round a border, after all!
border: UiRect::all(Val::Px(5.0)),
..default()
},
border_color: BorderColor(Color::BLACK),
// Apply the radius to all corners.
// Optionally, you could use `BorderRadius::all`.
border_radius: BorderRadius {
top_left: Val::Px(50.0),
top_right: Val::Px(50.0),
bottom_right: Val::Px(50.0),
bottom_left: Val::Px(50.0),
},
..default()
});
There's a new example showcasing this new API, a screenshot of which can be seen below:
Animation Blending with the AnimationGraph
#
- Authors: @pcwalton, @rparrett, @james7132
- PR #11989
Through the eyes of a beginner, handling animation seems simple enough. Define a series of keyframes which transform the various bits of your model to match those poses. We slap some interpolation on there to smoothly move between them, and the user tells you when to start and stop the animation. Easy!
But modern animation pipelines (especially in 3D!) are substantially more complex: animators expect to be able to smoothly blend and programmatically alter different animations dynamically in response to gameplay. In order to capture this richness, the industry has developed the notion of an animation graph, which is used to couple the underlying state machine of a game object to the animations that should be playing, and the transitions that should occur between each of the various states.
A player character may be walking, running, slashing a sword, defending with a sword... to create a polished effect, animators need to be able to change between these animations smoothly, change the speed of the walk cycle to match the movement speed along the ground and even perform multiple animations at once!
In Bevy 0.14, we've implemented the Animation Composition RFC, providing a low-level API that brings code- and asset-driven animation blending to Bevy.
#[derive(Resource)]
struct ExampleAnimationGraph(Handle<AnimationGraph>);
fn programmatic_animation_graph(
mut commands: Commands,
asset_server: ResMut<AssetServer>,
animation_graphs: ResMut<Assets<AnimationGraph>>,
) {
// Create the nodes.
let mut animation_graph = AnimationGraph::new();
let blend_node = animation_graph.add_blend(0.5, animation_graph.root);
animation_graph.add_clip(
asset_server.load(GltfAssetLabel::Animation(0).from_asset("models/animated/Fox.glb")),
1.0,
animation_graph.root,
);
animation_graph.add_clip(
asset_server.load(GltfAssetLabel::Animation(1).from_asset("models/animated/Fox.glb")),
1.0,
blend_node,
);
animation_graph.add_clip(
asset_server.load(GltfAssetLabel::Animation(2).from_asset("models/animated/Fox.glb")),
1.0,
blend_node,
);
// Add the graph to our collection of assets.
let handle = animation_graphs.add(animation_graph);
// Hold onto the handle
commands.insert_resource(ExampleAnimationGraph(handle));
}
While it can be used to great effect today, most animators will ultimately prefer editing these graphs with a GUI. We plan to build a GUI on top of this API as part of the fabled Bevy Editor. Today, there are also third party solutions like bevy_animation_graph
.
To learn more and see what the asset-driven approach looks like, take a look at the new animation_graph
example.
Improved Color API #
- Authors: @viridia, @mockersf
- PR #12013
Colors are a huge part of building a good game: UI, effects, shaders and more all need fully-featured, correct and convenient color tools.
Bevy now supports a broad selection of color spaces, each with their own type (e.g. LinearRgba
, Hsla
, Oklaba
), and offers a wide range of fully documented operations on and conversions between them.
The new API is more error-resistant, more idiomatic and allows us to save work by storing the LinearRgba
type in our rendering internals. This solid foundation has allowed us to implement a wide range of useful operations, clustered into traits like Hue
or Alpha
, allowing you to operate over any color space with the required property. Critically, color mixing / blending is now supported: perfect for procedurally generating color palettes and working with animations.
use bevy_color::prelude::*;
// Each color space now corresponds to a specific type
let red = Srgba::rgb(1., 0., 0.);
// All non-standard color space conversions are done through the shortest path between
// the source and target color spaces to avoid a quadratic explosion of generated code.
// This conversion...
let red = Oklcha::from(red);
// ...is implemented using
let red = Oklcha::from(Oklaba::from(LinearRgba::from(red)));
// We've added the `tailwind` palette colors: perfect for quick-but-pretty prototyping!
// And the existing CSS palette is now actually consistent with the industry standard :p
let blue = tailwind::BLUE_500;
// The color space that you're mixing your colors in has a huge impact!
// Consider using the scientifically-motivated `Oklcha` or `Oklaba` for a perceptually uniform effect.
let purple = red.mix(blue, 0.5);
Most of the user-facing APIs still accept a colorspace-agnostic Color
(which now wraps our color-space types), while rendering internals use the physically-based LinearRgba
type. For an overview of the different color spaces, and what they're each good for, please check out our color space usage documentation.
bevy_color
offers a solid, type-safe foundation, but it's just getting started. If you'd like another color space or there are more things you'd like to do to your colors, please open an issue or PR and we'd be happy to help!
Also note that bevy_color
is intended to operate effectively as a stand-alone crate: feel free to take a dependency on it for your non-Bevy projects as well.
Extruded Shapes #
- Authors: @lynn-lumen
- PR #13270
Bevy 0.14 introduces an entirely new group of primitives: extrusions!
An extrusion is a 2D primitive (the base shape) that is extruded into a third dimension by some depth. The resulting shape is a prism (or in the special case of the circle, a cylinder).
// Create an ellipse with width 2 and height 1.
let my_ellipse = Ellipse::from_size(2.0, 1.0);
// Create an extrusion of this ellipse with a depth of 1.
let my_extrusion = Extrusion::new(my_ellipse, 1.);
All extrusions are extruded along the Z-axis. This guarantees that an extrusion of depth 0 and the corresponding base shape are identical, just as one would expect.
Measuring and Sampling
Since all extrusions with base shapes that implement Measured2d
implement Measured3d
, you can easily get the surface area or volume of an extrusion. If you have an extrusion of a custom 2D primitive, you can simply implement Measured2d
for your primitive and Measured3d
will be implemented automatically for the extrusion.
Likewise, you can sample the boundary and interior of any extrusion if the base shape of the extrusion implements ShapeSample<Output = Vec2>
and Measured2d
.
// Create a 2D capsule with radius 1 and length 2, extruded to a depth of 3
let extrusion = Extrusion::new(Capsule2d::new(1.0, 2.0), 3.0);
// Get the volume of the extrusion
let volume = extrusion.volume();
// Get the surface area of the extrusion
let surface_area = extrusion.area();
// Create a random number generator
let mut rng = StdRng::seed_from_u64(4);
// Sample a random point inside the extrusion
let interior_sample = extrusion.sample_interior(&mut rng);
// Sample a random point on the surface of the extrusion
let boundary_sample = extrusion.sample_boundary(&mut rng);
Bounding
You can also get bounding spheres and Axis Aligned Bounding Boxes (AABBs) for extrusions. If you have a custom 2D primitive that implements Bounded2d
, you can simply implement BoundedExtrusion
) for your primitive. The default implementation will give optimal results but may be slower than a solution fitted to your primitive.
Meshing
Extrusions do not exist in the world of maths only though. They can also be meshed and displayed on the screen!
And again, adding meshing support for your own primitives is made easy by Bevy! You simply need to implement meshing for your 2D primitive and then implement Extrudable
for your 2D primitive's MeshBuilder
.
When implementing Extrudable
, you have to provide information about whether segments of the perimeter of the base shape are to be shaded smooth or flat, and what vertices belong to each of these perimeter segments.
The Extrudable
trait allows you to easily implement meshing for extrusions of custom primitives. Of course, you could also implement meshing manually for your extrusion.
If you want to see a full implementation of this, you can check out the custom primitives example.
More Gizmos #
- Authors: @mweatherley, @Kanabenki, @MrGVSV, @solis-lumine-vorago, @alice-i-cecile
- PR #12211
Gizmos in Bevy allow developers to easily draw arbitrary shapes to help debugging or authoring content, but also to visualize specific properties of your scene, such has the AABB of your meshes.
In 0.14, several new gizmos have been added to bevy::gizmos
:
Rounded box gizmos
Rounded boxes and cubes are great for visualizing regions and colliders.
If you set the corner_radius
or edge_radius
to a positive value, the corners will be rounded outwards. However, if you provide a negative value, the corners will flip and curve inwards.
Grid Gizmos
New grid gizmo types were added with Gizmos::grid_2d
and Gizmos::grid
to draw a plane grid in either 2D or 3D, alongside Gizmos::grid_3d
to draw a 3D grid.
Each grid type can be skewed, scaled and subdivided along its axis, and you can separately control which outer edges to draw.
Coordinate Axes Gizmo
The new Gizmos::axes
add a simple way to show the position, orientation and scale of any object from its Transform
plus a base size. The size of each axis arrow is proportional to the corresponding axis scale in the provided Transform
.
Light Gizmos
The new ShowLightGizmo
component implements a retained gizmo to visualize lights for SpotLight
, PointLight
and DirectionalLight
. Most light properties are visually represented by the gizmos, and the gizmo color can be set to match the light instance or use a variety of other behaviors.
Similar to other retained gizmos, ShowLightGizmo
can be configured per-instance or globally with LightGizmoConfigGroup
.
Gizmo Line Styles and Joints #
- Authors: @lynn-lumen
- PR #12394
Previous versions of Bevy supported drawing line gizmos:
fn draw_gizmos(mut gizmos: Gizmos) {
gizmos.line_2d(Vec2::ZERO, Vec2::splat(-80.), RED);
}
However the only way to customize gizmos was to change their color, which may be limiting for some use cases. Additionally, the meeting points of two lines in a line strip, their joints, had little gaps.
As of Bevy 0.14, you can change the style of the lines and their joints for each gizmo config group:
fn draw_gizmos(mut gizmos: Gizmos) {
gizmos.line_2d(Vec2::ZERO, Vec2::splat(-80.), RED);
}
fn setup(mut config_store: ResMut<GizmoConfigStore>) {
// Get the config for you gizmo config group
let (config, _) = config_store.config_mut::<DefaultGizmoConfigGroup>();
// Set the line style and joints for this config group
config.line_style = GizmoLineStyle::Dotted;
config.line_joints = GizmoLineJoint::Bevel;
}
The new line styles can be used in both 2D and 3D and respect the line_perspective
option of their config groups.
Available line styles are:
GizmoLineStyle::Dotted
: draws a dotted line with each dot being a squareGizmoLineStyle::Solid
: draws a solid line - this is the default behavior and the only one available before Bevy 0.14
Similarly, the new line joints offer a variety of options:
GizmoLineJoint::Miter
, which extends both lines until they meet at a common miter point,GizmoLineJoint::Round(resolution)
, which will approximate an arc filling the gap between the two lines. Theresolution
determines the amount of triangles used to approximate the geometry of the arc.GizmoLineJoint::Bevel
, which connects the ends of the two joining lines with a straight segment, andGizmoLineJoint::None
, which uses no joints and leaves small gaps - this is the default behavior and the only one available before Bevy 0.14.
You can check out the 2D gizmos example, which demonstrates the use of line styles and joints!
UI Node Outline Gizmos #
- Authors: @pablo-lua, @nicopap, @alice-i-cecile
- PR #11237
When working with UI on the web, being able to quickly debug the size of all your boxes is wildly useful. We now have a native layout tool which adds gizmos outlines to all Nodes
An example of what the tool looks like after enabled
use bevy::prelude::*;
// You first have to add the DebugUiPlugin to your app
let mut app = App::new()
.add_plugins(bevy::dev_tools::ui_debug_overlay::DebugUiPlugin);
// In order to enable the tool at runtime, you can add a system to toggle it
fn toggle_overlay(
input: Res<ButtonInput<KeyCode>>,
mut options: ResMut<bevy::dev_tools::ui_debug_overlay::UiDebugOptions>,
) {
info_once!("The debug outlines are enabled, press Space to turn them on/off");
if input.just_pressed(KeyCode::Space) {
// The toggle method will enable the debug_overlay if disabled and disable if enabled
options.toggle();
}
}
// And add the system to the app
app.add_systems(Update, toggle_overlay);
Contextually Clearing Gizmos #
- Authors: @Aceeri
- PR #10973
Gizmos are drawn via an immediate mode API. This means that every update you draw all gizmos you want to display, and only those will be shown. Previously, update referred to "once every time the Main
schedule runs". This matches the frame rate, so it usually works great! But when you try to draw gizmos during FixedMain
, they will flicker or be rendered multiple times. In Bevy 0.14, this now just works!
This can be extended for use with custom schedules. Instead of a single storage, there now are multiple storages differentiated by a context type parameter. You can also set a type parameter on the Gizmos
system param to choose what storage to write to. You choose when storages you add get drawn or cleared: Any gizmos in the default storage (the ()
context) during the Last
schedule will be shown.
Query Joins #
- Authors: @hymm
- PR #11535
ECS Queries can now be combined, returning the data for entities that are contained in both queries.
fn helper_function(a: &mut Query<&A>, b: &mut Query<&B>){
let a_and_b: QueryLens<(Entity, &A, &B)> = a.join(b);
assert!(a_and_b.iter().len() <= a.len());
assert!(a_and_b.iter().len() <= b.len());
}
In most cases, you should continue to simply add more parameters to your original query. Query<&A, &B>
will generally be clearer than joining them later. But when a complex system or helper function backs you into a corner, query joins are there if you need them.
If you're familiar with database terminology, this is an "inner join". Other types of query joins are being considered. Maybe you could take a crack at the follow-up issue?
Computed States & Sub-States #
- Authors: @lee-orr, @marcelchampagne, @MiniaczQ, @alice-i-cecile
- PR #11426
Bevy's States
are a simple but powerful abstraction for managing the control flow of your app.
But as users' games (and non-game applications!) grew in complexity, their limitations became more apparent. What happens if we want to capture the notion of "in a menu", but then have different states corresponding to which submenu should be open? What if we want to ask questions like "is the game paused", but that question only makes sense while we're within a game?
Finding a good abstraction for this required several attempts and a great deal of both experimentation and discussion.
While your existing States
code will work exactly as before, there are now two additional tools you can reach for if you're looking for more expressiveness: computed states and sub states.
Let's begin with a simple state declaration:
#[derive(States, Clone, PartialEq, Eq, Hash, Debug, Default)]
enum GameState {
#[default]
Menu,
InGame {
paused: bool
},
}
The addition of pause
field means that simply checking for GameState::InGame
doesn't work ... the states are different depending on its value and we may want to distinguish between game systems that run when the game is paused or not!
Computed States
While we can simply do OnEnter(GameState::InGame{paused: true})
, we need to be able to reason about "while we're in the game, paused or not". To this end, we define the InGame
computed state:
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
struct InGame;
impl ComputedStates for InGame {
// Computed states can be calculated from one or many source states.
type SourceStates = GameState;
// Now, we define the rule that determines the value of our computed state.
fn compute(sources: GameState) -> Option<InGame> {
match sources {
// We can use pattern matching to express the
//"I don't care whether or not the game is paused" logic!
GameState::InGame {..} => Some(InGame),
_ => None,
}
}
}
Sub-States
In contrast, sub-states should be used when you want to keep manual control over the value through NextState
, but still bind their existence to some parent state.
#[derive(SubStates, Clone, PartialEq, Eq, Hash, Debug, Default)]
// This macro means that `GamePhase` will only exist when we're in the `InGame` computed state.
// The intermediate computed state is helpful for clarity here, but isn't required:
// you can manually `impl SubStates` for more control, multiple parent states and non-default initial value!
#[source(InGame = InGame)]
enum GamePhase {
#[default]
Setup,
Battle,
Conclusion
}
Initialization
Initializing our states is easy: just call the appropriate method on App
and all of the required machinery will be set up for you.
App::new()
.init_state::<GameState>()
.add_computed_state::<InGame>()
.add_sub_state::<GamePhase>()
Just like any other state, computed states and substates work with all of the tools you're used to: the State
and NextState
resources, OnEnter
, OnExit
and OnTransition
schedules and the in_state
run condition. Make sure to visit both examples for more information!
The only exception is that, for correctness, computed states cannot be mutated through NextState
. Instead, they are strictly derived from their parent states; added, removed and updated automatically during state transitions based on the provided compute
method.
All of Bevy's state tools are now found in a dedicated bevy_state
crate, which can be controlled via a feature flag. Yearning for the days of state stacks? Wish that there was a method for re-entering states? All of the state machinery relies only on public ECS tools: resources, schedules, and run conditions, making it easy to build on top of. We know that state machines are very much a matter of taste; so if our design isn't to your taste consider taking advantage of Bevy's modularity and writing your own abstraction or using one supplied by the community!
State Scoped Entities #
- Authors: @MiniaczQ, @alice-i-cecile, @mockersf
- PR #13649
State scoped entities is a pattern that naturally emerged in community projects. Bevy 0.14 has embraced it!
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, States)]
enum GameState {
#[default]
Menu,
InGame,
}
fn spawn_player(mut commands: Commands) {
commands.spawn((
// We mark this entity with the `StateScoped` component.
// When the provided state is exited, the entity will be
// deleted recursively with all children.
StateScoped(GameState::InGame)
SpriteBundle { ... }
))
}
App::new()
.init_state::<GameState>()
// We need to install the appropriate machinery for the cleanup code
// to run, once for each state type.
.enable_state_scoped_entities::<GameState>()
.add_systems(OnEnter(GameState::InGame), spawn_player);
By binding entity lifetime to a state during setup, we can dramatically reduce the amount of cleanup code we have to write!
State Identity Transitions #
- Authors: @MiniaczQ, @alice-i-cecile
- PR #13579
Users have sometimes asked for us to trigger exit and entry steps when moving from a state to itself. While this has its uses (refreshing is the core idea), it can be surprising and unwanted in other cases. We've found a compromise that lets users hook into this type of transition if it's something they need.
StateEventTransition
events will now include transitions from a state to itself, which will also propagate to all dependent ComputedStates
and SubStates
.
Because it is a niche feature, OnExit
and OnEnter
schedules will ignore the new identity transitions by default, but you can visit the new custom_transitions
example to see how you can bypass or change that behavior!
GPU Frustum Culling #
- Authors: @pcwalton
- PR #12889
Bevy's rendering stack is often CPU-bound: by shifting more work onto the GPU, we can better balance the load and render more shiny things faster. Frustum culling is an optimization technique that automatically hides objects that are outside of a camera's view (its frustum). In Bevy 0.14, users can choose to have this work performed on the GPU, depending on the performance characteristics of their project.
Two new components are available to control frustum culling: GpuCulling
and NoCpuCulling
. Attach the appropriate combination of these components to a camera, and you're set.
commands.spawn((
Camera3dBundle::default(),
// Enable GPU frustum culling (does not automatically disable CPU frustum culling).
GpuCulling,
// Disable CPU frustum culling.
NoCpuCulling
));
World Command Queue #
- Authors: @james7132, @james-j-obrien
- PR #11823
Working with Commands
when you have exclusive world access has always been a pain. Create a CommandQueue
, generate a Commands
out of that, send your commands and then apply it? Not exactly the most intuitive solution.
Now, you can access the World
's own command queue:
let mut world = World::new();
let mut commands = world.commands();
commands.spawn(TestComponent);
world.flush_commands();
While this isn't the most performant approach (just apply the mutations directly to the world and skip the indirection), this API can be great for quickly prototyping with or easily testing your custom commands. It is also used internally to power component lifecycle hooks and observers.
As a bonus, one-shot systems now apply their commands (and other deferred system params) immediately when run! We already have exclusive world access: why introduce delays and subtle bugs?
Reduced Multi-Threaded Execution Overhead #
- Authors: @chescock, @james7132
- PR #11906
The largest source of overhead in Bevy's multithreaded system executor is from thread context switching, i.e. starting and stopping threads. Each time a thread is woken up it can take up to 30us if the cache for the thread is cold. Minimizing these switches is an important optimization for the executor. In this cycle we landed two changes that show improvements for this:
Run the multi-threaded executor at the end of each system task
The system executor is responsible for checking that the dependencies for a system have run already and evaluating the run criteria and then running a task for that system. The old version of the multithreaded executor ran as a separate task that was woken up after each task completed. This would sometimes cause a new thread to be woken up for the executor to process the system completing.
By changing it so the system task tries to run the multithreaded executor after each system completes, we ensure that the multithreaded executor always runs on a thread that is already awake. This prevents one source of context switches. In practice this reduces the number of context switches per a Schedule
run by 1-3 times, for an improvement of around 30us per schedule. When an app has many schedules, this can add up!
Combined Event update system
There used to be one instance of the "event update system" for each event type. With just the DefaultPlugins
, that results in 20+ instances of the system.
Each instance ran very quick, so the overhead of spawning the system tasks and waking up threads to run all these systems dominated the time it took for the First
schedule to run. So combining all these into one system avoids this overhead and makes the First
schedule run much faster. In testing this made running the schedule go from 140us to 25us. Again, not a huge win, but we're all about saving every microsecond we can!
Decouple BackgroundColor
from UiImage
#
- Authors: @benfrankel
- PR #11165
UI images can now be given solid background colors:
The BackgroundColor
component now works for UI images instead of applying a color tint on the image itself. You can still apply a color tint by setting UiImage::color
. For example:
commands.spawn((
ImageBundle {
image: UiImage {
handle: assets.load("logo.png"),
color: DARK_RED.into(),
..default()
},
..default()
},
BackgroundColor(ANTIQUE_WHITE.into()),
Outline::new(Val::Px(8.0), Val::ZERO, CRIMSON.into()),
));
Combined WinitEvent #
- Authors: @UkoeHB
- PR #12100
When handling inputs, the exact ordering of the events received is often very significant, even when the events are not the same type! Consider a simple drag-and-drop operation. When, exactly, did the user release the mouse button relative to the many tiny movements that they performed? Getting these details right goes a long way to a responsive, precise user experience.
We now expose the blanket WinitEvent
event stream, in addition to the existing separated event streams, which can be read and matched on directly whenever these problems arise.
Recursive Reflect Registration #
- Authors: @MrGVSV, @soqb, @cart, @james7132
- PR #5781
Bevy uses reflection in order to dynamically process data for things like serialization and deserialization. A Bevy app has a TypeRegistry
to keep track of which types exist. Users can register their custom types when initializing the app or plugin.
#[derive(Reflect)]
struct Data<T> {
value: T,
}
#[derive(Reflect)]
struct Blob {
contents: Vec<u8>,
}
app
.register_type::<Data<Blob>>()
.register_type::<Blob>()
.register_type::<Vec<u8>>()
In the code above, Data<Blob>
depends on Blob
which depends on Vec<u8>
, which means that all three types need to be manually registered— even if we only care about Data<Blob>
.
This is both tedious and error-prone, especially when these type dependencies are only used in the context of other types (i.e. they aren't used as standalone types).
In 0.14, any type that derives Reflect
will automatically register all of its type dependencies. So when we register Data<Blob>
, Blob
will be registered as well (which will register Vec<u8>
), thus simplifying our registration down to a single line:
app.register_type::<Data<Blob>>()
Note that removing the registration for Data<Blob>
now also means that Blob
and Vec<u8>
may not be registered either, unless they were registered some other way. If those types are needed as standalone types, they should be registered separately.
Rot2
Type for 2D Rotations #
- Authors: @Jondolf, @IQuick143, @tguichaoua
- PR #11658
Ever wanted to work with rotations in 2D and get frustrated with having to choose between quaternions and a raw f32
? Us too!
We've added a convenient Rot2
type for you, with plenty of helper methods. Feel free to replace that helper type you wrote, and submit little PRs for any useful functionality we're missing.
Rot2
is a great complement to the Dir2
type (formerly Direction2d
). The former represents an angle, while the latter is a unit vector. These types are similar but not interchangeable, and the choice of representation depends heavily on the task at hand. You can rotate a direction using direction = rotation * Dir2::X
. To recover the rotation, use Dir2::X::rotation_to(direction)
or in this case the helper Dir2::rotation_from_x(direction)
.
While these types aren't used widely within the engine yet, we are aware of your pain and are evaluating proposals for how we can make working with transforms in 2D more straightforward and pleasant.
Alignment API for Transforms #
- Authors: @mweatherley
- PR #12187
Bevy 0.14 adds a new Transform::align
function, which is a more general form of Transform::look_to
, which allows you to specify any local axis you want to use for the main and secondary axes.
This allows you to do things like point the front of a spaceship at a planet you're heading toward while keeping the right wing pointed in the direction of another ship. or point the top of a ship in the direction of the tractor beam pulling it in, while the front rotates to match the bigger ship's direction.
Lets consider a ship where we're going to use the front of the ship and the right wing as local axes:
// point the local negative-z axis in the global Y axis direction
// point the local x-axis in the global Z axis direction
transform.align(Vec3::NEG_Z, Vec3::Y, Vec3::X, Vec3::Z)
align
will move it to match the desired positions as closely as possible:
Note that not all rotations can be constructed and the documentation explains what happens in such scenarios.
Random Sampling of Shapes and Directions #
- Authors: @13ros27, @mweatherley, @lynn-lumen
- PR #12484
In the context of game development, it's often helpful to have access to random values, whether that's in the interest of driving behavior for NPCs, creating effects, or just trying to create variety. To help support this, a few random sampling features have been added to bevy_math
, gated behind the rand
feature. These are primarily geometric in nature, and they come in a couple of flavors.
First, one can sample random points from the boundaries and interiors of a variety of mathematical primitives:
In code, this can be performed in a couple different ways, using either the sample_interior
/sample_boundary
or interior_dist
/boundary_dist
APIs:
use bevy::math::prelude::*;
use rand::{Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
let sphere = Sphere::new(1.5);
// Instantiate an Rng:
let rng = &mut ChaCha8Rng::seed_from_u64(7355608);
// Using these, sample a random point from the interior of this sphere:
let interior_pt: Vec3 = sphere.sample_interior(rng);
// or from the boundary:
let boundary_pt: Vec3 = sphere.sample_boundary(rng);
// Or, if we want a lot of points, we can use a Distribution instead...
// to sample 100000 random points from the interior:
let interior_pts: Vec<Vec3> = sphere.interior_dist().sample_iter(rng).take(100000).collect();
// or 100000 random points from the boundary:
let boundary_pts: Vec<Vec3> = sphere.boundary_dist().sample_iter(rng).take(100000).collect();
Note that these methods explicitly require an Rng
object, giving you control over the randomization strategy and seed.
The currently supported shapes are as follows:
2D: Circle
, Rectangle
, Triangle2d
, Annulus
, Capsule2d
.
3D: Sphere
, Cuboid
, Triangle3d
, Tetrahedron
, Cylinder
, Capsule3d
, and extrusions of sampleable 2D shapes (Extrusion
).
Similarly, the direction types (Dir2
, Dir3
, Dir3A
) and quaternions (Quat
) can now be constructed randomly using from_rng
:
use bevy::math::prelude::*;
use rand::{random, Rng, SeedableRng};
use rand_chacha::ChaCha8Rng;
// Instantiate an Rng:
let rng = &mut ChaCha8Rng::seed_from_u64(7355608);
// Get a random direction:
let direction = Dir3::from_rng(rng);
// Similar, but requires left-hand type annotations or inference:
let another_direction: Dir3 = rng.gen();
// Using `random` to grab a value using implicit thread-local rng:
let yet_another_direction: Dir3 = random();
Tools for Profiling GPU Performance #
- Authors: @LeshaInc
- PR #9135
While Tracy already lets us measure CPU time per system, our GPU diagnostics are much weaker. In Bevy 0.14 we've added support for two classes of rendering-focused statistics via the RenderDiagnosticsPlugin
:
- Timestamp queries: how long did specific bits of work take on the GPU?
- Pipeline statistics: information about the quantity of work sent to the GPU.
While it may sound like timestamp queries are the ultimate diagnostic tool, they come with several caveats. Firstly, they vary quite heavily from frame-to-frame as GPUs dynamically ramp up and down clock speed due to workload (idle gaps in GPU work, e.g., a bunch of consecutive barriers, or the tail end of a large dispatch) or the physical temperature of the GPU. To get an accurate measurement, you need to look at summary statistics: mean, median, 75th percentile and so on.
Secondly, while timestamp queries will tell you how long something takes, but it will not tell you why things are slow. For finding bottlenecks, you want to use a GPU profiler from your GPU vendor (Nvidia's NSight, AMD's RGP, Intel's GPA or Apple's XCode). These tools will give you much more detailed stats about cache hit rate, warp occupancy, and so on. On the other hand they lock your GPU's clock to base speeds for stable results, so they won't give you a good indicator of real world performance.
RenderDiagnosticsPlugin
tracks the following pipeline statistics, recorded in Bevy's DiagnosticsStore
: Elapsed CPU time, Elapsed GPU time, Vertex shader invocations, Fragment shader invocations, Compute shader invocations, Clipper invocations, and Clipper primitives.
You can also track individual render/compute passes, groups of passes (e.g. all shadow passes), and individual commands inside passes (like draw calls). To do so, instrument them using methods from the RecordDiagnostics
trait.
New Geometric Primitives #
- Authors: @vitorfhc, @Chubercik, @andristarr, @spectria-limina, @salvadorcarvalhinho, @aristaeus, @mweatherley
- PR #12508
Geometric shapes find a variety of applications in game development, ranging from rendering simple items to the screen for display / debugging to use in colliders, physics, raycasting, and more.
For this, geometric shape primitives were introduced in Bevy 0.13, and work on this area has continued with Bevy 0.14, which brings the addition of Triangle3d
and Tetrahedron
3D primitives, along with Rhombus
, Annulus
, Arc2d
, CircularSegment
, and CircularSector
2D primitives. As usual, these each have methods for querying geometric information like perimeter, area, and volume, and they all support meshing (where applicable) as well as gizmo display.
Improve Point
and rename it to VectorSpace
#
- Authors: @mweatherley, @bushrat011899, @JohnTheCoolingFan, @NthTensor, @IQuick143, @alice-i-cecile
- PR #12747
Linear algebra is used everywhere in games, and we want to make sure it's easy to get right. That's why we've added a new VectorSpace
trait, as part of our work to make bevy_math
more general, expressive, and mathematically sound. Anything that implements VectorSpace
behaves like a vector. More formally, the trait requires that implementations satisfy the vector space axioms for vector addition and scalar multiplication. We've also added a NormedVectorSpace
trait, which includes an api for distance and magnitude.
These traits underpin the new curve and shape sampling apis. VectorSpace
is implemented for f32
, the glam
vector types, and several of the new color-space types. It completely replaces bevy_math::Point
.
The splines module in Bevy has been lacking some features for a long time. Splines are extremely useful in game development, so improving them would improve everything that uses them.
The biggest addition is NURBS support! It is a variant of a B-Spline with much more parameters that can be tweaked to create specific curve shapes. We also added a LinearSpline
, which can be used to put straight line segments in a curve. CubicCurve
now acts as a sequence of curve segments to which you can add new pieces, so you can mix various spline types together to form a single path.
2D Mesh Wireframes #
- Authors: @msvbg, @IceSentry
- PR #12135
Wireframe materials are used to render the individual edges and faces of a mesh. They are often used as a debugging tool to visualize geometry, but can also be used for various stylized effects. Bevy supports displaying 3D meshes as wireframes, but lacked the ability to do this for 2D meshes until now.
To render your 2D mesh as a wireframe, add Wireframe2dPlugin
to your app and a Wireframe2d
component to your sprite. The color of the wireframe can be configured per-object by adding the Wireframe2dColor
component, or globally by inserting a Wireframe2dConfig
resource.
For an example of how to use the feature, have a look at the new wireframe_2d example:
Custom Reflect Field Attributes #
- Authors: @MrGVSV
- PR #11659
One of the features of Bevy's reflection system is the ability to attach arbitrary "type data" to a type. This is most often used to allow trait methods to be called dynamically. However, some users saw it as an opportunity to do other awesome things.
The amazing bevy-inspector-egui used type data to great effect in order to allow users to configure their inspector UI per field:
use bevy_inspector_egui::prelude::*;
use bevy_reflect::Reflect;
#[derive(Reflect, Default, InspectorOptions)]
#[reflect(InspectorOptions)]
struct Slider {
#[inspector(min = 0.0, max = 1.0)]
value: f32,
}
Taking inspiration from this, Bevy 0.14 adds proper support for custom attributes when deriving Reflect
, so users and third-party crates should no longer need to create custom type data specifically for this purpose. These attributes can be attached to structs, enums, fields, and variants using the #[reflect(@...)]
syntax, where the ...
can be any expression that resolves to a type implementing Reflect
.
For example, we can use Rust's built-in RangeInclusive
type to specify our own range for a field:
use std::ops::RangeInclusive;
use bevy_reflect::Reflect;
#[derive(Reflect, Default)]
struct Slider {
#[reflect(@RangeInclusive<f32>::new(0.0, 1.0))]
// Since this accepts any expression,
// we could have also used Rust's shorthand syntax:
// #[reflect(@0.0..=1.0_f32)]
value: f32,
}
Attributes can then be accessed dynamically using TypeInfo
:
let TypeInfo::Struct(type_info) = Slider::type_info() else {
panic!("expected struct");
};
let field = type_info.field("value").unwrap();
let range = field.get_attribute::<RangeInclusive<f32>>().unwrap();
assert_eq!(*range, 0.0..=1.0);
This feature opens up a lot of possibilities for things built on top of Bevy's reflection system. And by making it agnostic to any particular usage, it allows for a wide range of use cases, including aiding editor work down the road.
In fact, this feature has already been put to use by bevy_reactor
to power their custom inspector UI:
#[derive(Resource, Debug, Reflect, Clone, Default)]
pub struct TestStruct {
pub selected: bool,
#[reflect(@ValueRange::<f32>(0.0..1.0))]
pub scale: f32,
pub color: Srgba,
pub position: Vec3,
pub unlit: Option<bool>,
#[reflect(@ValueRange::<f32>(0.0..10.0))]
pub roughness: Option<f32>,
#[reflect(@Precision(2))]
pub metalness: Option<f32>,
#[reflect(@ValueRange::<f32>(0.0..1000.0))]
pub factors: Vec<f32>,
}
Query Iteration Sorting #
- Authors: @Victoronz
- PR #13417
Bevy does not make any guarantees about the order of items. So if we wish to work with our query items in a certain order, we need to sort them! We might want to display the scores of the players in order, or ensure a consistent iteration order for the sake of networking stability. In 0.13 a sort could look like this:
#[derive(Component, Copy, Clone, Deref)]
pub struct Attack(pub usize)
fn handle_enemies(enemies: Query<(&Health, &Attack, &Defense)>) {
// An allocation!
let mut enemies: Vec<_> = enemies.iter().collect();
enemies.sort_by_key(|(_, atk, ..)| *atk)
for enemy in enemies {
work_with(enemy)
}
}
This can get especially unwieldy and repetitive when sorting within multiple systems. Even if we always want the same sort, different Query
types make it unreasonably difficult to abstract away as a user! To solve this, we implemented new sort methods on the QueryIter
type, turning the example into:
// To be used as a sort key, `Attack` now implements Ord.
#[derive(Component, Copy, Clone, Deref, PartialEq, Eq, PartialOrd, Ord)]
pub struct Attack(pub usize)
fn handle_enemies(enemies: Query<(&Health, &Attack, &Defense)>) {
// Still an allocation, but undercover.
for enemy in enemies.iter().sort::<&Attack>() {
work_with(enemy)
}
}
To sort our query with the Attack
component, we specify it as the generic parameter to sort
. To sort by more than one Component
, we can do so, independent of Component
order in the original Query
type: enemies.iter().sort::<(&Defense, &Attack)>()
The generic parameter can be thought of as being a lens or "subset" of the original query, on which the underlying sort is actually performed. The result is then internally used to return a new sorted query iterator over the original query items. With the default sort
, the lens has to be fully Ord
, like with slice::sort
. If this is not enough, we also have the counterparts to the remaining 6 sort methods from slice
!
The generic lens argument works the same way as with Query::transmute_lens
. We do not use filters, they are inherited from the original query. The transmute_lens
infrastructure has some nice additional features, which allows for this:
fn handle_enemies(enemies: Query<(&Health, &Attack, &Defense, &Rarity)>) {
for enemy in enemies.iter().sort_unstable::<Entity>() {
work_with(enemy)
}
}
Because we can add Entity
to any lens, we can sort by it without including it in the original query!
These sort methods work with both Query::iter
and Query::iter_mut
! The rest of the of the iterator methods on Query
do not currently support sorting. The sorts return QuerySortedIter
, itself an iterator, enabling the use of further iterator adapters on it.
Keep in mind that the lensing does add some overhead, so these query iterator sorts do not perform the same as a manual sort on average. However, this strongly depends on workload, so best test it yourself if relevant!
SystemBuilder #
- Authors: @james-j-obrien
- PR #13123
Bevy users love systems, so we made a builder for their systems so they can build systems from within systems. At runtime, using dynamically-defined component and resource types!
While you can use SystemBuilder
as an ergonomic alternative to the SystemState
API for splitting the World
into disjoint borrows, its true values lies in its dynamic usage.
You can choose to create a different system based on runtime branches or, more intriguingly, the queries and so on can use runtime-defined component IDs. This is another vital step towards creating an ergonomic and safe API to work with dynamic queries, laying the groundwork for the devs who want to integrate scripting languages or bake in sophisticated modding support for their game.
// Start by creating builder from the world
let system = SystemBuilder::<()>::new(&mut world)
// Various helper methods exist to add `SystemParam`.
.resource::<R>()
.query::<&A>()
// Alternatively use `.param::<T>()` for any other `SystemParam` types.
.param::<MyParam>()
// Finish it all up with a call `.build`
.build(my_system);
// The parameters the builder is initialized with will appear first in the arguments.
let system = SystemBuilder::<(Res<R>, Query<&A>)>::new(&mut world)
.param::<MyParam>()
.build(my_system);
// Parameters like `Query` that implement `BuildableSystemParam` can use
// `.builder::<T>()` to build in place.
let system = SystemBuilder::<()>::new(&mut world)
.resource::<R>()
// This turns our query into a `Query<&A, With<B>>`
.builder::<Query<&A>>(|builder| { builder.with::<B>(); })
.param::<MyParam>()
.build(my_system);
world.run_system_once(system);
Throttle Render Assets #
- Authors: @robtfm, @IceSentry, @mockersf
- PR #12622
Using a lot of assets? Uploading lots of bytes to the GPU in a short time might cause stutters due to the render world waiting for uploads to finish.
Often it's a more delightful experience if an application runs smoothly than if it stutters, and a few frames worth of delay before seeing an asset appear is often not even perceptible.
This experience is now possible:
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.insert_resource(RenderAssetBytesPerFrame::new(1_000_000_000)) // Tune to your situation by experimenting!
.run();
}
That's it! The number provided should be chosen by figuring out a nice trade-off between no stuttering and an acceptable delay.
This feature relies on assets knowing how many bytes they will occupy when sent to the GPU. Currently this is known by images and meshes, with more assets types expected to be able to report this in the future.
StandardMaterial UV Channel Selection #
- Authors: @geckoxx
- PR #13200
Previously, StandardMaterial always defaulted to using ATTRIBUTE_UV_0 for each texture except lightmap, which isn't flexible enough for a lot of gltf files. In Bevy 0.14, a new UvChannel enum was added allowing you to select the channel to use for each texture in StandardMaterial.
Here's a before and after showing the support of ATTRIBUTE_UV_1 across textures:
Remove limit on RenderLayers #
- Authors: @tychedelia, @robtfm, @UkoeHB
- PR #13317
Render layers are used to quickly toggle the visibility of sets of objects, and control which objects can be seen by which cameras. This can be useful for things like debug views, gear preview screens, toggle-able diegetic UI and so on.
Before Bevy 0.14 the membership was defined by a bitmask which had limited slots available. Now, there is no longer any practical limit to how many layers you can define, which is particularly helpful for creative coding applications like nannou! We've made sure to keep the common case fast, but now use a growable mask that will allocate space for additional layers as needed. Remember, there's still a cost to check visibility per layer, but this allows for more dynamic uses where layers can be created on demand without worrying about going over a limit.
on_unimplemented
Diagnostics #
- Authors: @bushrat011899, @alice-i-cecile, @Themayu
- PR #13347
Bevy takes full advantage of the powerful type system Rust provides, but with that power can often come confusion when even minor mistakes are made.
use bevy::prelude::*;
struct MyResource;
fn main() {
App::new()
.insert_resource(MyResource)
.run();
}
Running the above will produce a compiler error, let's see why...Click to expand...
error[E0277]: the trait bound `MyResource: Resource` is not satisfied
--> example.rs:6:32
|
6 | App::new().insert_resource(MyResource).run();
| --------------- ^^^^^^^^^^ the trait `Resource` is not implemented for `MyResource`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `Resource`:
AccessibilityRequested
ManageAccessibilityUpdates
bevy::a11y::Focus
DiagnosticsStore
FrameCount
bevy::prelude::Axis<T>
WinitActionHandlers
ButtonInput<T>
and 127 others
note: required by a bound in `bevy::prelude::App::insert_resource`
--> /bevy/crates/bevy_app/src/app.rs:537:31
|
537 | pub fn insert_resource<R: Resource>(&mut self, resource: R) -> &mut Self {
| ^^^^^^^^ required by this bound in `App::insert_resource`
The compiler suggests we use a different type that implements Resource
, or that we implement the trait on MyResource
. The former doesn't help us at all, and the latter fails to mention the available derive macro.
With the release of Rust 1.78, Bevy can now provide more direct messages for certain types of errors during compilation using diagnostic attributes.
error[E0277]: `MyResource` is not a `Resource`
--> example.rs:6:32
|
6 | App::new().insert_resource(MyResource).run();
| --------------- ^^^^^^^^^^ invalid `Resource`
| |
| required by a bound introduced by this call
|
= help: the trait `Resource` is not implemented for `MyResource`
= note: consider annotating `MyResource` with `#[derive(Resource)]`
= help: the following other types implement trait `Resource`:
AccessibilityRequested
...
Now, the error message has a more approachable entry point, and a new note
section pointing to the derive macro for resources. If Bevy's suggestions aren't the solution to your problem, the rest of the compiler error is still included just in case.
These diagnostics have been implemented for various traits across Bevy, and we hope to improve this experience as new features are added to Rust. For example, we'd really like to improve the experience of working with tuples of Component
's, but we're not quite there yet. You can read more about this change in the pull request and associated issue.
Motion Vectors and TAA for Animated Meshes #
- Authors: @pcwalton
- PR #13572
Back in Bevy 0.11 we added Temporal Anti Aliasing (TAA), which uses Motion Vectors to determine how fast an object is moving. However, in Bevy 0.11 we only added Motion Vector support for "static" meshes, meaning TAA did not work for animated meshes using skeletal animation or morph targets.
In Bevy 0.14, we implemented Per-Object Motion Blur, which also uses Motion Vectors and therefore would have that same limitation.
Fortunately in Bevy 0.14 we implemented Motion Vectors for skinned meshes and meshes with morph targets, closing this gap and enabling TAA, Per-Object Motion Blur, and future Motion Vector features to work with animated meshes.
Improved Matrix Naming #
- Authors: @ricky26
- PR #13489
Game engines generally provide a set of matrices to perform space transformations in the game world. Commonly, the following spaces are used:
- Normalized Device Coordinates: used by the graphics API directly
- Clip Space: coordinates after projection but before perspective divide
- View Space: coordinates in the camera's view
- World Space: global coordinates (this is the one we most often talk about!)
- Model Space: (or local space) coordinates relative to an entity
A common example is the 'model view projection matrix', which is the transformation from model space to NDC space (peculiarly in this shorthand, the view matrix is often a transformation from world to view space, but the model matrix is a transformation from model (or local) space to world space). Usually, matrices are referred to as part of that shorthand, so for example, the projection matrix transforms from view coordinates to NDC coordinates.
In a couple of places, Bevy had a view matrix, which was the transformation from view to world space (rather than from world to view space as above). Additionally, even when used consistently, the single-word shorthands are ambiguous and can cause confusion. We felt that a clearer convention was needed.
From now on, matrices in Bevy are named y_from_x
, for example world_from_local
, which would denote the transformation from local to world-space coordinates. One tidy benefit of this is that the inverse matrices are named x_from_y
, and when multiplying between spaces, it's easy to see that it's correct.
For example, instead of writing:
let model_view_projection = projection * view * model;
You would now write:
let clip_from_local = clip_from_view * view_from_world * world_from_local;
Typed glTF Labels #
- Authors: @mockersf, @rparrett, @alice-i-cecile
- PR #13586
If you've been using glTF
files for your scenes or looked at an example that does you've might have seen the labels at the end of the asset path:
let model_pine = asset_server.load("models/trees/pine.gltf#Scene0");
let model_hen = asset_server.load("models/animals/hen.gltf#Scene0");
let animation_hen = asset_server.load("models/animals/hen.gltf#Aniamtion1"); // Oh no!
Notice the #Scene0
syntax at the end. The glTF format is able to contain many things in a single file, including several scenes, animations, lights, and more.
These labels are a way of telling Bevy which part of the file we're loading.
However this is prone to user-error, and it looks like an error snuck in! The hen animation got the label Aniamtion1
instead of Animation1
.
No more! The above can now be re-written like so:
let hen = "models/animals/hen.gltf"; // Can re-use this more easily too
let model_pine = asset_server.load(GltfAssetLabel::Scene(0).from_asset("models/trees/pine.gltf"));
let model_hen = asset_server.load(GltfAssetLabel::Scene(0).from_asset(hen));
let animation_hen = asset_server.load(GltfAssetLabel::Animation(0).from_asset(hen)); // No typo!
Check out glTF label docs
to know which parts you can query for.
winit v0.30 #
- Authors: @pietrosophya, @mockersf
- PR #13366
Winit v0.30 changed its API to support a trait based architecture instead of a plain event-based one. Bevy 0.14 now implements that new architecture, making the event loop handling easier to follow.
It's now possible to define a custom winit
user event, that can be used to trigger App updates, and that can be read inside systems to trigger specific behaviors. This is particularly useful to send events from outside the winit
event loop and manage them inside Bevy systems (see the window/custom_user_event.rs
example).
The UpdateMode
enum now accepts only two values: Continuous
and Reactive
. The latter exposes 3 new properties to enable reactivity to device, user, or window events. The previous UpdateMode::Reactive
is now equivalent to UpdateMode::reactive()
, while UpdateMode::ReactiveLowPower
maps to UpdateMode::reactive_low_power()
.
Idle
: the loop has not started yetRunning
(previously calledStarted
): the loop is runningWillSuspend
: the loop is going to be suspendedSuspended
: the loop is suspendedWillResume
: the loop is going to be resumed
Note: the Resumed
state has been removed since the resumed app is just Running
.
Scene, Mesh, and Material glTF Extras #
- Authors: @kaosat-dev
- PR #13453
The glTF 3D model file format allows passing additional user defined metadata in the extras properties, and in addition to the glTF extras at the primitive/node level , Bevy now has specific GltfExtras for:
- scenes: SceneGltfExtras injected at the scene level if any
- meshes: MeshGltfExtras, injected at the mesh level if any
- materials: MaterialGltfExtras, injected at the mesh level if any: ie if a mesh has a material that has gltf extras, the component will be injected there.
You can now easily query for these specific extras
fn check_for_gltf_extras(
gltf_extras_per_entity: Query<(
Entity,
Option<&Name>,
Option<&GltfSceneExtras>,
Option<&GltfExtras>,
Option<&GltfMeshExtras>,
Option<&GltfMaterialExtras>,
)>,
) {
// use the extras' data
for (id, name, scene_extras, extras, mesh_extras, material_extras) in
gltf_extras_per_entity.iter()
{
}
}
This makes passing information from programs such as Blender to Bevy via gltf files more spec compliant, and more practical!
Resource Entity Mapping in Scenes #
- Authors: @brandon-reinhart
- PR #13650
Bevy's DynamicScene
is a collection of resources and entities that can be serialized to create collections like prefabs or savegame data. When a DynamicScene is deserialized and written into a World - such as when a saved game is loaded - the dynamic entity identifiers inside the scene must be mapped to their newly spawned counterparts.
Previously, this mapping was only available to Entity identifiers stored on Components. In Bevy 0.14, Resources can reflect MapEntitiesResource
and implement the MapEntities
trait to get access to the EntityMapper
.
// This resource reflects MapEntitiesResource and implements the MapEntities trait.
#[derive(Resource, Reflect, Debug)]
#[reflect(Resource, MapEntitiesResource)]
struct TestResource {
entity_a: Entity,
entity_b: Entity,
}
// A simple and common use is a straight mapping of the old entity to the new.
impl MapEntities for TestResource {
fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
self.entity_a = entity_mapper.map_entity(self.entity_a);
self.entity_b = entity_mapper.map_entity(self.entity_b);
}
}
CompassQuadrant and CompassOctant #
- Authors: @BobG1983, @alice-i-cecile
- PR #13653
There are many instances in game development where its important to know the compass facing for a given direction. This is particularly true in 2D games that use four or eight direction sprites, or want to map analog input into discrete movement directions.
In order to make this easier the enums CompassQuadrant
(for a four-way division) and CompassOctant
(for an eight-way division) have been added with implementations to and From<Dir2>
for ease of use.
Support AsyncSeek
When Loading Assets #
- Authors: @BeastLe9enD
- PR #12547
Assets can be huge, and you don't always need all of the data contained in a single file.
Bevy allows you to add your own asset loaders. Starting in Bevy 0.14, you can now seek to an offset of your choice, reading partway through the file.
Perhaps you have the .celestial
file format which encodes the universe, but you want to only look at lil' asteroids which always appear at some offset:
#[derive(Default)]
struct UniverseLoader;
#[derive(Asset, TypePath, Debug)]
struct JustALilAsteroid([u8; 128]); // Each lil' asteroid uses this much data
impl AssetLoader for UniverseLoader {
type Asset = JustALilAsteroid;
type Settings = ();
type Error = std::io::Error;
async fn load<'a>(
&'a self,
reader: &'a mut Reader<'_>,
_settings: &'a (),
_load_context: &'a mut LoadContext<'_>,
) -> Result<JustALilAsteroid, Self::Error> {
// The universe is big, and our lil' asteroids don't appear until this offset
// in the celestial file format!
let offset_of_lil_asteroids = 5_000_000_000_000;
// Skip vast parts of the universe with the new async seek trait!
reader
.seek(SeekFrom::Start(offset_of_lil_asteroids))
.await?;
let mut asteroid_buf = [0; 128];
reader.read_exact(&mut asteroid_buf).await?;
Ok(JustALilAsteroid(asteroid_buf))
}
fn extensions(&self) -> &[&str] {
&["celestial"]
}
}
This works because Bevy's reader
type passed into the asset loader's load
function now implements AsyncSeek
.
Real world use cases might for example be:
- You have packed several assets in an archive and you wish to skip to an asset within and read that
- You are dealing with big datasets such as map data and you know where to extract some locations of interest
LoadState::Failed Now Has Error Info #
- Authors: @bugsweeper
- PR #12709
Rust prides itself on its error handling, and Bevy has been steadily catching up. Previously, when checking if an asset was loaded using AssetServer::get_load_state
, all you'd get back was a data-less LoadState::Failed
if something went wrong. Not very useful for debugging!
Now, a full AssetLoadError
is included, with 14 different variants telling you exactly what went wrong. Great for troubleshooting, and it opens the door to proper error handling in more complex apps.
AppExit
Errors #
- Authors: @Brezak, @alice-i-cecile
- PR #13022
When running an app, there might be many reasons to trigger an exit. Maybe the user has pressed the quit button, or the render thread has encountered an error and died. You might want to distinguish between these two situations and return an appropriate exit code from your application.
In Bevy 0.14, you can. The AppExit
event is now an enum with two variants: Success
and Error
. The error variant also holds a non-zero code, which you're allowed to use however you wish. Since AppExit
events now contain useful information, app runners and App::run
now return the event that resulted in the application exiting.
For plugin developers, App
has gained a new method, App::should_exit
, which will check if any AppExit
events were sent in the last two updates. To make sure AppExit::Success
events won't drown out useful error information, this method will return any AppExit::Error
events, even if they were sent after an AppExit::Success
.
Finally, AppExit
also implements the Termination
trait, so it can be returned from main.
use bevy::prelude::*;
fn exit_with_a_error_code(mut events: EventWriter<AppExit>) {
events.send(AppExit::from_code(42));
}
fn main() -> AppExit {
App::new()
.add_plugins(MinimalPlugins)
.add_systems(Update, exit_with_a_error_code)
.run() // There's no semicolon here, `run()` returns `AppExit`.
}
Make dynamic_linking a no-op on WASM targets #
- Authors: @james7132
- PR #12672
WASM does not support dynamic libraries that can be linked to during runtime. Before, Bevy would fail to compile if you enabled the dynamic_linking
feature.
$ cargo build --target wasm32-unknown-unknown --features bevy/dynamic_linking
error: cannot produce dylib for `bevy_dylib v0.13.2` as the target `wasm32-unknown-unknown` does not support these crate types
Now, Bevy will fallback to static linking for all WASM targets. If you enable dynamic_linking
for development, you no longer need to disable it for WASM.
Deprecate Dynamic Plugins #
- Authors: @BD103
- PR #13080
bevy_dynamic_plugin
was a tool added in Bevy's original 0.1 release: intended to serve as a tool for dynamically loading / linking Rust code for use with things like modding. Unfortunately, this feature didn't see much community uptake, and as a result had a vanishingly small number of contributions to refine and document it over the years.
Combined with a challenging, intrinsically unsafe API that was producing worrying failures for users, we've decided to deprecate bevy_dynamic_plugin
and will be removing it completely in Bevy 0.15. If you were a happy user of this, simply copy the rather-small crate into your own project and proceed as before.
We still think that both modding and hot-reloading code for faster development times are valuable use cases that Bevy should help support one day. Our hope is that by removing this as a first-party crate, we can spur on third-party experiments and avoid wasting users' time as they investigate a complex potential solution before concluding that it doesn't yet meet their needs.
Bevy Working Groups #
- Authors: @alice-i-cecile
- PR #13162
Bevy has a ton of incredibly talented contributors, so keeping track of what's going on and making informed decisions can be a real challenge. We're experimenting with working groups: ad hoc groups tackling harder issues by creating a design document, getting sign-off from the experts, and then implementing it. If you'd like to help make complex, high-impact changes to Bevy: join or form a working group!
What's Next? #
The features above may be great, but what else does Bevy have in flight? Peering deep into the mists of time (predictions are extra hard when your team is almost all volunteers!), we can see some exciting work taking shape:
- Better Scenes: Scenes are one of Bevy's core building blocks: designed to be a powerful tool for authoring levels and creating reusable game objects, whether they're a radio button widget or a monster. We're working on a new scene system with a new syntax that will make defining scenes in assets and in code more powerful and more pleasant. You can check out the(now slightly old) project kickoff discussion for more information. We're also very close to putting out a design document outlining our plans and the current state of the implementation.
- ECS Relations: Relations (a first-class feature for linking entities together) is wildly desired but remarkably complex, driving features and refactors to our ECS internals. The working group has been patiently laying out what we need to do and why in this RFC.
- Better Audio: Bevy's built-in audio solution has never really hit the right notes. The Better Audio working group is plotting a path forward.
- Contributing Book: Our documentation on how to contribute is scattered to the four corners of our repositories. By gathering this together, the Contributing Book working group hopes to make it easier to discover and maintain.
- Curve Abstraction: Curves come up all of the time in game dev, and the mathmagicians that make up the Curve Crew are designing a trait to unify and power them.
- Better Text: our existing text solution isn't up to the demands of modern UI. The "Lorem Ipsum" working group is looking into replacing it with a better solution.
- A Unified View on Dev Tools: In 0.14, we've added a stub
bevy_dev_tools
crate: a place for tools and overlays that speed up game development such as performance monitors, fly cameras, or in-game commands to spawn game objects. We're working on adding more tools, and creating a dev tool abstraction. This will give us a unified way to enable/disable, customize and group this grab bag of tools into toolboxes to create something like Quake console or VSCode Command Palette with tools from around the ecosystem. - Bevy Remote Protocol: Communicating with actively running Bevy games is an incredibly powerful tool for building editors, debuggers and other tools. We're developing a reflection-powered protocol to create a solution that's ready to power a whole ecosystem.
- A Modular, Maintainable Render Graph: Bevy's existing rendering architecture is already quite good at providing reusable renderer features like
RenderPhases
, batching, and draw commands. However, the render graph interface itself is one remaining pain points. Since it's distributed across many files the control flow is hard to understand, and its heavy use of ECS resources for passing around rendering data actively works against modularity. While the exact design hasn't been finalized (and feedback is very welcome!), we've been actively working to redesign the render graph in order to build up to a larger refactor of the renderer towards modularity and ease of use.
Support Bevy #
Bevy will always be free and open-source, but it isn't free to make! Because Bevy is free, we rely on the generosity of the Bevy community to fund our efforts. If you are a happy user of Bevy or you believe in our mission, please consider donating to the Bevy Foundation... every bit helps!
Contributors #
A huge thanks to the 256 contributors that made this release (and associated docs) possible! In random order:
- @miroim
- @vitorfhc
- @13ros27
- @andristarr
- @mrtolkien
- @atlv24
- @MrGVSV
- @SludgePhD
- @Wuketuke
- @AndrewDanial
- @thebluefish
- @waywardmonkeys
- @VictorBulba
- @Earthmark
- @GitGhillie
- @andriyDev
- @shanecelis
- @mintlu8
- @bushrat011899
- @TheCarton
- @RobWalt
- @NoahShomette
- @jake8655
- @sam-kirby
- @Olle-Lukowski
- @R081n
- @adithramachandran
- @msvbg
- @freiksenet
- @IQuick143
- @AldanTanneo
- @ricky26
- @torsteingrindvik
- @Chubercik
- @Themayu
- @umut-sahin
- @hut
- @JMS55
- @hi-names-nat
- @BobG1983
- @gagnus
- Fpgu
- @dependabot[bot]
- @Hexorg
- @A-Walrus
- @killercup
- @rparrett
- @Zeenobit
- @Bluefinger
- @Brezak
- @nicoburns
- @lee-orr
- ebola
- @JoshuaSchlichting
- @mrchantey
- @Aceeri
- @ramirezmike
- @mgi388
- @LuisFigueiredo73
- @benpinno
- @james-j-obrien
- @oli-obk
- @tguichaoua
- @SolarLiner
- @s-puig
- @dmlary
- @brandon-reinhart
- @ekropotin
- @Victoronz
- @janhohenheim
- @Xzihnago
- @infmagic2047
- @spooky-th-ghost
- @greytdepression
- @philpax
- @pablo-lua
- @rmsthebest
- @mockersf
- @UkoeHB
- @eira-fransham
- @chompaa
- @ghost
- @pkupper
- @porkbrain
- @tychedelia
- @Kanabenki
- @MScottMcBee
- @gabrielkryss
- @EmiOnGit
- @kristoff3r
- @imrn99
- @moonlightaria
- @geekvest
- @sampettersson
- @JoJoJet
- @JeanMertz
- @arcashka
- @Testare
- @Davier
- @SkiFire13
- @ArthurBrussee
- @IceSentry
- @zuiyu1998
- @snendev
- @MiniaczQ
- @soqb
- Alice Cecile
- @Gingeh
- @Weibye
- @viridia
- @MarcoMeijer
- @lambertsbennett
- @doonv
- @DGriffin91
- @BD103
- @forgemo
- @StephenTurley
- @kaosat-dev
- @mnmaita
- @Maximetinu
- @eidloi
- @yrns
- @daxpedda
- @Kurble
- @findmyhappy
- @inodentry
- @TimJentzsch
- @alice-i-cecile
- @eero-lehtinen
- @OneFourth
- @pcwalton
- @MonaMayrhofer
- @jgayfer
- @blukai
- @vertesians
- @geckoxx
- @james7132
- @theredfish
- @nzhao95
- @StrikeForceZero
- @spectria-limina
- @ChristopherBiscardi
- @gavlig
- @Multirious
- @mweatherley
- @TheNullicorn
- @lukaschod
- @salvadorcarvalhinho
- @ua-kxie
- @stinkytoe
- @Aztro-dev
- @bcolloran
- @awwsmm
- @TheRawMeatball
- @tomara-x
- @orzogc
- @matiqo15
- @TimLeach635
- @uwuPyxl
- @Soulghost
- @benfrankel
- @kornelski
- @paolobarbolini
- @notmd
- @mamekoro
- Franklin
- @simbleau
- @NixyJuppie
- @coolreader18
- @feyokorenhof
- @eerii
- @AmionSky
- @jkb0o
- @Shatur
- @stowmyy
- @chescock
- @hymm
- @ShadowMitia
- @pietrosophya
- @jnhyatt
- @Jondolf
- @jdm
- @TrialDragon
- @Remi-Godin
- @Friz64
- @dmyyy
- @rib
- @juliohq
- @stepancheg
- @nbielans
- @komadori
- @djeedai
- @ManevilleF
- @mghildiy
- @BeastLe9enD
- @JohnTheCoolingFan
- @kettle11
- @emilyselwood
- @cBournhonesque
- @aristaeus
- @chrisjuchem
- @allsey87
- @nicopap
- @tjamaan
- @gibletfeets
- @floppyhammer
- @honungsburk
- @CatThingy
- @jakobhellermann
- @aevyrie
- @jirisvd
- @CptPotato
- @NiklasEi
- @lynn-lumen
- @AxiomaticSemantics
- @Azorlogh
- @zeux
- @agiletelescope
- @Elabajaba
- @RobinKellnerVector
- @iiYese
- @ycysdf
- @Waridley
- @coreh
- @yyogo
- @targrub
- @marcelchampagne
- @tygyh
- @unknownue
- @TheNeikos
- @Vrixyz
- @MTFT-Games
- @SpecificProtagonist
- @Zoomulator
- @afonsolage
- @NthTensor
- @cart
- @maboesanman
- @IWonderWhatThisAPIDoes
- @re0312
- @66OJ66
- @theon
- @robtfm
- @NiseVoid
- Lukas Chodosevicius
- @superdump
- @oyasumi731
- @ameknite
- @franklinblanco
- @bugsweeper
- @Zeophlite
- @xStrom
- @ItsDoot
- @LeshaInc
- @maniwani
- @ickshonpe
Full Changelog #
The changes mentioned above are only the most appealing, highest impact changes that we've made this cycle. Innumerable bug fixes, documentation changes and API usability tweaks made it in too. For a complete list of changes, check out the PRs listed below.
Accessibility + Rendering #
Accessibility + Windowing #
Animation #
Rework animation to be done in two phases.
Fix docs for quaternion interpolation
Implement the
AnimationGraph
, allowing for multiple animations to be blended together.fix find_current_keyframe panic
Expose mutable Animation Clips
new example: sprite animation in response to an event
Make the component types of the new animation players clonable.
Added
get_main_animation
forAnimationTransitions
Animation + Assets #
Animation + Color + Math + Rendering #
Animation + Color + Rendering #
Animation + Rendering #
App #
Refactor App and SubApp internals for better separation
Added add_group to PluginGroupBuilder
Move PanicHandlerPlugin into bevy_app
Make
AppExit
more specific about exit reason.Simplify runner app exit code.
Update
App:is_plugin_added
to work insidePlugin::finish
andPlugin::clean
Fix
custom_loop
example to include plugin finalizationDeprecate dynamic plugins
Fix bevy_app not compiling without default features
Forward exit codes in default app runner
Let init_non_send_resource require FromWorld instead of Default
Add missing plugins to doc of DefaultPlugins
Fix is_plugin_added::<Self>() being true during build
App + ECS #
Move state installation methods from
bevy_app
tobevy_state
Ensure that events are updated even when using a bare-bones Bevy App (#13808)
Move
StateTransitionSteps
registration to states plugin
Assets #
Qualify embedded_asset expansion with $crate::
Fix example docs on embedded_asset macro
Parse missing mime types
Create imported_assets directory with full path
Improve file watcher error msg
Add a way to get a strong handle from an AssetId
Normalise root path in file_watcher
Remove the UpdateAssets and AssetEvents schedules
Add to_bits and from_bits functions to
AssetIndex
Add methods to directly load assets from World
add note about unloading assets from ram in wasm
Add extra_asset_source example
Use
.register_asset_source()
inextra_asset_source
exampleMove AssetEvents to Last
Fix doc comment on AssetActionMinimal
send Unused event when asset is actually unused
Use async-fn in traits rather than BoxedFuture
Make
AssetAction::Ignore
not copy assets toimported_assets
Add path function to ProcessContext
Removed Into<AssedId<T>> for Handle<T> as mentioned in #12600
Fix get_asset_paths not properly deleting empty folders (& recursive async functions)
Fix fetching assets in Web Workers
Allow converting mutable handle borrows to AssetId.
Add
AsyncSeek
trait toReader
to be able to seek inside asset loadersIgnore query parameters in AssetPaths when determining the extension
Error info has been added to LoadState::Failed
Add example for using .meta files
Fix a copy-paste typo doc
Fix extensionless image loading panic
Fix unfinished sentence in a comment in asset_settings example
Make
AssetMetaCheck
a field on the asset pluginbevy_asset: Add missing web-sys feature and cleanup unused ones
Misc asset code quality and docs
Use
load_with_settings
instead of manually overriding srgbness in examplesAdd more load_direct implementations
Make LoadContext use the builder pattern for loading dependent assets
Allow
AssetServer::load
to acquire a guard item.Add docs to bevy_gltf about loading parts of a Gltf asset
glTF labels: add enum to avoid misspelling and keep up-to-date list documented
Improvement of AssetServer::load documentation to help find a way to load from file with hash in filename
Avoid a panic when loading labelled assets
Add labels to Gltf Node and Mesh assets
Allow loading assets with custom async behavior
Provide more information when a filewatcher failure is hit.
Improve error handling for
AssetServer::add_async
Assets + Diagnostics #
Assets + ECS #
Assets + Reflection #
Assets + Rendering #
revert PointLightBundle to DirectionalLightBundle change made to asset_loading example between 0.12.1 and 0.13.0
Gltf loader now shows which file is missing pre baked tangents
Fix
ImageLoader
not being initialized withwebp
orpnm
featuresAllow setting RenderAssetUsages for gLTF meshes & materials during load
Fixed a bug where skybox ddsfile would crash from wgpu
Created loading screen example
Consolidate Render(Ui)Materials(2d) into RenderAssets
Added deref trait for Mesh2dHandle
fix normals computation for gltf
Add ImageFormatSetting::Guess to image loader
unload unused images that are RenderAssetUsages::RENDER_WORLD
add handling of all missing gltf extras: scene, mesh & materials
Improve MeshletMesh::from_mesh performance
Improve MeshletMesh::from_mesh performance further
Audio #
don't depend directly on oboe
Contribution guidelines for
bevy_audio
Fix leftover references to children when despawning audio entities
updated audio_source.rs documentation
Programmed soundtrack example
Adding explanation for loading additonal audio formats to example
Update to
rodio
0.18
Build-System #
Add a
[lints]
entry for workspace members missing itFix taplo CI - toml fmt
Check
cfg
during CI and fix feature typosAdd
typos
- Source code spell checkerCI: run long tasks on new macOS runners
add cancel in progress support to automated CI checks
Update cargo deny
Explicitly run
+nightly
for-Zcheck-cfg
pass in ci.Fix failures of typos and check-cfg
Quality-of-life updates for running CI locally
Fix duplicate dependencies on raw-window-handle
Fix minimal plugins in ci
CI testing: don't crash if screenshot manager resource is not available
Fix CI desktop mode patch
change file location for showcase patch for light
make align deterministic with a seeded random
make alien_cake_addict deterministic with a seeded random
check that patches are not broken
make example font_atlas_debug deterministic with a seeded random
Fix Ci failing over dead code in tests
Remove redundant doc_auto_config
Add repository field to bevy_utils_proc_macros
Fix wrong dependency in weekly ci
Fix strings not interpolating in weely ci run
Small CI tool improvements
tools: Refactor CI to use
argh
Create custom action for installing Linux dependencies
fail when an example doesn't set doc-scrape-examples
Remove unused nightly toolchain environmental variable
Bump crate-ci/typos from 1.20.8 to 1.20.9
Improve output of example showcase patches CI workflow
Small CI improvements
install rust target for arm ios simulator
Make dynamic_linking a no-op on wasm targets
Restructure
ci
modulesBump crate-ci/typos from 1.20.9 to 1.20.10
Small changes to
ci
toolExample setup for tooling
new format for ci config file
Update compile test to use ui_test 0.23
Bump crate-ci/typos from 1.20.10 to 1.21.0
Don't deploy docs when working on a fork
Fix
asset-source-website.patch
line numberUpdate release workflow pr body
Add
cargo ci
alias forci
toolRefactor
ci_testing
and separate it fromDevToolsPlugin
Regenerate light cluster patch file
Shader code paths
example showcase: keep the order of the shaders imported
Build-System + Cross-Cutting #
Build-System + Dev-Tools #
Build-System + ECS + Reflection #
Build-System + Meta #
Build-System + Rendering #
Color #
minor oklab/oklch doc nitpicks
Solve some oklaba inconsistencies
Implement maths and
Animatable
forSrgba
move wgsl color operations from bevy_pbr to bevy_render
Add color conversions #13224
Remove
ClampColor
Implement Color Operations for
Color
Added a Grey trait, and implementations on baked-in colors. Fixes #13206
Adds back in way to convert color to u8 array, implemented for the two RGB color types, also renames Color::linear to Color::to_linear.
Color + Gizmos #
Color + Gizmos + Rendering + Text + UI #
Color + Rendering #
bevy_color: adding 'palettes' module.
bevy_color
: Created a private traitStandardColor
bevy_color
: AddedXyza
Colour SpaceSimplified
bevy_color
Srgba
hex string parsingMade
bevy_color
a dependency ofbevy_render
Port
bevy_core_pipeline
toLinearRgba
bevy_color
: AddedHsva
andHwba
Modelsbevy_color
: AddLaba
to support Lab Color Modelbevy_color
: Added Color Conversion Mermaid DiagramDefine a prelude for bevy_color, and add it to bevy_internal
bevy_color::Color
convenience methodsbevy_color
: Add Oklch Color SpaceRe-export
basic
color palette viacss
color palettebevy_color
: Addsequence_dispersed
toHsla
,Lcha
,Oklcha
Reflect default in colorspaces in
bevy_color
bevy_color: Add Tailwind palette
Fix
Oklab
andOklch
color space inconsistencyAdd hue traits
Emissive is now LinearRgba on StandardMaterial
fix emissive value in StandardMaterial after swith to LinearRgba
Color + Rendering + UI #
Core #
Explain Camera2dBundle.projection needs to be set carefully
bevy_core: Derive useful traits on FrameCount
Cross-Cutting #
Set the logo and favicon for all of Bevy's published crates
Remove unnecessary executable flags from Rust source files
Forbid unsafe in most crates in the engine
Remove redundant imports
Clean up some low level dependencies
Fix some nightly Clippy lints
Fix some doc warnings
Fix beta lints
Fix uses of "it's" vs "its".
Fix Clippy lints on WASM
Switch monolithic lib to module re-exports
chore: fix some comments
Remove
version
field for non-publish crates and update descriptionsImprove
config_fast_builds.toml
Add
README.md
to all cratesDetermine msrv for every standalone bevy_* crate.
Revert "Add
on_unimplemented
Diagnostics to Most Public Traits"
Cross-Cutting + Dev-Tools + Gizmos #
Cross-Cutting + ECS #
Implement clone for most bundles.
Unrevert (vert?) "Add
on_unimplemented
Diagnostics to Most Public Traits"
Dev-Tools #
Fps overlay
Always spawn fps_overlay on top of everything
rename
debug_overlay
toui_debug_overlay
in bevy_dev_toolsremove close_on_esc
Use folder for example showcase reports and add show logs flag
Dev-Tools + Diagnostics #
Dev-Tools + Diagnostics + Rendering #
Dev-Tools + ECS + Networking #
Dev-Tools + Gizmos + UI #
Dev-Tools + Reflection #
Dev-Tools + Windowing #
Diagnostics #
Remove unnecessary wildcards from
LogPlugin
and convert warnings to errors.Make sysinfo diagnostic plugin optional
Replace bevy_log's tracing reexport with bevy_utils'
Add access to
App
withinLogPlugin::update_subscriber
Remove "features" feature
Simplified backtraces
fix deprecations from toml_edit
Handle NaNs in diagnostics
Fix unhandled null characters in Android logs
Remove bevy log's usage of non send resource
Improve tracing layer customization
Diagnostics + ECS #
Diagnostics + Rendering #
ECS #
Update documentation for WorldQuery and filters
Stepping disabled performance fix
Fix
SystemTypeSet::system_type
being out of sync withSystem::type_id
bevy_ecs address trivial cases of
unsafe_op_in_unsafe_fn
Loosen lifetime requirements for single-threaded
Scope::spawn
to match the multi-threaded version.Fix SimpleExecutor crash
Immediately apply deferred system params in System::run
Update docstrings for some Commands to use the correct type
Add Archetype::component_count
Implements conversion from
SystemId
toEntity
Remove downcast-rs as a dependency from bevy_ecs
Component Lifecycle Hooks and a Deferred World
Replace init_component_info with register_component_hooks
Document instability of Entity's internal representation
Move commands module into bevy::ecs::world
Use NonMaxUsize for non-component SparseSets
Improve components hooks docs
bevy_ecs: Fix up docs for
World::run_system
andWorld::run_system_with_input
Rewrite part of Commands rustdoc
Remove ComponentStorage and associated types
Remove initialize_resource<T> and friends
Clean up pointer use in BundleSpawner/BundleInserter
Implement MutUntyped::from(mut_typed)
Mention in docs about the query iteration order and result uniqueness.
Query Joins
SystemId should manually implement
Eq
Make a note about the performance of Query::is_empty
Fix inconsistency between Debug and serialized representation of Entity
Split ScheduleGraph::process_configs function (adopted)
Remove archetype_component_access from QueryState
Add into_ methods for EntityMut and EntityWorldMut that consume self.
Remove WorldCell
Update ecs query docs
Allow Commands to register systems
Adding some docs for archetype internals
Update safety comment for bundle removal
Added an
init_bundle
method toWorld
Add Debug to Has Query type
Implement QueryData for &Archetype and EntityLocation
Implement Clone for ManualEventReader
Add QueryState::contains, document complexity, and make as_nop pub(crate)
Store only the IDs needed for Query iteration
Fix typos
Fix typos in insert_or_spawn_batch/spawn_batch methods
Add
RemovedComponentEvents::iter
Remove unnecessary branch in query iteration
Add
EntityWorldMut::remove_by_id
Remove stepping from default features
Cluster small table/archetype into single Task in parallel iteration
Implement
From&lt;&amp;&#x27;w mut EntityMut&gt;
forEntityMut&lt;&#x27;w&gt;
Add archetypal to Access Debug impl
Optimize Event Updates
Update docs of
set_if_neq
andreplace_if_neq
Cleanup the multithreaded executor
fix: use try_insert instead of insert in bevy_ui to prevent panics when despawning ui nodes
Make SystemParam::new_archetype and QueryState::new_archetype unsafe functions
Fix doc when state is missing
Parallel event reader
Improve par_iter and Parallel
Use
ptr::from_ref
andptr::addr_eq
in macroAdd
#[track_caller]
toQuery
methodsBetter SystemId to Entity conversions
add schedule docs
Computed State & Sub States
Schedule resource mutation
Make one-shot example more noob friendly
Separate unrelated code to submodules in compute/sub-state examples
Separate state crate
State example
constrain WorldQuery::get_state to only use &Components
Implement
WorldQuery
andQueryData
onMut
.implement the full set of sort methods on QueryIter
Fix doc for Added, Changed
Implement a SystemBuilder for building SystemParams
Further improve docs for component hooks
simple Debug impls for query iterators
Refactor command application for more consistency
Fix unsoundness in
FilteredEntity{Ref,Mut}
variousget
methodsconstrain WorldQuery::init_state argument to ComponentInitializer
Update docs for NextState
Unify transition names to
exited
andentered
Add ability to clear all components on an entity via EntityWorldMut
Simplify state transitions
Combine transition systems of
Substates
Clean up substate code a bit
Add
on_unimplemented
Diagnostics to Most Public TraitsAdd
on_unimplemented
Diagnostics to Most Public Traits (#13347)Move utilities from examples to
bevy_state
and add concept of state-scoped entitiesGeneralize
StateTransitionEvent&lt;S&gt;
to allow identity transitionsAdd dynamic slice based variants of get_many_entities methods
Update crate metadata for bevy state
Clear messed up feature flag on AppExitStates impl
Fix EntityCommands::despawn docs
Add more granular system sets for state transition schedule ordering
fix docs around
StateTransition
and remove references to `apply_sta…Update serialize flag for bevy_ecs
Remove extra call to clear_trackers
Revert "constrain WorldQuery::init_state argument to ComponentInitial…
Fix minor typos in query join docs
Restore overwrite capabilities of
insert_state
Generalised ECS reactivity with Observers (#10839)
remove inaccurate warning from
in_state
Warn about missing
StatesPlugin
when installing statesobservers example doesn't follow standards
Update observer archetype flags for sparse components
feat(bevy_app): expose an API to perform updates for a specific sub-app.
Don't show
.to_bits
inDisplay
impl forEntity
Fixing par_read targetting 0.14 branch
AnyOf soundness fix
Emit a warning if the result of
EntityCommand::with_entity
is not usedadd missing sort_unstable_by_key to QueryIter
Add missing StaticSystemParam::queue implementation.
Fix error in AnyOf
Fix
push_children
inserting aChildren
component even when no children are suppliedadd missing mention of sort_unstable_by_key in QuerySortedIter docs
Backport #14083 (deregister events) to 0.14 branch
ECS + Networking #
ECS + Networking + Scenes #
ECS + Pointers #
ECS + Reflection #
Replace
FromWorld
requirement onReflectResource
and reflectResource
forState&lt;S&gt;
Make some
ReflectComponent
/ReflectBundle
methods work withEntityMut
tooMake
from_reflect_or_world
also tryReflectDefault
and improve some comments and panic messagesAdd Reflect derive to Events and contained types
Generalize component reflection to operate on
FilteredEntityRef
andFilteredEntityMut
, notEntityRef
andEntityMut
.feat: Reflection implementations on Identifier
ECS + Rendering #
ECS + Tasks #
Update async-channel to 2.2.0
Run the multi-threaded executor at the end of each system task.
multi_threaded feature rename
ECS + Utils #
Editor #
Editor + Gizmos #
Editor + Reflection #
Gizmos #
Move gizmos examples in the separate folder
make gizmo groups ordering stable when rendering
Add Grid gizmos
Add basic light gizmos
Example for axes gizmos
Fix gizmos panicking given bad output from
GlobalTransform::to_scale_rotation_translation
Improve gizmo axes example
Gizmo line joints
Gizmos: Replace PositionItem with Vec3
Gizmo 3d grids
order systems in axes example
Gizmo line styles
Support wireframes for 2D meshes
Changed the order of arguments for the Arc gizmo docs
Add tetrahedron gizmos
Add double end arrow to gizmos
Contextually clearing gizmos
gizmos: take normal of normal on plane 3d before rotation
Add Rounded box gizmos
De-clutter
2d_gizmos
exampleInconsistent segments/resolution naming
Make gizmos take primitives by ref
More gizmos builders
Add axes_2d gizmo.
Gizmos + Math #
pick nits from example bounding_2d
Add
Annulus
-gizmosNew circular primitives:
Arc2d
,CircularSector
,CircularSegment
Add
Triangle3d
/Tetrahedron
to render_primitives exampleImplement Rhombus 2D primitive.
Implemented GizmoPrimitive2d for
Arc2d
,CircularSegment
,CircularSector
, and make arc_2d use counter-clockwise angle.
Gizmos + Reflection #
Gizmos + Rendering #
Hierarchy #
Add entity id to hierarchy propagation error message
fix bevy_hierarchy crate optional feature
bevy_app
Hierarchy + Scenes #
Input #
also look in just_pressed touches for position
Add table showing complexity of methods for Input
Prevent panic when multiple Enter inputs received in
text_input
exampleonly update
Touches
resource when neededFix missing renaming of Input -> ButtonInput
Make Gilrs a normal resource on non-Wasm targets
Add WinitEvent aggregate event for synchronized window event reading
Update
Input
toButtonInput
in a couple places at keyboard input docsSend GamepadEvent for gamepads connected at startup
Clarify documentation regarding just_released and just_pressed inputs
Remove unused
ImePreedit
component fromtext_input
examplefix previous_position / previous_force being discarded too early
ButtonInput docs - performance cost adjustment
Added
ButtonInput
docs usage examplerename touchpad to gesture, and add new gestures
Fix phantom key presses in winit on focus change (#13299)
Input + Math #
Input + Windowing #
Document ButtonInput behavior regarding window focus
Deprecate
ReceivedCharacter
flush key_input cache when Bevy loses focus (Adopted)
Math #
Add single-f32 constructors for a few (very few) primitives
Add
Direction3dA
and move direction types out ofprimitives
Cubic splines overhaul
Rename
Direction2d&#x2F;3d
toDir2&#x2F;3
Implement
Mul
betweenf32
and direction typesImprove error messages for denormalized directions
Support transforming bounding volumes
Add note about rotations for
Aabb3d
Add
Rotation2d
Add
scale_around_center
method toBoundingVolume
traitchange doc for SphereKind::Ico to reflect that the triangles are equa…
Uniform point sampling methods for some primitive shapes.
Add methods to return the inner value for direction types
Add a from Dir2 impl for Vec2
Make cardinal splines include endpoints
Add
Triangle3d
primitive tobevy_math::primitives
Math tests fix
Implement
From&lt;Vec2&gt;
forAspectRatio
Move
Point
out of cubic splines module and expand itFix
Triangle2d
/Triangle3d
interior sampling to correctly follow triangleRemove VectorSpace impl on Quat
Add
Tetrahedron
primitive tobevy_math::primitives
fixing line comment in 2d_shapes.rs example
Change
Tetrahedron
default origin to(0, 0, 0)
Random sampling of directions and quaternions
Meshing for
Triangle3d
primitiveMath primitives cleanup
Additional doc aliases for
WindingOrder
inbevy_math
Use Vec3A for 3D bounding volumes and raycasts
Update glam version requirement from 0.25 to 0.27
Ellipse functions
replace std::f32::EPSILON with f32::EPSILON
Add
AXES
iterators forDir
typesAdd copy, clone, and debug derives to cubic spline structs
Allow shapes to be constructed with zero values
Tetrahedron sampling
Add slerp function for Dir2, Dir3, Dir3A
Add
Distribution
access methods forShapeSample
traitAnnulus sampling
Add triangle_math tests and fix Triangle3d::bounding_sphere bug
Mention of Vec normalization for Dir::new
Example for random sampling
Create a primitive sampling showcase example
Clarify cone position
Implement
ShapeSample
forExtrusion&lt;T&gt;
Add wireframe toggle to 2d and 3d shapes example
Add compass direction constants to
Dir2
Dir2
->Rotation2d
conversionsExtrusion bounded
Meshable extrusions
Meshable extrusions - Part 2
Allow creation of random
Rotation2d
Allow
Bounded3d
implementations for custom primitivesRename
Rotation2d
toRot2
Extrusion
Add segments to
ExtrusionBuilder
Custom primitives example
Math + Reflection #
Add reflect impls for bevy_math curve structs
Move
bevy_math
Reflect
implsImplemented
Reflect
for (almost) allbevy_math
types
Math + Rendering #
Add
Annulus
primitive tobevy_math::primitives
Meshing for
Annulus
primitiveseparating finite and infinite 3d planes
Add meshing for
Cone
Common
MeshBuilder
traitFix normals during mesh scaling
Tetrahedron mesh
Add meshing for
ConicalFrustum
Additional options to mesh primitives
Add subdivisions to PlaneMeshBuilder
Math + Transform #
Make
Transform::rotate_axis
andTransform::rotate_local_axis
useDir3
Use
Dir3
for local axis methods inGlobalTransform
Math + Utils #
Fix
Ord
andPartialOrd
differing forFloatOrd
and optimize implementationMove FloatOrd into bevy_math
Math + Windowing #
Meta #
Replace references to old book with quick start guide
Bump Version after Release
Add a release step, add links to the github release note
Update funding link
document how to publish patches
Add note on partial reviews
Add paragraph on requesting reviews
Add Testing section to the PR template
Add guidance on closing PRs
Reorganize issue labels
Add a process for working groups
Document the Release Candidate process
Modding #
Pointers #
Reflection #
bevy_reflect: Recursive registration
Add method for querying whether a given short type path is ambiguous
reflect: treat proxy types correctly when serializing
Added reflect support for std::HashSet, BTreeSet and BTreeMap.
Remove unnecessary
impl_reflect_for_btree_map
macroClean up type registrations
bevy_reflect: Remove
U32Visitor
Add reflect for type id
add reflect for BinaryHeap
reflect: remove manual Reflect impls which could be handled by macros
bevy_reflect: Rename
UntypedReflectDeserializer
toReflectDeserializer
Implement Reflect for Result<T, E> as enum
examples: Add
Dynamic Types
reflection exampleRename
bevy_reflect_derive
folder toderive
Finish the work on
try_apply
bevy_reflect: Remove
ContainerAttributes::merge
Avoid bevy_reflect::List::iter wrapping in release mode
bevy_reflect:
enum_utility
cleanupAdd some missing reflect for volumetric fog types
hashing error in bevy_reflect now includes the type (bevyengine#13646)
Reflection + Rendering #
Reflection + Scenes #
Fix: deserialize
DynamicEnum
using indexFix TypeRegistry use in dynamic scene
Map entities from a resource when written to the world.
Reflection + Time #
Reflection + Utils #
Rendering #
Per-Object Motion Blur
Meshlet rendering (initial feature)
Fix dds feature dependencies in bevy_core_pipeline
Add the serde feature to bitflags for bevy_render.
rename Camera3dBundle's 'dither' field to 'deband_dither' to align with Camera2dBundle
Implement Debug for SpriteBundle and SpriteSheetBundle
Allow Mesh-related queue phase systems to parallelize
Save 16 bytes per MeshUniform in uniform/storage buffers
Fix MSAA writeback when 3 or more cameras have the same target.
Add support for KHR_texture_transform
Move AlphaMode into bevy_render
Make Globals visible in vertex shaders
Fixed Ui Image slicing
FIX: iOS Simulator not rendering due to missing CUBE_ARRAY_TEXTURES
Make more things pub in the renderer
set pipeline to queued when shader is not yet available
fix typo: converstion -> conversion
make reflection probe example frame rate independent
Pad SkyUniforms to 16 bytes for WASM
Adding "fluent" methods to modify color channels.
Prefer
UVec2
when working with texture dimensionsCleanup: Use Parallel in extract_meshes
Increase 3D Lighting example's light intensity
Early-exit bloom node if
intensity == 0.0
Fix WebGL not rendering
StandardMaterial
sort alpha masked pipelines by pipeline & mesh instead of by distance
Fix
CameraProjectionPlugin
not implementingPlugin
in some casesAdd random shader utils, fix cluster_debug_visualization
Use
spawn_batch
inmany_lights
exampleImprove lighting in more examples
Impl ShaderType for LinearRgba
compute shader game of life example: use R32Float instead of Rgba8Unorm
Register
fxaa::Sensitivity
and deriveDebug
bloom: use emissive instead of base_color for emissive
Intern mesh vertex buffer layouts so that we don't have to compare them over and over.
Update
wgpu
to v0.19.3 and unpinweb-sys
.Batching: replace GpuArrayBufferIndex::index with a u32
PBR: use attenuation instead of base_color for attenuation
fix example lightmaps after color migration
Slicing support for texture atlas
update comment on
emissive
field ofStandardMaterial
struct to mention large color channel valuesUse floats mathed from 8-bit values in basic color palette
Fix directional light shadow frustum culling near clip plane to infinity
Improve Bloom 3D lighting
try_insert NoAutomaticBatching
Extracting ambient light from light.rs, and creating light directory
stop retrying removed assets
Add trait for clamping colors
fast-fail in as_bind_group
Add setting to enable/disable shadows to MaterialPlugin
Implement
Mix
forHsva
andHwba
Interpolating hues should use rem_euclid.
Remove needless color specializaion for
SpritePipeline
Moving structs PointLight, SpotLight, and DirectionalLight out of light/mod.rs
fix: make WebGPU shader work again
Add iOS to synchronous_pipeline_compilation docs
Fix CI for wasm atomics
Update image requirement from 0.24 to 0.25
Make PersistentGpuBufferable a safe trait
Pack the
StandardMaterialKey
into a single scalar instead of a structure.Torus benchmark
Improve performance by binning together opaque items instead of sorting them.
Vectorize reset_view_visibility
Added a small comment to post_processing example with instructions on how to make it work for 2d
Fix crash on Linux Nvidia 550 driver
remove
DeterministicRenderingConfig
Normalize warning messages with Nvidia drivers
Fix UV coords in
generate_custom_mesh
exampleMicro-optimize
queue_material_meshes
, primarily to remove bit manipulation.many_cubes: Add no automatic batching and generation of different meshes
Add the annulus shape to the
2d_shapes
exampleDisable RAY_QUERY and RAY_TRACING_ACCELERATION_STRUCTURE by default
Relax BufferVec's type constraints
Added method to get waiting pipelines IDs from pipeline cache.
fix msaa shift with irradiance volumes in mesh pipeline key
Fix broken link in mesh docs
Fix skybox wrong alpha
more robust gpu image use
Add previous_view_uniforms.inverse_view
Fix potential out-of-bounds access in pbr_functions.wgsl
Add gpu readback example
Fix example game of life
Generate
MeshUniform
s on the GPU via compute shader where available.flipping texture coords methods has been added to the StandardMaterial
Implement percentage-closer filtering (PCF) for point lights.
Divide the single
VisibleEntities
list into separate lists for 2D meshes, 3D meshes, lights, and UI elements, for performance.Fix rendering of sprites, text, and meshlets after #12582.
Don't examine every entity when extracting
SpriteSource
s.Fixed crash when transcoding one- or two-channel KTX2 textures
Fix 2D BatchedInstanceBuffer clear
Implement alpha to coverage (A2C) support.
Normalization anchor for sprite slice in dimensions of this slice
fix: incorrect sprite size for aabb when sprite has rect and no custom_size
Add missing Default impl to ExtendedMaterial.
Document Camera coordinate space
Run
CheckVisibility
after all the other visibility system sets have…Expose
desired_maximum_frame_latency
through window creationUse WireframeColor to override global color
use a u64 for MeshPipelineKey
Clarify comment about camera coordinate system
Remove unused push constants
Meshlet continuous LOD
Fix custom pipeline in mesh2d_manual rendering other meshes
Throttle render assets
Cleanup extract_meshes
Fix
CameraProjection
panic and improveCameraProjectionPlugin
asset throttling: don't be exhausted if there is no limit
Meshlet LOD-compatible two-pass occlusion culling
Restore dragons to their seat of power
Implement GPU frustum culling.
Fix typo in
bevy_render&#x2F;src&#x2F;batching&#x2F;gpu_preprocessing.rs
Don't ignore unbatchable sorted items.
Implement filmic color grading.
Use BindGroupLayoutEntryBuilder in texture_binding_array example
Implement visibility ranges, also known as hierarchical levels of detail (HLODs).
Add BufferVec, an higher-performance alternative to StorageBuffer, and make GpuArrayBuffer use it.
Implement Auto Exposure plugin
Re-export IntoDynamicImageError as public
Meshlet remove per-cluster data upload
Doc custom CameraProjection requires use of plugin
Example with repeated texture
Only create changed buffer if it already exists
Implement clearcoat per the Filament and the
KHR_materials_clearcoat
specifications.Modulate the emissive texture by the emissive color again.
Extract mesh view layouts logic
Fix the WebGL 2 backend by giving the
visibility_ranges
array a fixed length.Clean up 2d render phases
Headless renderer example has been added
Fix motion blur on wasm
remove unused warnings in release
Fix incorrect workgroupBarrier and OOB array access in auto_exposure
Add UV channel selection to StandardMaterial
Implement fast depth of field as a postprocessing effect.
Add docs for
PointLight
Apply uv transform in the prepass
Skip redundant mesh_position_local_to_world call in vertex prepass shader
Fix ClearColor in 2d pipelines
Enable depth of field on webgpu
Add
Debug
derive forScreenSpaceAmbientOcclusionSettings
structFix transmission by setting the correct value for transmissive_lighting_input.F_ab
Support calculating normals for indexed meshes
Revert "Support calculating normals for indexed meshes" (#12716) and add support for calculating smooth normals
#12502 Remove limit on RenderLayers.
Implement volumetric fog and volumetric lighting, also known as light shafts or god rays.
Remove unnecessary .view_layouts
example render_to_texture: remove extra light
Add emissive_exposure_weight to the StandardMaterial
Make the prepass shader compile when lightmaps are present.
Remove another .view_layouts
Fixed incorrect behaviour of headless_renderer depending on image dimensions
Fix lints on beta Rust
Make render phases render world resources instead of components.
fix lava emissive strength in depth of field example
Fix 2D looking blurry at odd window sizes
Fix lighting example following emissive material changes in #13350
Update render graph docs
add glsl feature for bevy_pbr
Implement opt-in sharp screen-space reflections for the deferred renderer, with improved raymarching code.
revert reflections PR changes to the meshlet example
use ssr dynamic offset in volumetric fog bind group
add tonemapping LUT bindings for sprite and mesh2d pipelines
Set the default target exposure to the minimum value, not 0
Run motion blur before TAA to reduce artifacts
Fix: Motion blur should sample onscreen fragments with no depth
disable gpu preprocessing on android with Adreno 6xx GPU
color_grading: update UI when camera settings changed
Fix docs for
RenderLayers
Implement motion vectors and TAA for skinned meshes and meshes with morph targets.
Use correct minimal version of meshopt
Add Skybox Motion Vectors
Meshlet single pass depth downsampling (SPD)
More idiomatic texture atlas builder
Extra info on Image debug assertions
Move clustering-related types and functions into their own module.
Normalise matrix naming
Update ruzstd requirement from 0.6.0 to 0.7.0
Implement PBR anisotropy per
KHR_materials_anisotropy
.document need to update Aabb in Mesh::(with_)insert_attribute
Rename "point light" to "clusterable object" in cluster contexts.
Add
binding()
helper function toBufferVec
Implement subpixel morphological antialiasing, or SMAA.
Use
BufferVec
forgpu_readback
exampleSkip tonemapping in case it is none
Made
Mesh::merge
take a reference ofMesh
.Misc meshlet changes
Use TBN in apply_normal_mapping in pbr_prepass
Allow mix of hdr and non-hdr cameras to same render target
2D top-down camera example
Remove unused mip_bias parameter from apply_normal_mapping
Meshlet misc
Clarify error message due to missing shader file
Fix meshlet vertex attribute interpolation
Add
from_color
toStandardMaterial
andColorMaterial
Make FOG_ENABLED a shader_def instead of material flag
Revert "Make FOG_ENABLED a shader_def instead of material flag (#13783)"
Use dynamic uniform buffer in post processing example
Wgpu 0.20
Make meshlet processing deterministic
Fix meshlet interactions with regular shading passes
Fix MeshletMesh material system ordering
don't crash without features
bevy_pbr
,ktx2
,zstd
Print warning when using llvmpipe
typo
Fix typo in CPU adapter warning
Fix incorrect computation of mips for cluster occlusion lookup
Allow phase items not associated with meshes to be binned.
Fix compile failure in WASM without
wgpu
backendSupport operations for render layers and fix equality comparisons
Clarify the difference between default render layers and
none
render layersAdded feature switch to default Standard Material's new anisotropy texture to off
Rendering + Transform #
Rendering + UI #
Deprecate
SpriteSheetBundle
andAtlasImageBundle
Decouple
BackgroundColor
fromUiImage
Fix blurry text
Fix UI border artifacts caused by incorrect blending
Fix UI elements randomly not appearing after #13277.
reduce the antialias strength
fix panic: invalid SlotMap key used
Make default behavior for
BackgroundColor
andBorderColor
more intuitive
Rendering + Utils #
Rendering + Windowing #
Update
split_screen
example with 4 camerasconfigure_surface needs to be on the main thread on iOS
Introduce a
WindowWrapper
to extend the lifetime of the window when using pipelined rendering
Scenes #
scene example: remove unnecessary reflect(FromWorld)
Fix typo in
SceneBundle
docsRemove
InstanceId
when Scene Despawn
Tasks #
Add an index argument to parallel iteration helpers in bevy_tasks
Get Bevy building for WebAssembly with multithreading
Bump async-task
Remove async-task as a dependency
async_compute example: don't block in the task
Tasks + Windowing #
Text #
text2d example: animate_scale no longer unnecessarily performs the same translation at each Update
Calculate AABBs to enable text2d culling
fix non-exact text h-alignment
text position: use size instead of bounds
Time #
Transform #
Alignment API for Transforms
Use
Dir3
inTransform
APIsRefactor align example to use
Dir3
random samplingbevy_transform split up to allow feature gate modularity
Allow bevy_transform to be used as a barebones dependency
Fix links to
Transform
inTransform
andGlobalTransform
docsUse a ship in Transform::align example
Transform + UI #
UI #
Add doc comments explaining the different behaviours of alignment and Anchor with text_2d
Simplify and improve
overflow_debug
exampleRemove custom window size from
flex_layout
exampleAdd tinting to the border in
ui_texture_slice
exampleui materials respect target camera
Avoid panicking with non-UI nodes
Fix #12255 Updating TargetCamera on multi camera scenes not allowing layout to be calculated
remove background color from UI example image
Fix
with_scale_factor_override
improperly settingscale_factor_override
Fix incorrect link in UiMaterial documentation
Add "all-features = true" to docs.rs metadata for most crates
don't attempt to set cursor relative position for zero sized nodes
correctly set up background color in mobile example
Reduce steady-state allocations in ui_stack_system
Add
with_left
,with_right
,with_top
,with_bottom
toUiRect
Compute texture slices after layout
feat: derive some common traits on some UI types
Add border radius to UI nodes (adopted)
UI: allow border radius to be optional for images and background
UI: don't multiply color channels by alpha
UI: rounded border should use camera instead of windows
Update
borders
example to matchrounded_borders
examplerounded border: remove dead code in shader
Restore pre 0.13.1 Root Node Layout behavior
Add padding to new text in
ui
example[bevy_ui/layout] Extract UiSurface to its own file
grammar fix
Correctly handle UI hierarchy without a camera
Added vmin and vmax to the gridtrack impls, repeatedgridtrack impls
UI: pass the untransformed node size to the shader
Upgrade to Taffy 0.4
Rename
Rect
inset()
method toinflate()
Optimize the values for
EMPTY
rect.Fix various bugs with UI rounded borders
fix rounded borders on buttons
Fix UI in WebGPU: call
textureSample
from outside the ifFix image measure function to apply inherent aspect ratio to style sizes
Updates default Text font size to 24px
make UI text rendering camera driven
bug: Fix 9-slice textures with asymmetric borders.
add PartialEq to Outline
fix remaining issues with background color in examples
Fix border color in
ui_texture_slice
andui_texture_atlas_slice
examples.
Utils #
refactor: Extract parallel queue abstraction
bevy_utils: Add
BuildHasher
parameter tobevy_utils::Entry
type aliasDisentangle bevy_utils/bevy_core's reexported dependencies
Windowing #
Add
size
andphysical_size
towindow
Fix fit_canvas_to_parent
Add the ability to request a redraw from an external source
Fix winit control flow when re-focusing game
Make
CreateWindowParams
type andcreate_windows
system publicExpose Winit's
with_skip_taskbar
on window creationClean up WinitWindows::remove_window
Add Clone to WinitSettings
Fixes #12000: When viewport is set to camera and switched to SizedFul…
Remove unecessary lint
#[allow(...)]
fix: rewrite winit loop
Simplify winit runner exit code reporting
Ensure clean exit
fix: upgrade to winit v0.30
make sure windows are dropped on main thread
13743 app exit hang
Correctly check physical size when updating winit
apply window scale to window size when creating it
Have WindowPosition::Centered take scale_factor_override into account
only run one update per frame drawn
No area label #
Use
is
method instead ofdowncast_ref::&lt;T&gt;().is_some()
inApp::is_plugin_added
Update to toml_edit 0.22
Use the scroll wheel to control the camera speed in examples
fix some typos
remove unnecessary mut in query in ui_texture_slice example
Fixed iOS documentation typo for xcrun command
examples/ecs/iter_combinations: Initialize velocity using fixed timestep
Update tracing-log requirement from 0.1.2 to 0.2.0
include links in error messages
Add a colon to error message link
Various improvements to the
contributors
exampleBuild dev docs like docs.rs
Add nightly hint to config.toml
Update engine_style_guide with guideline to link to the error code when using bevy engine error codes
remove repetitive code
Bump crate-ci/typos from 1.18.2 to 1.19.0
remove comment in typos.toml
Fix docs for atlas + slicing support
Fix green colors becoming darker in various examples
Fix "dark grey" colors becoming lighter in various examples
Fix ios simulator support
We must have googly eyes (new Game example)
Fix dim emissive values in
lighting
exampleUpdate ruzstd requirement from 0.5.0 to 0.6.0
low_power example: pick nits
Fix
z
scale being0.0
in breakout exampleBreakout refactor
Fix typo in bevy_internal/Cargo.toml
Update to fixedbitset 0.5
remove link to inexistent example
Beautify example showcase site URLs
Update base64 requirement from 0.21.5 to 0.22.0
Fix pink colors in examples
refactor: separate out
PanicHandlerPlugin
typo: 'plateform' -> 'platform'
Switch to portable RNG in examples
Make
feature(doc_auto_cfg)
workAdding explanation to seeded rng used in examples
fix example mesh2d_manual in wasm/webgl2
Fix ambiguities causing a crash
Fix example showcase wasm window settings patch
Bump crate-ci/typos from 1.19.0 to 1.20.4
Enable
clippy::ref_as_ptr
Bump crate-ci/typos from 1.20.4 to 1.20.8
Add
Cascades
to the type registry, fixing lights in glTF.Update and clarify a Maintainer merge rule
Give alt text to Bevy logo
headless_renderer comments typo fix
Update itertools requirement from 0.12 to 0.13
small improvements on the color_grading example
Set ambient_intensity to 0.0 in volumetric_fog example, correct doc comment
Swapping back to using From<Color> for StandardMaterial in examples
Use standard instruction text / position in various examples
Handle wgsl errors in the game of life example
Fix a few typos
rename the crate bevy_state_macros_official back to its original name
Make Observer::with_event (and other variants) unsafe
fix examples color_grading and mobile after BackgroundColor changes