mirror of
https://github.com/bevyengine/bevy
synced 2024-12-24 12:03:14 +00:00
8a3a8b5cfb
# Objective We switch back and forwards between logical and physical coordinates all over the place. Systems have to query for cameras and the UiScale when they shouldn't need to. It's confusing and fragile and new scale factor bugs get found constantly. ## Solution * Use physical coordinates whereever possible in `bevy_ui`. * Store physical coords in `ComputedNode` and tear out all the unneeded scale factor calculations and queries. * Add an `inverse_scale_factor` field to `ComputedNode` and set nodes changed when their scale factor changes. ## Migration Guide `ComputedNode`'s fields and methods now use physical coordinates. `ComputedNode` has a new field `inverse_scale_factor`. Multiplying the physical coordinates by the `inverse_scale_factor` will give the logical values. --------- Co-authored-by: atlv <email@atlasdostal.com>
74 lines
2.8 KiB
Rust
74 lines
2.8 KiB
Rust
//! This example illustrates how to how to flip and tile images with 9-slicing in the UI.
|
|
|
|
use bevy::{
|
|
image::{ImageLoaderSettings, ImageSampler},
|
|
prelude::*,
|
|
ui::widget::NodeImageMode,
|
|
winit::WinitSettings,
|
|
};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.add_plugins(DefaultPlugins)
|
|
.insert_resource(UiScale(2.))
|
|
// Only run the app when there is user input. This will significantly reduce CPU/GPU use for UI-only apps.
|
|
.insert_resource(WinitSettings::desktop_app())
|
|
.add_systems(Startup, setup)
|
|
.run();
|
|
}
|
|
|
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
|
|
let image = asset_server.load_with_settings(
|
|
"textures/fantasy_ui_borders/numbered_slices.png",
|
|
|settings: &mut ImageLoaderSettings| {
|
|
// Need to use nearest filtering to avoid bleeding between the slices with tiling
|
|
settings.sampler = ImageSampler::nearest();
|
|
},
|
|
);
|
|
|
|
let slicer = TextureSlicer {
|
|
// `numbered_slices.png` is 48 pixels square. `BorderRect::square(16.)` insets the slicing line from each edge by 16 pixels, resulting in nine slices that are each 16 pixels square.
|
|
border: BorderRect::square(16.),
|
|
// With `SliceScaleMode::Tile` the side and center slices are tiled to fill the side and center sections of the target.
|
|
// And with a `stretch_value` of `1.` the tiles will have the same size as the corresponding slices in the source image.
|
|
center_scale_mode: SliceScaleMode::Tile { stretch_value: 1. },
|
|
sides_scale_mode: SliceScaleMode::Tile { stretch_value: 1. },
|
|
..default()
|
|
};
|
|
|
|
// ui camera
|
|
commands.spawn(Camera2d);
|
|
|
|
commands
|
|
.spawn(Node {
|
|
width: Val::Percent(100.),
|
|
height: Val::Percent(100.),
|
|
justify_content: JustifyContent::Center,
|
|
align_content: AlignContent::Center,
|
|
flex_wrap: FlexWrap::Wrap,
|
|
column_gap: Val::Px(10.),
|
|
row_gap: Val::Px(10.),
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
for [columns, rows] in [[3., 3.], [4., 4.], [5., 4.], [4., 5.], [5., 5.]] {
|
|
for (flip_x, flip_y) in [(false, false), (false, true), (true, false), (true, true)]
|
|
{
|
|
parent.spawn((
|
|
ImageNode {
|
|
image: image.clone(),
|
|
flip_x,
|
|
flip_y,
|
|
image_mode: NodeImageMode::Sliced(slicer.clone()),
|
|
..default()
|
|
},
|
|
Node {
|
|
width: Val::Px(16. * columns),
|
|
height: Val::Px(16. * rows),
|
|
..default()
|
|
},
|
|
));
|
|
}
|
|
}
|
|
});
|
|
}
|