# Objective
Currently, UI is always rendered with anti-aliasing. This makes bevy's
UI completely unsuitable for art-styles that demands hard pixelated
edges, such as retro-style games.
## Solution
Add a component for disabling anti-aliasing in UI.
## Testing
In
[`examples/ui/button.rs`](15e246eff8/examples/ui/button.rs),
add the component to the camera like this:
```rust
use bevy::{prelude::*, ui::prelude::*};
commands.spawn((Camera2dBundle::default(), UiAntiAlias::Off));
```
The rounded button will now render without anti-aliasing.
## Showcase
An example of a rounded UI node rendered without anti-aliasing, with and
without borders:
![image](https://github.com/user-attachments/assets/ea797e40-bdaa-4ede-a0d3-c9a7eab95b6e)
# Objective
- Another way of specifying rotations was requested in
https://github.com/bevyengine/bevy/issues/11132#issuecomment-2344603178
## Solution
- Add methods on `Rot2`
- `turn_fraction(fraction: f32) -> Self`
- `as_turn_fraction(self) -> f32`
- Also add some documentation on range of rotation
## Testing
- extended existing tests
- added new tests
## Showcase
```rust
let rotation1 = Rot2::degrees(90.0);
let rotation2 = Rot2::turn_fraction(0.25);
// rotations should be equal
assert_relative_eq!(rotation1, rotation2);
// The rotation should be 90 degrees
assert_relative_eq!(rotation2.as_radians(), FRAC_PI_2);
assert_relative_eq!(rotation2.as_degrees(), 90.0);
```
---------
Co-authored-by: Joona Aalto <jondolf.dev@gmail.com>
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
# Objective
- Adds the missing API commands `insert_if_new_and` and
`try_insert_if_new_and` (resolves#15105)
- Adds some test coverage for existing insert commands
## Testing
- Implemented additional unit tests to add coverage
# Objective
Right now, `DynSystemParam::downcast()` always requires the type
parameter to be specified with a turbofish. Make it so that it can be
inferred from the use of the return value, like:
```rust
fn expects_res_a(mut param: DynSystemParam) {
let res: Res<A> = param.downcast().unwrap();
}
```
## Solution
The reason this doesn't currently work is that the type parameter is a
`'static` version of the `SystemParam` so that it can be used with
`Any::downcast_mut()`. Change the method signature so that the type
parameter matches the return type, and use `T::Item<'static, 'static>`
to get the `'static` version. That means we wind up returning a
`T::Item<'static, 'static>::Item<'w, 's>`, so constrain that to be equal
to `T`. That works with every `SystemParam` implementation, since they
have `T::Item == T` up to lifetimes.
# Objective
Fixes#14540
## Solution
- Clean slab layouts from stale `SlabId`s when freeing meshes
- Technically performance requirements of freeing now increase based on
the number of existing meshes, but maybe it doesn't matter too much in
practice
- This was the case before this PR too, but it's technically possible to
free and allocate 2^32 times and overflow with `SlabId`s and cause
incorrect behavior. It looks like new meshes would then override old
ones.
## Testing
- Tested in `loading_screen` example and tapping keyboard 1 and 2.
# Objective
- fix#12853
- Make `Table::allocate` faster
## Solution
The PR consists of multiple steps:
1) For the component data: create a new data-structure that's similar to
`BlobVec` but doesn't store `len` & `capacity` inside of it: "BlobArray"
(name suggestions welcome)
2) For the `Tick` data: create a new data-structure that's similar to
`ThinSlicePtr` but supports dynamic reallocation: "ThinArrayPtr" (name
suggestions welcome)
3) Create a new data-structure that's very similar to `Column` that
doesn't store `len` & `capacity` inside of it: "ThinColumn"
4) Adjust the `Table` implementation to use `ThinColumn` instead of
`Column`
The result is that only one set of `len` & `capacity` is stored in
`Table`, in `Table::entities`
### Notes Regarding Performance
Apart from shaving off some excess memory in `Table`, the changes have
also brought noteworthy performance improvements:
The previous implementation relied on `Vec::reserve` &
`BlobVec::reserve`, but that redundantly repeated the same if statement
(`capacity` == `len`). Now that check could be made at the `Table` level
because the capacity and length of all the columns are synchronized;
saving N branches per allocation. The result is a respectable
performance improvement per every `Table::reserve` (and subsequently
`Table::allocate`) call.
I'm hesitant to give exact numbers because I don't have a lot of
experience in profiling and benchmarking, but these are the results I
got so far:
*`add_remove_big/table` benchmark after the implementation:*
![after_add_remove_big_table](https://github.com/bevyengine/bevy/assets/46227443/b667da29-1212-4020-8bb0-ec0f15bb5f8a)
*`add_remove_big/table` benchmark in main branch (measured in comparison
to the implementation):*
![main_add_remove_big_table](https://github.com/bevyengine/bevy/assets/46227443/41abb92f-3112-4e01-b935-99696eb2fe58)
*`add_remove_very_big/table` benchmark after the implementation:*
![after_add_remove_very_big](https://github.com/bevyengine/bevy/assets/46227443/f268a155-295b-4f55-ab02-f8a9dcc64fc2)
*`add_remove_very_big/table` benchmark in main branch (measured in
comparison to the implementation):*
![main_add_remove_very_big](https://github.com/bevyengine/bevy/assets/46227443/78b4e3a6-b255-47c9-baee-1a24c25b9aea)
cc @james7132 to verify
---
## Changelog
- New data-structure that's similar to `BlobVec` but doesn't store `len`
& `capacity` inside of it: `BlobArray`
- New data-structure that's similar to `ThinSlicePtr` but supports
dynamic allocation:`ThinArrayPtr`
- New data-structure that's very similar to `Column` that doesn't store
`len` & `capacity` inside of it: `ThinColumn`
- Adjust the `Table` implementation to use `ThinColumn` instead of
`Column`
- New benchmark: `add_remove_very_big` to benchmark the performance of
spawning a lot of entities with a lot of components (15) each
## Migration Guide
`Table` now uses `ThinColumn` instead of `Column`. That means that
methods that previously returned `Column`, will now return `ThinColumn`
instead.
`ThinColumn` has a much more limited and low-level API, but you can
still achieve the same things in `ThinColumn` as you did in `Column`.
For example, instead of calling `Column::get_added_tick`, you'd call
`ThinColumn::get_added_ticks_slice` and index it to get the specific
added tick.
---------
Co-authored-by: James Liu <contact@jamessliu.com>
# Objective
It would be convenient to be able to quickly deny or allow all
components and resources on a `DynamicSceneBuilder` with a single method
call.
Context: #15210 renamed `{allow/deny}_all` to
`{allow/deny}_all_components`.
## Solution
Added two new methods to `DynamicSceneBuilder`, `allow_all` and
`deny_all`, which affect both the component and resource filters.
## Showcase
### Before
```rust
let builder = DynamicSceneBuilder::from_world(world)
.deny_all_components()
.deny_all_resources();
```
### After
```rust
let builder = DynamicSceneBuilder::from_world(world).deny_all();
```
The function `bevy_input::schedule::condition::Condition::or_else` has
been deprecated in favor of
`bevy_input::schedule::condition::Condition::or`. However the docs for
`ButtonInput` were still using the deprecated function in their example.
# Objective
The method names on `DynamicSceneBuilder` are misleading. Specifically,
`deny_all` and `allow_all` implies everything will be denied/allowed,
including all components and resources. In reality, these methods only
apply to components (which is mentioned in the docs).
## Solution
- change `deny_all` and `allow_all` to `deny_all_components` and
`allow_all_components`
- also, change the remaining methods to mention component where it makes
sense
We could also add the `deny_all` and `allow_all` methods back later,
only this time, they would deny/allow both resources and components.
## Showcase
### Before
```rust
let builder = DynamicSceneBuilder::from_world(world)
.deny_all()
.deny_all_resources()
.allow::<MyComponent>();
```
### After
```rust
let builder = DynamicSceneBuilder::from_world(world)
.deny_all_components()
.deny_all_resources()
.allow_component::<MyComponent>();
```
## Migration Guide
the following invocations on `DynamicSceneBuilder` should be changed by
users
- `with_filter` -> `with_component_filter`
- `allow` -> `allow_component`
- `deny` -> `deny_component`
- `allow_all` -> `allow_all_components`
- `deny_all` -> `deny_all_components`
# Objective
Fix#10284.
## Solution
When `DynamicSceneBuilder` extracts entities, they are cloned via
`PartialReflect::clone_value`, making them into dynamic versions of the
original components. This loses any custom `ReflectSerialize` type data.
Dynamic scenes are deserialized with the original types, not the dynamic
versions, and so any component with a custom serialize may fail. In this
case `Rect` and `Vec2`. The dynamic version includes the field names 'x'
and 'y' but the `Serialize` impl doesn't, hence the "expect float"
error.
The solution here: Instead of using `clone_value` to clone the
components, `FromReflect` clones and retains the original information
needed to serialize with any custom `Serialize` impls. I think using
something like `reflect_clone` from
(https://github.com/bevyengine/bevy/pull/13432) might make this more
efficient.
I also did the same when deserializing dynamic scenes to appease some of
the round-trip tests which use `ReflectPartialEq`, which requires the
types be the same and not a unique/proxy pair. I'm not sure it's
otherwise necessary. Maybe this would also be more efficient when
spawning dynamic scenes with `reflect_clone` instead of `FromReflect`
again?
An alternative solution would be to fall back to the dynamic version
when deserializing `DynamicScene`s if the custom version fails. I think
that's possible. Or maybe simply always deserializing via the dynamic
route for dynamic scenes?
## Testing
This example is similar to the original test case in #10284:
``` rust
#![allow(missing_docs)]
use bevy::{prelude::*, scene::SceneInstanceReady};
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Startup, (save, load).chain())
.observe(check)
.run();
}
static SAVEGAME_SAVE_PATH: &str = "savegame.scn.ron";
fn save(world: &mut World) {
let entity = world.spawn(OrthographicProjection::default()).id();
let scene = DynamicSceneBuilder::from_world(world)
.extract_entity(entity)
.build();
if let Some(registry) = world.get_resource::<AppTypeRegistry>() {
let registry = registry.read();
let serialized_scene = scene.serialize(®istry).unwrap();
// println!("{}", serialized_scene);
std::fs::write(format!("assets/{SAVEGAME_SAVE_PATH}"), serialized_scene).unwrap();
}
world.entity_mut(entity).despawn_recursive();
}
fn load(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(DynamicSceneBundle {
scene: asset_server.load(SAVEGAME_SAVE_PATH),
..default()
});
}
fn check(_trigger: Trigger<SceneInstanceReady>, query: Query<&OrthographicProjection>) {
dbg!(query.single());
}
```
## Migration Guide
The `DynamicScene` format is changed to use custom serialize impls so
old scene files will need updating:
Old:
```ron
(
resources: {},
entities: {
4294967299: (
components: {
"bevy_render:📷:projection::OrthographicProjection": (
near: 0.0,
far: 1000.0,
viewport_origin: (
x: 0.5,
y: 0.5,
),
scaling_mode: WindowSize(1.0),
scale: 1.0,
area: (
min: (
x: -1.0,
y: -1.0,
),
max: (
x: 1.0,
y: 1.0,
),
),
),
},
),
},
)
```
New:
```ron
(
resources: {},
entities: {
4294967299: (
components: {
"bevy_render:📷:projection::OrthographicProjection": (
near: 0.0,
far: 1000.0,
viewport_origin: (0.5, 0.5),
scaling_mode: WindowSize(1.0),
scale: 1.0,
area: (
min: (-1.0, -1.0),
max: (1.0, 1.0),
),
),
},
),
},
)
```
---------
Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
# Objective
- Fixes#14552
- Make the current note of `before` and `after` understandable.
- > The given set is not implicitly added to the schedule when this
system set is added.
## Solution
- Replace note in docs of [`after` and
`before`](https://docs.rs/bevy/latest/bevy/ecs/prelude/trait.IntoSystemConfigs.html#method.before)
- Note of after was removed completely, and links to `before`, because
they notes would be identical.
- Also encourage to use `.chain`, which is much simpler and safer to use
## Testing
- Checked the docs after running `cargo doc` and `cargo run -p ci --
lints`
- Are there any parts that need more testing?
- no need to test, but please review the text. If it is still including
the intended message and especially if its understandable.
---------
Co-authored-by: Jan Hohenheim <jan@hohenheim.ch>
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
`Capsule2d::sample_interior` uses the radius of the capsule for the
width of its rectangular section. It should be using two times the
radius for the full width!
I noticed this as I was getting incorrect results for angular inertia
approximated from a point cloud of points sampled on the capsule. This
hinted that something was wrong with the sampling.
## Solution
Multiply the radius by two to get the full width of the rectangular
section. With this, the sampling produces the correct result in my
tests.
# Objective
- implements ParsedPath::try_from<&str>
- resolves#14438
## Testing
- Added unit test for ParsedPath::try_from<&str>
Note: I don't claim to be an expert on lifetimes! That said I think it
makes sense that the error shares a lifetime with input string as deeper
down it is used to construct it.
# Objective
Thanks to #7207, we now have a way to validate at the type-level that a
reflected value is actually the type it says it is and not just a
dynamic representation of that type.
`dyn PartialReflect` values _might_ be a dynamic type, but `dyn Reflect`
values are guaranteed to _not_ be a dynamic type.
Therefore, we can start to add methods to `Reflect` that weren't really
possible before. For example, we should now be able to always get a
`&'static TypeInfo`, and not just an `Option<&'static TypeInfo>`.
## Solution
Add the `DynamicTyped` trait.
This trait is similar to `DynamicTypePath` in that it provides a way to
use the non-object-safe `Typed` trait in an object-safe way.
And since all types that derive `Reflect` will also derive `Typed`, we
can safely add `DynamicTyped` as a supertrait of `Reflect`. This allows
us to use it when just given a `dyn Reflect` trait object.
## Testing
You can test locally by running:
```
cargo test --package bevy_reflect
```
---
## Showcase
`Reflect` now has a supertrait of `DynamicTyped`, allowing `TypeInfo` to
be retrieved from a `dyn Reflect` trait object without having to unwrap
anything!
```rust
let value: Box<dyn Reflect> = Box::new(String::from("Hello!"));
// BEFORE
let info: &'static TypeInfo = value.get_represented_type_info().unwrap();
// AFTER
let info: &'static TypeInfo = value.reflect_type_info();
```
## Migration Guide
`Reflect` now has a supertrait of `DynamicTyped`. If you were manually
implementing `Reflect` and did not implement `Typed`, you will now need
to do so.
# Objective
Fixes#14980
## Solution
Only iterate over archetypes containing the component.
## Alternatives
Additionally, for each archetype, cache how many observers are watching
one of its components & use this to speed up the check for each affected
archetype ([implemented
here](55c89aa033)).
Benchmarking showed this to lead only to a minor speedup.
## Testing
There's both already a test checking that observers don't run after
being despawned as well as a regression test for the bug that
necessitates the check this PR optimizes.
# Objective
Applies feedback from previous PR #15135 'cause it got caught up in the
merge train 🚂
I couldn't resist including roll, both for completeness and due to
playing too many games that implemented it as a child.
cc: @janhohenheim
# Objective
Fixes https://github.com/bevyengine/bevy/issues/13225
## Solution
Invalidate `TrackedRenderPass` internal state upon accessing internal
`wgpu::RenderPass`.
## Testing
- Tested by calling `set_bind_group` on `RenderPass` returned by
`TrackedRenderPass::wgpu_pass` and checking if in later `set_bind_group`
calls on `TrackedRenderPass` correct bind group is restored.
# Objective
- Finish resolving https://github.com/bevyengine/bevy/issues/15125
- Inserting bundles was implemented in
https://github.com/bevyengine/bevy/pull/15128 but removing bundles still
needed to be implemented.
## Solution
- Modified `bevy_ecs::reflect::entity_commands::remove_reflect` to
handle both components and bundles
- Modified documentation of `ReflectCommandExt` methods to reflect that
one can now use bundles with these commands.
## Testing
- Three tests were added to match the ones for inserting components.
# Objective
- Remove any ambiguity around how multiple `Observer` components work on
a single `Entity` by completely removing the concept.
- Fixes#15122
## Solution
- Removed type parameters from `Observer`, relying on a function pointer
to provide type information into the relevant aspects of running an
observer.
## Testing
- Ran CI locally.
- Checked `observers.rs` example continued to function as expected.
## Notes
This communicates to users of observers that only a single `Observer`
can be inserted onto an entity at a time within the established type
system. This has been achieved by erasing the type information from the
stored `ObserverSystem` and retrieving it again using a function
pointer. This has the downside of increasing the size of the `Observer`
component and increases the complexity of the observer runner. However,
this complexity was already present, and is in my opinion a worthwhile
tradeoff for the clearer user experience.
The other notable benefit is users no longer need to use the
`ObserverState` component to filter for `Observer` entities, and can
instead use `Observer` directly.
Technically this is a breaking change, since the type signature for
`Observer` has changed. However, it was so cumbersome to use that I
don't believe there are any instances in the wild of users directly
naming `Observer` types, instead relying on `ObserverState`, and the
methods provided by `App` and `World`. As can be seen in the diff, this
change had very little knock-on effects across Bevy.
## Migration Guide
If you filtered for observers using `Observer<A, B>`, instead filter for
an `Observer`.
---------
Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
# Objective
Fixes#15079 , repairing the `game_menu` example
## Solution
- Changed the target component for the color updates from `UiImage` to
`BackgroundColor`.
- Changed the width of the `button_style` to `300px` to prevent overlap
with the text.
## Testing
Checked that buttons now correctly update their background color on
hover/exit/press.
---
## Showcase
https://github.com/user-attachments/assets/8f7ede9b-c271-4b59-91f9-27d9e3db1429
# Objective
The module docs for `bevy_reflect::func` don't mention the
`FunctionRegistry`.
## Solution
Add a section about the `FunctionRegistry` to the module-level
documentation.
## Testing
You can test locally by running:
```
cargo test --doc --package bevy_reflect --all-features
```