diff --git a/crates/bevy_sprite/src/bundle.rs b/crates/bevy_sprite/src/bundle.rs index 1b8bb36c3f..fdc2f8ed51 100644 --- a/crates/bevy_sprite/src/bundle.rs +++ b/crates/bevy_sprite/src/bundle.rs @@ -8,12 +8,6 @@ use bevy_render::{ use bevy_transform::components::{GlobalTransform, Transform}; /// A [`Bundle`] of components for drawing a single sprite from an image. -/// -/// # Extra behaviors -/// -/// You may add one or both of the following components to enable additional behaviors: -/// - [`ImageScaleMode`](crate::ImageScaleMode) to enable either slicing or tiling of the texture -/// - [`TextureAtlas`](crate::TextureAtlas) to draw a specific section of the texture #[derive(Bundle, Clone, Debug, Default)] #[deprecated( since = "0.15.0", diff --git a/crates/bevy_sprite/src/lib.rs b/crates/bevy_sprite/src/lib.rs index ce62a1e975..265be52209 100644 --- a/crates/bevy_sprite/src/lib.rs +++ b/crates/bevy_sprite/src/lib.rs @@ -30,7 +30,7 @@ pub mod prelude { #[doc(hidden)] pub use crate::{ bundle::SpriteBundle, - sprite::{ImageScaleMode, Sprite}, + sprite::{Sprite, SpriteImageMode}, texture_atlas::{TextureAtlas, TextureAtlasLayout, TextureAtlasSources}, texture_slice::{BorderRect, SliceScaleMode, TextureSlice, TextureSlicer}, ColorMaterial, ColorMesh2dBundle, MeshMaterial2d, TextureAtlasBuilder, @@ -106,7 +106,7 @@ impl Plugin for SpritePlugin { app.init_asset::() .register_asset_reflect::() .register_type::() - .register_type::() + .register_type::() .register_type::() .register_type::() .register_type::() diff --git a/crates/bevy_sprite/src/sprite.rs b/crates/bevy_sprite/src/sprite.rs index f6a4da9949..88faf4af10 100644 --- a/crates/bevy_sprite/src/sprite.rs +++ b/crates/bevy_sprite/src/sprite.rs @@ -34,6 +34,8 @@ pub struct Sprite { pub rect: Option, /// [`Anchor`] point of the sprite in the world pub anchor: Anchor, + /// How the sprite's image will be scaled. + pub image_mode: SpriteImageMode, } impl Sprite { @@ -79,9 +81,12 @@ impl From> for Sprite { } /// Controls how the image is altered when scaled. -#[derive(Component, Debug, Clone, Reflect)] -#[reflect(Component, Debug)] -pub enum ImageScaleMode { +#[derive(Default, Debug, Clone, Reflect, PartialEq)] +#[reflect(Debug)] +pub enum SpriteImageMode { + /// The sprite will take on the size of the image by default, and will be stretched or shrunk if [`Sprite::custom_size`] is set. + #[default] + Auto, /// The texture will be cut in 9 slices, keeping the texture in proportions on resize Sliced(TextureSlicer), /// The texture will be repeated if stretched beyond `stretched_value` @@ -96,6 +101,17 @@ pub enum ImageScaleMode { }, } +impl SpriteImageMode { + /// Returns true if this mode uses slices internally ([`SpriteImageMode::Sliced`] or [`SpriteImageMode::Tiled`]) + #[inline] + pub fn uses_slices(&self) -> bool { + matches!( + self, + SpriteImageMode::Sliced(..) | SpriteImageMode::Tiled { .. } + ) + } +} + /// How a sprite is positioned relative to its [`Transform`]. /// It defaults to `Anchor::Center`. #[derive(Component, Debug, Clone, Copy, PartialEq, Default, Reflect)] diff --git a/crates/bevy_sprite/src/texture_slice/computed_slices.rs b/crates/bevy_sprite/src/texture_slice/computed_slices.rs index 25b23c7025..6e2d94198c 100644 --- a/crates/bevy_sprite/src/texture_slice/computed_slices.rs +++ b/crates/bevy_sprite/src/texture_slice/computed_slices.rs @@ -1,4 +1,4 @@ -use crate::{ExtractedSprite, ImageScaleMode, Sprite, TextureAtlasLayout}; +use crate::{ExtractedSprite, Sprite, SpriteImageMode, TextureAtlasLayout}; use super::TextureSlice; use bevy_asset::{AssetEvent, Assets}; @@ -8,7 +8,7 @@ use bevy_render::texture::Image; use bevy_transform::prelude::*; use bevy_utils::HashSet; -/// Component storing texture slices for sprite entities with a [`ImageScaleMode`] +/// Component storing texture slices for tiled or sliced sprite entities /// /// This component is automatically inserted and updated #[derive(Debug, Clone, Component)] @@ -69,24 +69,19 @@ impl ComputedTextureSlices { } } -/// Generates sprite slices for a `sprite` given a `scale_mode`. The slices +/// Generates sprite slices for a [`Sprite`] with [`SpriteImageMode::Sliced`] or [`SpriteImageMode::Sliced`]. The slices /// will be computed according to the `image_handle` dimensions or the sprite rect. /// /// Returns `None` if the image asset is not loaded /// /// # Arguments /// -/// * `sprite` - The sprite component, will be used to find the draw area size -/// * `scale_mode` - The image scaling component -/// * `image_handle` - The texture to slice or tile +/// * `sprite` - The sprite component with the image handle and image mode /// * `images` - The image assets, use to retrieve the image dimensions -/// * `atlas` - Optional texture atlas, if set the slicing will happen on the matching sub section -/// of the texture /// * `atlas_layouts` - The atlas layout assets, used to retrieve the texture atlas section rect #[must_use] fn compute_sprite_slices( sprite: &Sprite, - scale_mode: &ImageScaleMode, images: &Assets, atlas_layouts: &Assets, ) -> Option { @@ -111,9 +106,9 @@ fn compute_sprite_slices( (size, rect) } }; - let slices = match scale_mode { - ImageScaleMode::Sliced(slicer) => slicer.compute_slices(texture_rect, sprite.custom_size), - ImageScaleMode::Tiled { + let slices = match &sprite.image_mode { + SpriteImageMode::Sliced(slicer) => slicer.compute_slices(texture_rect, sprite.custom_size), + SpriteImageMode::Tiled { tile_x, tile_y, stretch_value, @@ -125,18 +120,21 @@ fn compute_sprite_slices( }; slice.tiled(*stretch_value, (*tile_x, *tile_y)) } + SpriteImageMode::Auto => { + unreachable!("Slices should not be computed for SpriteImageMode::Stretch") + } }; Some(ComputedTextureSlices(slices)) } /// System reacting to added or modified [`Image`] handles, and recompute sprite slices -/// on matching sprite entities with a [`ImageScaleMode`] component +/// on sprite entities with a matching [`SpriteImageMode`] pub(crate) fn compute_slices_on_asset_event( mut commands: Commands, mut events: EventReader>, images: Res>, atlas_layouts: Res>, - sprites: Query<(Entity, &ImageScaleMode, &Sprite)>, + sprites: Query<(Entity, &Sprite)>, ) { // We store the asset ids of added/modified image assets let added_handles: HashSet<_> = events @@ -150,29 +148,31 @@ pub(crate) fn compute_slices_on_asset_event( return; } // We recompute the sprite slices for sprite entities with a matching asset handle id - for (entity, scale_mode, sprite) in &sprites { + for (entity, sprite) in &sprites { + if !sprite.image_mode.uses_slices() { + continue; + } if !added_handles.contains(&sprite.image.id()) { continue; } - if let Some(slices) = compute_sprite_slices(sprite, scale_mode, &images, &atlas_layouts) { + if let Some(slices) = compute_sprite_slices(sprite, &images, &atlas_layouts) { commands.entity(entity).insert(slices); } } } -/// System reacting to changes on relevant sprite bundle components to compute the sprite slices -/// on matching sprite entities with a [`ImageScaleMode`] component +/// System reacting to changes on the [`Sprite`] component to compute the sprite slices pub(crate) fn compute_slices_on_sprite_change( mut commands: Commands, images: Res>, atlas_layouts: Res>, - changed_sprites: Query< - (Entity, &ImageScaleMode, &Sprite), - Or<(Changed, Changed)>, - >, + changed_sprites: Query<(Entity, &Sprite), Changed>, ) { - for (entity, scale_mode, sprite) in &changed_sprites { - if let Some(slices) = compute_sprite_slices(sprite, scale_mode, &images, &atlas_layouts) { + for (entity, sprite) in &changed_sprites { + if !sprite.image_mode.uses_slices() { + continue; + } + if let Some(slices) = compute_sprite_slices(sprite, &images, &atlas_layouts) { commands.entity(entity).insert(slices); } } diff --git a/crates/bevy_sprite/src/texture_slice/slicer.rs b/crates/bevy_sprite/src/texture_slice/slicer.rs index ea32f1122b..325e7ccb2b 100644 --- a/crates/bevy_sprite/src/texture_slice/slicer.rs +++ b/crates/bevy_sprite/src/texture_slice/slicer.rs @@ -10,7 +10,7 @@ use bevy_reflect::Reflect; /// sections will be scaled or tiled. /// /// See [9-sliced](https://en.wikipedia.org/wiki/9-slice_scaling) textures. -#[derive(Debug, Clone, Reflect)] +#[derive(Debug, Clone, Reflect, PartialEq)] pub struct TextureSlicer { /// The sprite borders, defining the 9 sections of the image pub border: BorderRect, @@ -23,7 +23,7 @@ pub struct TextureSlicer { } /// Defines how a texture slice scales when resized -#[derive(Debug, Copy, Clone, Default, Reflect)] +#[derive(Debug, Copy, Clone, Default, Reflect, PartialEq)] pub enum SliceScaleMode { /// The slice will be stretched to fit the area #[default] diff --git a/crates/bevy_ui/src/layout/mod.rs b/crates/bevy_ui/src/layout/mod.rs index c613e02aca..5d163a34f1 100644 --- a/crates/bevy_ui/src/layout/mod.rs +++ b/crates/bevy_ui/src/layout/mod.rs @@ -221,7 +221,7 @@ pub fn ui_layout_system( || node.is_changed() || content_size .as_ref() - .map(|c| c.measure.is_some()) + .map(|c| c.is_changed() || c.measure.is_some()) .unwrap_or(false) { let layout_context = LayoutContext::new( diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index 15af4b3fe3..6edd497f17 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -62,7 +62,7 @@ pub mod prelude { Interaction, MaterialNode, UiMaterialPlugin, UiScale, }, // `bevy_sprite` re-exports for texture slicing - bevy_sprite::{BorderRect, ImageScaleMode, SliceScaleMode, TextureSlicer}, + bevy_sprite::{BorderRect, SliceScaleMode, SpriteImageMode, TextureSlicer}, }; } diff --git a/crates/bevy_ui/src/node_bundles.rs b/crates/bevy_ui/src/node_bundles.rs index 4e0723cfb1..18d1162f28 100644 --- a/crates/bevy_ui/src/node_bundles.rs +++ b/crates/bevy_ui/src/node_bundles.rs @@ -57,12 +57,6 @@ pub struct NodeBundle { } /// A UI node that is an image -/// -/// # Extra behaviors -/// -/// You may add one or both of the following components to enable additional behaviors: -/// - [`ImageScaleMode`](bevy_sprite::ImageScaleMode) to enable either slicing or tiling of the texture -/// - [`TextureAtlas`](bevy_sprite::TextureAtlas) to draw a specific section of the texture #[derive(Bundle, Debug, Default)] #[deprecated( since = "0.15.0", @@ -110,12 +104,6 @@ pub struct ImageBundle { } /// A UI node that is a button -/// -/// # Extra behaviors -/// -/// You may add one or both of the following components to enable additional behaviors: -/// - [`ImageScaleMode`](bevy_sprite::ImageScaleMode) to enable either slicing or tiling of the texture -/// - [`TextureAtlas`](bevy_sprite::TextureAtlas) to draw a specific section of the texture #[derive(Bundle, Clone, Debug)] #[deprecated( since = "0.15.0", diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index e194df93b8..417a6593d1 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -41,7 +41,7 @@ use bevy_render::{ ExtractSchedule, Render, }; use bevy_sprite::TextureAtlasLayout; -use bevy_sprite::{BorderRect, ImageScaleMode, SpriteAssetEvents}; +use bevy_sprite::{BorderRect, SpriteAssetEvents}; use crate::{Display, Node}; use bevy_text::{ComputedTextBlock, PositionedGlyph, TextColor, TextLayoutInfo}; @@ -309,18 +309,15 @@ pub fn extract_uinode_images( texture_atlases: Extract>>, default_ui_camera: Extract, uinode_query: Extract< - Query< - ( - Entity, - &ComputedNode, - &GlobalTransform, - &ViewVisibility, - Option<&CalculatedClip>, - Option<&TargetCamera>, - &UiImage, - ), - Without, - >, + Query<( + Entity, + &ComputedNode, + &GlobalTransform, + &ViewVisibility, + Option<&CalculatedClip>, + Option<&TargetCamera>, + &UiImage, + )>, >, mapping: Extract>, ) { @@ -338,6 +335,7 @@ pub fn extract_uinode_images( if !view_visibility.get() || image.color.is_fully_transparent() || image.image.id() == TRANSPARENT_IMAGE_HANDLE.id() + || image.image_mode.uses_slices() { continue; } diff --git a/crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs b/crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs index e6fabe06a7..2824186bbe 100644 --- a/crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs +++ b/crates/bevy_ui/src/render/ui_texture_slice_pipeline.rs @@ -24,7 +24,7 @@ use bevy_render::{ Extract, ExtractSchedule, Render, RenderSet, }; use bevy_sprite::{ - ImageScaleMode, SliceScaleMode, SpriteAssetEvents, TextureAtlasLayout, TextureSlicer, + SliceScaleMode, SpriteAssetEvents, SpriteImageMode, TextureAtlasLayout, TextureSlicer, }; use bevy_transform::prelude::GlobalTransform; use bevy_utils::HashMap; @@ -232,7 +232,7 @@ pub struct ExtractedUiTextureSlice { pub clip: Option, pub camera_entity: Entity, pub color: LinearRgba, - pub image_scale_mode: ImageScaleMode, + pub image_scale_mode: SpriteImageMode, pub flip_x: bool, pub flip_y: bool, pub main_entity: MainEntity, @@ -257,14 +257,11 @@ pub fn extract_ui_texture_slices( Option<&CalculatedClip>, Option<&TargetCamera>, &UiImage, - &ImageScaleMode, )>, >, mapping: Extract>, ) { - for (entity, uinode, transform, view_visibility, clip, camera, image, image_scale_mode) in - &slicers_query - { + for (entity, uinode, transform, view_visibility, clip, camera, image) in &slicers_query { let Some(camera_entity) = camera.map(TargetCamera::entity).or(default_ui_camera.get()) else { continue; @@ -274,6 +271,22 @@ pub fn extract_ui_texture_slices( continue; }; + let image_scale_mode = match image.image_mode.clone() { + widget::NodeImageMode::Sliced(texture_slicer) => { + SpriteImageMode::Sliced(texture_slicer) + } + widget::NodeImageMode::Tiled { + tile_x, + tile_y, + stretch_value, + } => SpriteImageMode::Tiled { + tile_x, + tile_y, + stretch_value, + }, + _ => continue, + }; + // Skip invisible images if !view_visibility.get() || image.color.is_fully_transparent() @@ -312,7 +325,7 @@ pub fn extract_ui_texture_slices( clip: clip.map(|clip| clip.clip), image: image.image.id(), camera_entity, - image_scale_mode: image_scale_mode.clone(), + image_scale_mode, atlas_rect, flip_x: image.flip_x, flip_y: image.flip_y, @@ -719,10 +732,10 @@ impl RenderCommand

for DrawSlicer { fn compute_texture_slices( image_size: Vec2, target_size: Vec2, - image_scale_mode: &ImageScaleMode, + image_scale_mode: &SpriteImageMode, ) -> [[f32; 4]; 3] { match image_scale_mode { - ImageScaleMode::Sliced(TextureSlicer { + SpriteImageMode::Sliced(TextureSlicer { border: border_rect, center_scale_mode, sides_scale_mode, @@ -775,7 +788,7 @@ fn compute_texture_slices( ], ] } - ImageScaleMode::Tiled { + SpriteImageMode::Tiled { tile_x, tile_y, stretch_value, @@ -784,6 +797,9 @@ fn compute_texture_slices( let ry = compute_tiled_axis(*tile_y, image_size.y, target_size.y, *stretch_value); [[0., 0., 1., 1.], [0., 0., 1., 1.], [1., 1., rx, ry]] } + SpriteImageMode::Auto => { + unreachable!("Slices should not be computed for ImageScaleMode::Stretch") + } } } diff --git a/crates/bevy_ui/src/widget/image.rs b/crates/bevy_ui/src/widget/image.rs index 049424ca14..83dbc1fc76 100644 --- a/crates/bevy_ui/src/widget/image.rs +++ b/crates/bevy_ui/src/widget/image.rs @@ -5,14 +5,14 @@ use bevy_ecs::prelude::*; use bevy_math::{Rect, UVec2, Vec2}; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::texture::{Image, TRANSPARENT_IMAGE_HANDLE}; -use bevy_sprite::{TextureAtlas, TextureAtlasLayout}; +use bevy_sprite::{TextureAtlas, TextureAtlasLayout, TextureSlicer}; use bevy_window::{PrimaryWindow, Window}; use taffy::{MaybeMath, MaybeResolve}; /// The 2D texture displayed for this UI node #[derive(Component, Clone, Debug, Reflect)] #[reflect(Component, Default, Debug)] -#[require(Node, UiImageSize, ContentSize)] +#[require(Node, UiImageSize)] pub struct UiImage { /// The tint color used to draw the image. /// @@ -23,11 +23,11 @@ pub struct UiImage { /// /// This defaults to a [`TRANSPARENT_IMAGE_HANDLE`], which points to a fully transparent 1x1 texture. pub image: Handle, - /// The (optional) texture atlas used to render the image + /// The (optional) texture atlas used to render the image. pub texture_atlas: Option, - /// Whether the image should be flipped along its x-axis + /// Whether the image should be flipped along its x-axis. pub flip_x: bool, - /// Whether the image should be flipped along its y-axis + /// Whether the image should be flipped along its y-axis. pub flip_y: bool, /// An optional rectangle representing the region of the image to render, instead of rendering /// the full image. This is an easy one-off alternative to using a [`TextureAtlas`]. @@ -35,6 +35,8 @@ pub struct UiImage { /// When used with a [`TextureAtlas`], the rect /// is offset by the atlas's minimal (top-left) corner position. pub rect: Option, + /// Controls how the image is altered to fit within the layout and how the layout algorithm determines the space to allocate for the image. + pub image_mode: NodeImageMode, } impl Default for UiImage { @@ -56,6 +58,7 @@ impl Default for UiImage { flip_x: false, flip_y: false, rect: None, + image_mode: NodeImageMode::Auto, } } } @@ -81,6 +84,7 @@ impl UiImage { flip_y: false, texture_atlas: None, rect: None, + image_mode: NodeImageMode::Auto, } } @@ -119,6 +123,12 @@ impl UiImage { self.rect = Some(rect); self } + + #[must_use] + pub const fn with_mode(mut self, mode: NodeImageMode) -> Self { + self.image_mode = mode; + self + } } impl From> for UiImage { @@ -127,6 +137,39 @@ impl From> for UiImage { } } +/// Controls how the image is altered to fit within the layout and how the layout algorithm determines the space in the layout for the image +#[derive(Default, Debug, Clone, Reflect)] +pub enum NodeImageMode { + /// The image will be sized automatically by taking the size of the source image and applying any layout constraints. + #[default] + Auto, + /// The image will be resized to match the size of the node. The image's original size and aspect ratio will be ignored. + Stretch, + /// The texture will be cut in 9 slices, keeping the texture in proportions on resize + Sliced(TextureSlicer), + /// The texture will be repeated if stretched beyond `stretched_value` + Tiled { + /// Should the image repeat horizontally + tile_x: bool, + /// Should the image repeat vertically + tile_y: bool, + /// The texture will repeat when the ratio between the *drawing dimensions* of texture and the + /// *original texture size* are above this value. + stretch_value: f32, + }, +} + +impl NodeImageMode { + /// Returns true if this mode uses slices internally ([`NodeImageMode::Sliced`] or [`NodeImageMode::Tiled`]) + #[inline] + pub fn uses_slices(&self) -> bool { + matches!( + self, + NodeImageMode::Sliced(..) | NodeImageMode::Tiled { .. } + ) + } +} + /// The size of the image's texture /// /// This component is updated automatically by [`update_image_content_size_system`] @@ -216,7 +259,7 @@ pub fn update_image_content_size_system( textures: Res>, atlases: Res>, - mut query: Query<(&mut ContentSize, &UiImage, &mut UiImageSize), UpdateImageFilter>, + mut query: Query<(&mut ContentSize, Ref, &mut UiImageSize), UpdateImageFilter>, ) { let combined_scale_factor = windows .get_single() @@ -225,6 +268,14 @@ pub fn update_image_content_size_system( * ui_scale.0; for (mut content_size, image, mut image_size) in &mut query { + if !matches!(image.image_mode, NodeImageMode::Auto) { + if image.is_changed() { + // Mutably derefs, marking the `ContentSize` as changed ensuring `ui_layout_system` will remove the node's measure func if present. + content_size.measure = None; + } + continue; + } + if let Some(size) = match &image.texture_atlas { Some(atlas) => atlas.texture_rect(&atlases).map(|t| t.size()), None => textures.get(&image.image).map(Image::size), diff --git a/examples/2d/sprite_slice.rs b/examples/2d/sprite_slice.rs index 0dae09dce5..2542eb44c6 100644 --- a/examples/2d/sprite_slice.rs +++ b/examples/2d/sprite_slice.rs @@ -19,55 +19,65 @@ fn spawn_sprites( ) { let cases = [ // Reference sprite - ("Original", style.clone(), Vec2::splat(100.0), None), + ( + "Original", + style.clone(), + Vec2::splat(100.0), + SpriteImageMode::Auto, + ), // Scaled regular sprite - ("Stretched", style.clone(), Vec2::new(100.0, 200.0), None), + ( + "Stretched", + style.clone(), + Vec2::new(100.0, 200.0), + SpriteImageMode::Auto, + ), // Stretched Scaled sliced sprite ( "With Slicing", style.clone(), Vec2::new(100.0, 200.0), - Some(ImageScaleMode::Sliced(TextureSlicer { + SpriteImageMode::Sliced(TextureSlicer { border: BorderRect::square(slice_border), center_scale_mode: SliceScaleMode::Stretch, ..default() - })), + }), ), // Scaled sliced sprite ( "With Tiling", style.clone(), Vec2::new(100.0, 200.0), - Some(ImageScaleMode::Sliced(TextureSlicer { + SpriteImageMode::Sliced(TextureSlicer { border: BorderRect::square(slice_border), center_scale_mode: SliceScaleMode::Tile { stretch_value: 0.5 }, sides_scale_mode: SliceScaleMode::Tile { stretch_value: 0.2 }, ..default() - })), + }), ), // Scaled sliced sprite horizontally ( "With Tiling", style.clone(), Vec2::new(300.0, 200.0), - Some(ImageScaleMode::Sliced(TextureSlicer { + SpriteImageMode::Sliced(TextureSlicer { border: BorderRect::square(slice_border), center_scale_mode: SliceScaleMode::Tile { stretch_value: 0.2 }, sides_scale_mode: SliceScaleMode::Tile { stretch_value: 0.3 }, ..default() - })), + }), ), // Scaled sliced sprite horizontally with max scale ( "With Corners Constrained", style, Vec2::new(300.0, 200.0), - Some(ImageScaleMode::Sliced(TextureSlicer { + SpriteImageMode::Sliced(TextureSlicer { border: BorderRect::square(slice_border), center_scale_mode: SliceScaleMode::Tile { stretch_value: 0.1 }, sides_scale_mode: SliceScaleMode::Tile { stretch_value: 0.2 }, max_corner_scale: 0.2, - })), + }), ), ]; @@ -77,13 +87,11 @@ fn spawn_sprites( Sprite { image: texture_handle.clone(), custom_size: Some(size), + image_mode: scale_mode, ..default() }, Transform::from_translation(position), )); - if let Some(scale_mode) = scale_mode { - cmd.insert(scale_mode); - } cmd.with_children(|builder| { builder.spawn(( Text2d::new(label), diff --git a/examples/2d/sprite_tile.rs b/examples/2d/sprite_tile.rs index 9755059b21..4809874ace 100644 --- a/examples/2d/sprite_tile.rs +++ b/examples/2d/sprite_tile.rs @@ -26,14 +26,15 @@ fn setup(mut commands: Commands, asset_server: Res) { current: 128.0, speed: 50.0, }); - commands.spawn(( - Sprite::from_image(asset_server.load("branding/icon.png")), - ImageScaleMode::Tiled { + commands.spawn(Sprite { + image: asset_server.load("branding/icon.png"), + image_mode: SpriteImageMode::Tiled { tile_x: true, tile_y: true, stretch_value: 0.5, // The image will tile every 128px }, - )); + ..default() + }); } fn animate(mut sprites: Query<&mut Sprite>, mut state: ResMut, time: Res