Migrate bevy_sprite to required components (#15489)

# Objective

Continue migration of bevy APIs to required components, following
guidance of https://hackmd.io/@bevy/required_components/

## Solution

- Make `Sprite` require `Transform` and `Visibility` and
`SyncToRenderWorld`
- move image and texture atlas handles into `Sprite`
- deprecate `SpriteBundle`
- remove engine uses of `SpriteBundle`

## Testing

ran cargo tests on bevy_sprite and tested several sprite examples.

---

## Migration Guide

Replace all uses of `SpriteBundle` with `Sprite`. There are several new
convenience constructors: `Sprite::from_image`,
`Sprite::from_atlas_image`, `Sprite::from_color`.

WARNING: use of `Handle<Image>` and `TextureAtlas` as components on
sprite entities will NO LONGER WORK. Use the fields on `Sprite` instead.
I would have removed the `Component` impls from `TextureAtlas` and
`Handle<Image>` except it is still used within ui. We should fix this
moving forward with the migration.
This commit is contained in:
Emerson Coskey 2024-10-09 09:17:26 -07:00 committed by GitHub
parent 219b5930f1
commit 7d40e3ec87
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 456 additions and 676 deletions

View file

@ -77,8 +77,6 @@ use core::{any::TypeId, ptr::NonNull};
/// Additionally, [Tuples](`tuple`) of bundles are also [`Bundle`] (with up to 15 bundles). /// Additionally, [Tuples](`tuple`) of bundles are also [`Bundle`] (with up to 15 bundles).
/// These bundles contain the items of the 'inner' bundles. /// These bundles contain the items of the 'inner' bundles.
/// This is a convenient shorthand which is primarily used when spawning entities. /// This is a convenient shorthand which is primarily used when spawning entities.
/// For example, spawning an entity using the bundle `(SpriteBundle {...}, PlayerMarker)`
/// will spawn an entity with components required for a 2d sprite, and the `PlayerMarker` component.
/// ///
/// [`unit`], otherwise known as [`()`](`unit`), is a [`Bundle`] containing no components (since it /// [`unit`], otherwise known as [`()`](`unit`), is a [`Bundle`] containing no components (since it
/// can also be considered as the empty tuple). /// can also be considered as the empty tuple).

View file

@ -1,3 +1,4 @@
#![expect(deprecated)]
use crate::Sprite; use crate::Sprite;
use bevy_asset::Handle; use bevy_asset::Handle;
use bevy_ecs::bundle::Bundle; use bevy_ecs::bundle::Bundle;
@ -16,6 +17,10 @@ use bevy_transform::components::{GlobalTransform, Transform};
/// - [`ImageScaleMode`](crate::ImageScaleMode) to enable either slicing or tiling of the texture /// - [`ImageScaleMode`](crate::ImageScaleMode) to enable either slicing or tiling of the texture
/// - [`TextureAtlas`](crate::TextureAtlas) to draw a specific section of the texture /// - [`TextureAtlas`](crate::TextureAtlas) to draw a specific section of the texture
#[derive(Bundle, Clone, Debug, Default)] #[derive(Bundle, Clone, Debug, Default)]
#[deprecated(
since = "0.15.0",
note = "Use the `Sprite` component instead. Inserting it will now also insert `Transform` and `Visibility` automatically."
)]
pub struct SpriteBundle { pub struct SpriteBundle {
/// Specifies the rendering properties of the sprite, such as color tint and flip. /// Specifies the rendering properties of the sprite, such as color tint and flip.
pub sprite: Sprite, pub sprite: Sprite,

View file

@ -185,9 +185,9 @@ pub fn calculate_bounds_2d(
atlases: Res<Assets<TextureAtlasLayout>>, atlases: Res<Assets<TextureAtlasLayout>>,
meshes_without_aabb: Query<(Entity, &Mesh2d), (Without<Aabb>, Without<NoFrustumCulling>)>, meshes_without_aabb: Query<(Entity, &Mesh2d), (Without<Aabb>, Without<NoFrustumCulling>)>,
sprites_to_recalculate_aabb: Query< sprites_to_recalculate_aabb: Query<
(Entity, &Sprite, &Handle<Image>, Option<&TextureAtlas>), (Entity, &Sprite),
( (
Or<(Without<Aabb>, Changed<Sprite>, Changed<TextureAtlas>)>, Or<(Without<Aabb>, Changed<Sprite>)>,
Without<NoFrustumCulling>, Without<NoFrustumCulling>,
), ),
>, >,
@ -199,13 +199,13 @@ pub fn calculate_bounds_2d(
} }
} }
} }
for (entity, sprite, texture_handle, atlas) in &sprites_to_recalculate_aabb { for (entity, sprite) in &sprites_to_recalculate_aabb {
if let Some(size) = sprite if let Some(size) = sprite
.custom_size .custom_size
.or_else(|| sprite.rect.map(|rect| rect.size())) .or_else(|| sprite.rect.map(|rect| rect.size()))
.or_else(|| match atlas { .or_else(|| match &sprite.texture_atlas {
// We default to the texture size for regular sprites // We default to the texture size for regular sprites
None => images.get(texture_handle).map(Image::size_f32), None => images.get(&sprite.image).map(Image::size_f32),
// We default to the drawn rect for atlas sprites // We default to the drawn rect for atlas sprites
Some(atlas) => atlas Some(atlas) => atlas
.texture_rect(&atlases) .texture_rect(&atlases)
@ -259,10 +259,7 @@ mod test {
app.add_systems(Update, calculate_bounds_2d); app.add_systems(Update, calculate_bounds_2d);
// Add entities // Add entities
let entity = app let entity = app.world_mut().spawn(Sprite::from_image(image_handle)).id();
.world_mut()
.spawn((Sprite::default(), image_handle))
.id();
// Verify that the entity does not have an AABB // Verify that the entity does not have an AABB
assert!(!app assert!(!app

View file

@ -4,7 +4,7 @@
use core::cmp::Reverse; use core::cmp::Reverse;
use crate::{Sprite, TextureAtlas, TextureAtlasLayout}; use crate::{Sprite, TextureAtlasLayout};
use bevy_app::prelude::*; use bevy_app::prelude::*;
use bevy_asset::prelude::*; use bevy_asset::prelude::*;
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
@ -32,8 +32,6 @@ pub fn sprite_picking(
sprite_query: Query<( sprite_query: Query<(
Entity, Entity,
&Sprite, &Sprite,
Option<&TextureAtlas>,
&Handle<Image>,
&GlobalTransform, &GlobalTransform,
Option<&PickingBehavior>, Option<&PickingBehavior>,
&ViewVisibility, &ViewVisibility,
@ -42,9 +40,9 @@ pub fn sprite_picking(
) { ) {
let mut sorted_sprites: Vec<_> = sprite_query let mut sorted_sprites: Vec<_> = sprite_query
.iter() .iter()
.filter(|x| !x.4.affine().is_nan()) .filter(|x| !x.2.affine().is_nan())
.collect(); .collect();
sorted_sprites.sort_by_key(|x| Reverse(FloatOrd(x.4.translation().z))); sorted_sprites.sort_by_key(|x| Reverse(FloatOrd(x.2.translation().z)));
let primary_window = primary_window.get_single().ok(); let primary_window = primary_window.get_single().ok();
@ -77,82 +75,79 @@ pub fn sprite_picking(
.iter() .iter()
.copied() .copied()
.filter(|(.., visibility)| visibility.get()) .filter(|(.., visibility)| visibility.get())
.filter_map( .filter_map(|(entity, sprite, sprite_transform, picking_behavior, ..)| {
|(entity, sprite, atlas, image, sprite_transform, picking_behavior, ..)| { if blocked {
if blocked { return None;
return None; }
}
// Hit box in sprite coordinate system // Hit box in sprite coordinate system
let extents = match (sprite.custom_size, atlas) { let extents = match (sprite.custom_size, &sprite.texture_atlas) {
(Some(custom_size), _) => custom_size, (Some(custom_size), _) => custom_size,
(None, None) => images.get(image)?.size().as_vec2(), (None, None) => images.get(&sprite.image)?.size().as_vec2(),
(None, Some(atlas)) => texture_atlas_layout (None, Some(atlas)) => texture_atlas_layout
.get(&atlas.layout) .get(&atlas.layout)
.and_then(|layout| layout.textures.get(atlas.index)) .and_then(|layout| layout.textures.get(atlas.index))
// Dropped atlas layouts and indexes out of bounds are rendered as a sprite // Dropped atlas layouts and indexes out of bounds are rendered as a sprite
.map_or(images.get(image)?.size().as_vec2(), |rect| { .map_or(images.get(&sprite.image)?.size().as_vec2(), |rect| {
rect.size().as_vec2() rect.size().as_vec2()
}), }),
}; };
let anchor = sprite.anchor.as_vec(); let anchor = sprite.anchor.as_vec();
let center = -anchor * extents; let center = -anchor * extents;
let rect = Rect::from_center_half_size(center, extents / 2.0); let rect = Rect::from_center_half_size(center, extents / 2.0);
// Transform cursor line segment to sprite coordinate system // Transform cursor line segment to sprite coordinate system
let world_to_sprite = sprite_transform.affine().inverse(); let world_to_sprite = sprite_transform.affine().inverse();
let cursor_start_sprite = let cursor_start_sprite = world_to_sprite.transform_point3(cursor_ray_world.origin);
world_to_sprite.transform_point3(cursor_ray_world.origin); let cursor_end_sprite = world_to_sprite.transform_point3(cursor_ray_end);
let cursor_end_sprite = world_to_sprite.transform_point3(cursor_ray_end);
// Find where the cursor segment intersects the plane Z=0 (which is the sprite's // Find where the cursor segment intersects the plane Z=0 (which is the sprite's
// plane in sprite-local space). It may not intersect if, for example, we're // plane in sprite-local space). It may not intersect if, for example, we're
// viewing the sprite side-on // viewing the sprite side-on
if cursor_start_sprite.z == cursor_end_sprite.z { if cursor_start_sprite.z == cursor_end_sprite.z {
// Cursor ray is parallel to the sprite and misses it // Cursor ray is parallel to the sprite and misses it
return None; return None;
} }
let lerp_factor = let lerp_factor =
f32::inverse_lerp(cursor_start_sprite.z, cursor_end_sprite.z, 0.0); f32::inverse_lerp(cursor_start_sprite.z, cursor_end_sprite.z, 0.0);
if !(0.0..=1.0).contains(&lerp_factor) { if !(0.0..=1.0).contains(&lerp_factor) {
// Lerp factor is out of range, meaning that while an infinite line cast by // Lerp factor is out of range, meaning that while an infinite line cast by
// the cursor would intersect the sprite, the sprite is not between the // the cursor would intersect the sprite, the sprite is not between the
// camera's near and far planes // camera's near and far planes
return None; return None;
} }
// Otherwise we can interpolate the xy of the start and end positions by the // Otherwise we can interpolate the xy of the start and end positions by the
// lerp factor to get the cursor position in sprite space! // lerp factor to get the cursor position in sprite space!
let cursor_pos_sprite = cursor_start_sprite let cursor_pos_sprite = cursor_start_sprite
.lerp(cursor_end_sprite, lerp_factor) .lerp(cursor_end_sprite, lerp_factor)
.xy(); .xy();
let is_cursor_in_sprite = rect.contains(cursor_pos_sprite); let is_cursor_in_sprite = rect.contains(cursor_pos_sprite);
blocked = is_cursor_in_sprite blocked = is_cursor_in_sprite
&& picking_behavior.map(|p| p.should_block_lower) != Some(false); && picking_behavior.map(|p| p.should_block_lower) != Some(false);
is_cursor_in_sprite.then(|| { is_cursor_in_sprite.then(|| {
let hit_pos_world = let hit_pos_world =
sprite_transform.transform_point(cursor_pos_sprite.extend(0.0)); sprite_transform.transform_point(cursor_pos_sprite.extend(0.0));
// Transform point from world to camera space to get the Z distance // Transform point from world to camera space to get the Z distance
let hit_pos_cam = cam_transform let hit_pos_cam = cam_transform
.affine() .affine()
.inverse() .inverse()
.transform_point3(hit_pos_world); .transform_point3(hit_pos_world);
// HitData requires a depth as calculated from the camera's near clipping plane // HitData requires a depth as calculated from the camera's near clipping plane
let depth = -cam_ortho.near - hit_pos_cam.z; let depth = -cam_ortho.near - hit_pos_cam.z;
( (
entity, entity,
HitData::new( HitData::new(
cam_entity, cam_entity,
depth, depth,
Some(hit_pos_world), Some(hit_pos_world),
Some(*sprite_transform.back()), Some(*sprite_transform.back()),
), ),
) )
}) })
}, })
)
.collect(); .collect();
let order = camera.order as f32; let order = camera.order as f32;

View file

@ -1,10 +1,10 @@
use core::ops::Range; use core::ops::Range;
use crate::{ use crate::{
texture_atlas::{TextureAtlas, TextureAtlasLayout}, texture_atlas::TextureAtlasLayout, ComputedTextureSlices, Sprite, WithSprite,
ComputedTextureSlices, Sprite, WithSprite, SPRITE_SHADER_HANDLE, SPRITE_SHADER_HANDLE,
}; };
use bevy_asset::{AssetEvent, AssetId, Assets, Handle}; use bevy_asset::{AssetEvent, AssetId, Assets};
use bevy_color::{ColorToComponents, LinearRgba}; use bevy_color::{ColorToComponents, LinearRgba};
use bevy_core_pipeline::{ use bevy_core_pipeline::{
core_2d::{Transparent2d, CORE_2D_DEPTH_FORMAT}, core_2d::{Transparent2d, CORE_2D_DEPTH_FORMAT},
@ -377,15 +377,12 @@ pub fn extract_sprites(
&ViewVisibility, &ViewVisibility,
&Sprite, &Sprite,
&GlobalTransform, &GlobalTransform,
&Handle<Image>,
Option<&TextureAtlas>,
Option<&ComputedTextureSlices>, Option<&ComputedTextureSlices>,
)>, )>,
>, >,
) { ) {
extracted_sprites.sprites.clear(); extracted_sprites.sprites.clear();
for (original_entity, entity, view_visibility, sprite, transform, handle, sheet, slices) in for (original_entity, entity, view_visibility, sprite, transform, slices) in sprite_query.iter()
sprite_query.iter()
{ {
if !view_visibility.get() { if !view_visibility.get() {
continue; continue;
@ -394,12 +391,14 @@ pub fn extract_sprites(
if let Some(slices) = slices { if let Some(slices) = slices {
extracted_sprites.sprites.extend( extracted_sprites.sprites.extend(
slices slices
.extract_sprites(transform, original_entity, sprite, handle) .extract_sprites(transform, original_entity, sprite)
.map(|e| (commands.spawn(TemporaryRenderEntity).id(), e)), .map(|e| (commands.spawn(TemporaryRenderEntity).id(), e)),
); );
} else { } else {
let atlas_rect = let atlas_rect = sprite
sheet.and_then(|s| s.texture_rect(&texture_atlases).map(|r| r.as_rect())); .texture_atlas
.as_ref()
.and_then(|s| s.texture_rect(&texture_atlases).map(|r| r.as_rect()));
let rect = match (atlas_rect, sprite.rect) { let rect = match (atlas_rect, sprite.rect) {
(None, None) => None, (None, None) => None,
(None, Some(sprite_rect)) => Some(sprite_rect), (None, Some(sprite_rect)) => Some(sprite_rect),
@ -423,7 +422,7 @@ pub fn extract_sprites(
custom_size: sprite.custom_size, custom_size: sprite.custom_size,
flip_x: sprite.flip_x, flip_x: sprite.flip_x,
flip_y: sprite.flip_y, flip_y: sprite.flip_y,
image_handle_id: handle.id(), image_handle_id: sprite.image.id(),
anchor: sprite.anchor.as_vec(), anchor: sprite.anchor.as_vec(),
original_entity: Some(original_entity), original_entity: Some(original_entity),
}, },

View file

@ -1,16 +1,22 @@
use bevy_asset::Handle;
use bevy_color::Color; use bevy_color::Color;
use bevy_ecs::{component::Component, reflect::ReflectComponent}; use bevy_ecs::{component::Component, reflect::ReflectComponent};
use bevy_math::{Rect, Vec2}; use bevy_math::{Rect, Vec2};
use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_reflect::{std_traits::ReflectDefault, Reflect};
use bevy_render::{sync_world::SyncToRenderWorld, texture::Image, view::Visibility};
use bevy_transform::components::Transform;
use crate::TextureSlicer; use crate::{TextureAtlas, TextureSlicer};
/// Specifies the rendering properties of a sprite. /// Describes a sprite to be rendered to a 2D camera
///
/// This is commonly used as a component within [`SpriteBundle`](crate::bundle::SpriteBundle).
#[derive(Component, Debug, Default, Clone, Reflect)] #[derive(Component, Debug, Default, Clone, Reflect)]
#[require(Transform, Visibility, SyncToRenderWorld)]
#[reflect(Component, Default, Debug)] #[reflect(Component, Default, Debug)]
pub struct Sprite { pub struct Sprite {
/// The image used to render the sprite
pub image: Handle<Image>,
/// The (optional) texture atlas used to render the sprite
pub texture_atlas: Option<TextureAtlas>,
/// The sprite's color tint /// The sprite's color tint
pub color: Color, pub color: Color,
/// Flip the sprite along the `X` axis /// Flip the sprite along the `X` axis
@ -21,9 +27,9 @@ pub struct Sprite {
/// of the sprite's image /// of the sprite's image
pub custom_size: Option<Vec2>, pub custom_size: Option<Vec2>,
/// An optional rectangle representing the region of the sprite's image to render, instead of rendering /// An optional rectangle representing the region of the sprite's image to render, instead of rendering
/// the full image. This is an easy one-off alternative to using a [`TextureAtlas`](crate::TextureAtlas). /// the full image. This is an easy one-off alternative to using a [`TextureAtlas`].
/// ///
/// When used with a [`TextureAtlas`](crate::TextureAtlas), the rect /// When used with a [`TextureAtlas`], the rect
/// is offset by the atlas's minimal (top-left) corner position. /// is offset by the atlas's minimal (top-left) corner position.
pub rect: Option<Rect>, pub rect: Option<Rect>,
/// [`Anchor`] point of the sprite in the world /// [`Anchor`] point of the sprite in the world
@ -38,6 +44,38 @@ impl Sprite {
..Default::default() ..Default::default()
} }
} }
/// Create a sprite from an image
pub fn from_image(image: Handle<Image>) -> Self {
Self {
image,
..Default::default()
}
}
/// Create a sprite from an image, with an associated texture atlas
pub fn from_atlas_image(image: Handle<Image>, atlas: TextureAtlas) -> Self {
Self {
image,
texture_atlas: Some(atlas),
..Default::default()
}
}
/// Create a sprite from a solid color
pub fn from_color(color: impl Into<Color>, size: Vec2) -> Self {
Self {
color: color.into(),
custom_size: Some(size),
..Default::default()
}
}
}
impl From<Handle<Image>> for Sprite {
fn from(image: Handle<Image>) -> Self {
Self::from_image(image)
}
} }
/// Controls how the image is altered when scaled. /// Controls how the image is altered when scaled.
@ -58,7 +96,7 @@ pub enum ImageScaleMode {
}, },
} }
/// How a sprite is positioned relative to its [`Transform`](bevy_transform::components::Transform). /// How a sprite is positioned relative to its [`Transform`].
/// It defaults to `Anchor::Center`. /// It defaults to `Anchor::Center`.
#[derive(Component, Debug, Clone, Copy, PartialEq, Default, Reflect)] #[derive(Component, Debug, Clone, Copy, PartialEq, Default, Reflect)]
#[reflect(Component, Default, Debug, PartialEq)] #[reflect(Component, Default, Debug, PartialEq)]

View file

@ -190,10 +190,7 @@ impl<'a> TextureAtlasBuilder<'a> {
/// let texture = textures.add(texture); /// let texture = textures.add(texture);
/// let layout = layouts.add(atlas_layout); /// let layout = layouts.add(atlas_layout);
/// // Spawn your sprite /// // Spawn your sprite
/// commands.spawn(( /// commands.spawn(Sprite::from_atlas_image(texture, TextureAtlas::from(layout)));
/// SpriteBundle { texture, ..Default::default() },
/// TextureAtlas::from(layout),
/// ));
/// } /// }
/// ``` /// ```
/// ///

View file

@ -1,7 +1,7 @@
use crate::{ExtractedSprite, ImageScaleMode, Sprite, TextureAtlas, TextureAtlasLayout}; use crate::{ExtractedSprite, ImageScaleMode, Sprite, TextureAtlasLayout};
use super::TextureSlice; use super::TextureSlice;
use bevy_asset::{AssetEvent, Assets, Handle}; use bevy_asset::{AssetEvent, Assets};
use bevy_ecs::prelude::*; use bevy_ecs::prelude::*;
use bevy_math::{Rect, Vec2}; use bevy_math::{Rect, Vec2};
use bevy_render::texture::Image; use bevy_render::texture::Image;
@ -29,7 +29,6 @@ impl ComputedTextureSlices {
transform: &'a GlobalTransform, transform: &'a GlobalTransform,
original_entity: Entity, original_entity: Entity,
sprite: &'a Sprite, sprite: &'a Sprite,
handle: &'a Handle<Image>,
) -> impl ExactSizeIterator<Item = ExtractedSprite> + 'a { ) -> impl ExactSizeIterator<Item = ExtractedSprite> + 'a {
let mut flip = Vec2::ONE; let mut flip = Vec2::ONE;
let [mut flip_x, mut flip_y] = [false; 2]; let [mut flip_x, mut flip_y] = [false; 2];
@ -52,7 +51,7 @@ impl ComputedTextureSlices {
custom_size: Some(slice.draw_size), custom_size: Some(slice.draw_size),
flip_x, flip_x,
flip_y, flip_y,
image_handle_id: handle.id(), image_handle_id: sprite.image.id(),
anchor: Self::redepend_anchor_from_sprite_to_slice(sprite, slice), anchor: Self::redepend_anchor_from_sprite_to_slice(sprite, slice),
} }
}) })
@ -88,12 +87,10 @@ impl ComputedTextureSlices {
fn compute_sprite_slices( fn compute_sprite_slices(
sprite: &Sprite, sprite: &Sprite,
scale_mode: &ImageScaleMode, scale_mode: &ImageScaleMode,
image_handle: &Handle<Image>,
images: &Assets<Image>, images: &Assets<Image>,
atlas: Option<&TextureAtlas>,
atlas_layouts: &Assets<TextureAtlasLayout>, atlas_layouts: &Assets<TextureAtlasLayout>,
) -> Option<ComputedTextureSlices> { ) -> Option<ComputedTextureSlices> {
let (image_size, texture_rect) = match atlas { let (image_size, texture_rect) = match &sprite.texture_atlas {
Some(a) => { Some(a) => {
let layout = atlas_layouts.get(&a.layout)?; let layout = atlas_layouts.get(&a.layout)?;
( (
@ -102,7 +99,7 @@ fn compute_sprite_slices(
) )
} }
None => { None => {
let image = images.get(image_handle)?; let image = images.get(&sprite.image)?;
let size = Vec2::new( let size = Vec2::new(
image.texture_descriptor.size.width as f32, image.texture_descriptor.size.width as f32,
image.texture_descriptor.size.height as f32, image.texture_descriptor.size.height as f32,
@ -139,13 +136,7 @@ pub(crate) fn compute_slices_on_asset_event(
mut events: EventReader<AssetEvent<Image>>, mut events: EventReader<AssetEvent<Image>>,
images: Res<Assets<Image>>, images: Res<Assets<Image>>,
atlas_layouts: Res<Assets<TextureAtlasLayout>>, atlas_layouts: Res<Assets<TextureAtlasLayout>>,
sprites: Query<( sprites: Query<(Entity, &ImageScaleMode, &Sprite)>,
Entity,
&ImageScaleMode,
&Sprite,
&Handle<Image>,
Option<&TextureAtlas>,
)>,
) { ) {
// We store the asset ids of added/modified image assets // We store the asset ids of added/modified image assets
let added_handles: HashSet<_> = events let added_handles: HashSet<_> = events
@ -159,18 +150,11 @@ pub(crate) fn compute_slices_on_asset_event(
return; return;
} }
// We recompute the sprite slices for sprite entities with a matching asset handle id // We recompute the sprite slices for sprite entities with a matching asset handle id
for (entity, scale_mode, sprite, image_handle, atlas) in &sprites { for (entity, scale_mode, sprite) in &sprites {
if !added_handles.contains(&image_handle.id()) { if !added_handles.contains(&sprite.image.id()) {
continue; continue;
} }
if let Some(slices) = compute_sprite_slices( if let Some(slices) = compute_sprite_slices(sprite, scale_mode, &images, &atlas_layouts) {
sprite,
scale_mode,
image_handle,
&images,
atlas,
&atlas_layouts,
) {
commands.entity(entity).insert(slices); commands.entity(entity).insert(slices);
} }
} }
@ -183,30 +167,12 @@ pub(crate) fn compute_slices_on_sprite_change(
images: Res<Assets<Image>>, images: Res<Assets<Image>>,
atlas_layouts: Res<Assets<TextureAtlasLayout>>, atlas_layouts: Res<Assets<TextureAtlasLayout>>,
changed_sprites: Query< changed_sprites: Query<
( (Entity, &ImageScaleMode, &Sprite),
Entity, Or<(Changed<ImageScaleMode>, Changed<Sprite>)>,
&ImageScaleMode,
&Sprite,
&Handle<Image>,
Option<&TextureAtlas>,
),
Or<(
Changed<ImageScaleMode>,
Changed<Handle<Image>>,
Changed<Sprite>,
Changed<TextureAtlas>,
)>,
>, >,
) { ) {
for (entity, scale_mode, sprite, image_handle, atlas) in &changed_sprites { for (entity, scale_mode, sprite) in &changed_sprites {
if let Some(slices) = compute_sprite_slices( if let Some(slices) = compute_sprite_slices(sprite, scale_mode, &images, &atlas_layouts) {
sprite,
scale_mode,
image_handle,
&images,
atlas,
&atlas_layouts,
) {
commands.entity(entity).insert(slices); commands.entity(entity).insert(slices);
} }
} }

View file

@ -33,13 +33,10 @@ fn setup(
)); ));
// Sprite // Sprite
commands.spawn(SpriteBundle { commands.spawn(Sprite {
texture: asset_server.load("branding/bevy_bird_dark.png"), image: asset_server.load("branding/bevy_bird_dark.png"),
sprite: Sprite { color: Color::srgb(5.0, 5.0, 5.0), // 4. Put something bright in a dark environment to see the effect
color: Color::srgb(5.0, 5.0, 5.0), // 4. Put something bright in a dark environment to see the effect custom_size: Some(Vec2::splat(160.0)),
custom_size: Some(Vec2::splat(160.0)),
..default()
},
..default() ..default()
}); });

View file

@ -78,11 +78,7 @@ fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
let handle = images.add(image); let handle = images.add(image);
// create a sprite entity using our image // create a sprite entity using our image
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(handle.clone()));
texture: handle.clone(),
..Default::default()
});
commands.insert_resource(MyProcGenImage(handle)); commands.insert_resource(MyProcGenImage(handle));
} }

View file

@ -19,11 +19,8 @@ enum Direction {
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(asset_server.load("branding/icon.png")),
texture: asset_server.load("branding/icon.png"), Transform::from_xyz(100., 0., 0.),
transform: Transform::from_xyz(100., 0., 0.),
..default()
},
Direction::Up, Direction::Up,
)); ));
} }

View file

@ -52,22 +52,16 @@ struct Rotate;
fn setup_sprite(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup_sprite(mut commands: Commands, asset_server: Res<AssetServer>) {
// the sample sprite that will be rendered to the pixel-perfect canvas // the sample sprite that will be rendered to the pixel-perfect canvas
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(asset_server.load("pixel/bevy_pixel_dark.png")),
texture: asset_server.load("pixel/bevy_pixel_dark.png"), Transform::from_xyz(-40., 20., 2.),
transform: Transform::from_xyz(-40., 20., 2.),
..default()
},
Rotate, Rotate,
PIXEL_PERFECT_LAYERS, PIXEL_PERFECT_LAYERS,
)); ));
// the sample sprite that will be rendered to the high-res "outer world" // the sample sprite that will be rendered to the high-res "outer world"
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(asset_server.load("pixel/bevy_pixel_light.png")),
texture: asset_server.load("pixel/bevy_pixel_light.png"), Transform::from_xyz(-40., -20., 2.),
transform: Transform::from_xyz(-40., -20., 2.),
..default()
},
Rotate, Rotate,
HIGH_RES_LAYERS, HIGH_RES_LAYERS,
)); ));
@ -132,14 +126,7 @@ fn setup_camera(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
)); ));
// spawn the canvas // spawn the canvas
commands.spawn(( commands.spawn((Sprite::from_image(image_handle), Canvas, HIGH_RES_LAYERS));
SpriteBundle {
texture: image_handle,
..default()
},
Canvas,
HIGH_RES_LAYERS,
));
// the "outer" camera renders whatever is on `HIGH_RES_LAYERS` to the screen. // the "outer" camera renders whatever is on `HIGH_RES_LAYERS` to the screen.
// here, the canvas and one of the sample sprites will be rendered by this camera // here, the canvas and one of the sample sprites will be rendered by this camera

View file

@ -62,10 +62,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// player controlled ship // player controlled ship
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(ship_handle),
texture: ship_handle,
..default()
},
Player { Player {
movement_speed: 500.0, // meters per second movement_speed: 500.0, // meters per second
rotation_speed: f32::to_radians(360.0), // degrees per second rotation_speed: f32::to_radians(360.0), // degrees per second
@ -74,39 +71,27 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// enemy that snaps to face the player spawns on the bottom and left // enemy that snaps to face the player spawns on the bottom and left
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(enemy_a_handle.clone()),
texture: enemy_a_handle.clone(), Transform::from_xyz(0.0 - horizontal_margin, 0.0, 0.0),
transform: Transform::from_xyz(0.0 - horizontal_margin, 0.0, 0.0),
..default()
},
SnapToPlayer, SnapToPlayer,
)); ));
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(enemy_a_handle),
texture: enemy_a_handle, Transform::from_xyz(0.0, 0.0 - vertical_margin, 0.0),
transform: Transform::from_xyz(0.0, 0.0 - vertical_margin, 0.0),
..default()
},
SnapToPlayer, SnapToPlayer,
)); ));
// enemy that rotates to face the player enemy spawns on the top and right // enemy that rotates to face the player enemy spawns on the top and right
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(enemy_b_handle.clone()),
texture: enemy_b_handle.clone(), Transform::from_xyz(0.0 + horizontal_margin, 0.0, 0.0),
transform: Transform::from_xyz(0.0 + horizontal_margin, 0.0, 0.0),
..default()
},
RotateToPlayer { RotateToPlayer {
rotation_speed: f32::to_radians(45.0), // degrees per second rotation_speed: f32::to_radians(45.0), // degrees per second
}, },
)); ));
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(enemy_b_handle),
texture: enemy_b_handle, Transform::from_xyz(0.0, 0.0 + vertical_margin, 0.0),
transform: Transform::from_xyz(0.0, 0.0 + vertical_margin, 0.0),
..default()
},
RotateToPlayer { RotateToPlayer {
rotation_speed: f32::to_radians(90.0), // degrees per second rotation_speed: f32::to_radians(90.0), // degrees per second
}, },

View file

@ -11,8 +11,7 @@ fn main() {
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(
texture: asset_server.load("branding/bevy_bird_dark.png"), asset_server.load("branding/bevy_bird_dark.png"),
..default() ));
});
} }

View file

@ -56,24 +56,23 @@ impl AnimationConfig {
// This system loops through all the sprites in the `TextureAtlas`, from `first_sprite_index` to // This system loops through all the sprites in the `TextureAtlas`, from `first_sprite_index` to
// `last_sprite_index` (both defined in `AnimationConfig`). // `last_sprite_index` (both defined in `AnimationConfig`).
fn execute_animations( fn execute_animations(time: Res<Time>, mut query: Query<(&mut AnimationConfig, &mut Sprite)>) {
time: Res<Time>, for (mut config, mut sprite) in &mut query {
mut query: Query<(&mut AnimationConfig, &mut TextureAtlas)>,
) {
for (mut config, mut atlas) in &mut query {
// we track how long the current sprite has been displayed for // we track how long the current sprite has been displayed for
config.frame_timer.tick(time.delta()); config.frame_timer.tick(time.delta());
// If it has been displayed for the user-defined amount of time (fps)... // If it has been displayed for the user-defined amount of time (fps)...
if config.frame_timer.just_finished() { if config.frame_timer.just_finished() {
if atlas.index == config.last_sprite_index { if let Some(atlas) = &mut sprite.texture_atlas {
// ...and it IS the last frame, then we move back to the first frame and stop. if atlas.index == config.last_sprite_index {
atlas.index = config.first_sprite_index; // ...and it IS the last frame, then we move back to the first frame and stop.
} else { atlas.index = config.first_sprite_index;
// ...and it is NOT the last frame, then we move to the next frame... } else {
atlas.index += 1; // ...and it is NOT the last frame, then we move to the next frame...
// ...and reset the frame timer to start counting all over again atlas.index += 1;
config.frame_timer = AnimationConfig::timer_from_fps(config.fps); // ...and reset the frame timer to start counting all over again
config.frame_timer = AnimationConfig::timer_from_fps(config.fps);
}
} }
} }
} }
@ -104,16 +103,15 @@ fn setup(
// create the first (left-hand) sprite // create the first (left-hand) sprite
commands.spawn(( commands.spawn((
SpriteBundle { Sprite {
transform: Transform::from_scale(Vec3::splat(6.0)) image: texture.clone(),
.with_translation(Vec3::new(-50.0, 0.0, 0.0)), texture_atlas: Some(TextureAtlas {
texture: texture.clone(), layout: texture_atlas_layout.clone(),
index: animation_config_1.first_sprite_index,
}),
..default() ..default()
}, },
TextureAtlas { Transform::from_scale(Vec3::splat(6.0)).with_translation(Vec3::new(-50.0, 0.0, 0.0)),
layout: texture_atlas_layout.clone(),
index: animation_config_1.first_sprite_index,
},
LeftSprite, LeftSprite,
animation_config_1, animation_config_1,
)); ));
@ -123,15 +121,13 @@ fn setup(
// create the second (right-hand) sprite // create the second (right-hand) sprite
commands.spawn(( commands.spawn((
SpriteBundle { Sprite {
transform: Transform::from_scale(Vec3::splat(6.0)) image: texture.clone(),
.with_translation(Vec3::new(50.0, 0.0, 0.0)), texture_atlas: Some(TextureAtlas {
texture: texture.clone(), layout: texture_atlas_layout.clone(),
..default() index: animation_config_2.first_sprite_index,
}, }),
TextureAtlas { ..Default::default()
layout: texture_atlas_layout.clone(),
index: animation_config_2.first_sprite_index,
}, },
RightSprite, RightSprite,
animation_config_2, animation_config_2,

View file

@ -11,15 +11,12 @@ fn main() {
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(SpriteBundle { commands.spawn(Sprite {
texture: asset_server.load("branding/bevy_bird_dark.png"), image: asset_server.load("branding/bevy_bird_dark.png"),
sprite: Sprite { // Flip the logo to the left
// Flip the logo to the left flip_x: true,
flip_x: true, // And don't flip it upside-down ( the default )
// And don't flip it upside-down ( the default ) flip_y: false,
flip_y: false, ..Default::default()
..default()
},
..default()
}); });
} }

View file

@ -22,16 +22,19 @@ struct AnimationTimer(Timer);
fn animate_sprite( fn animate_sprite(
time: Res<Time>, time: Res<Time>,
mut query: Query<(&AnimationIndices, &mut AnimationTimer, &mut TextureAtlas)>, mut query: Query<(&AnimationIndices, &mut AnimationTimer, &mut Sprite)>,
) { ) {
for (indices, mut timer, mut atlas) in &mut query { for (indices, mut timer, mut sprite) in &mut query {
timer.tick(time.delta()); timer.tick(time.delta());
if timer.just_finished() { if timer.just_finished() {
atlas.index = if atlas.index == indices.last { if let Some(atlas) = &mut sprite.texture_atlas {
indices.first atlas.index = if atlas.index == indices.last {
} else { indices.first
atlas.index + 1 } else {
}; atlas.index + 1
};
}
} }
} }
} }
@ -48,15 +51,14 @@ fn setup(
let animation_indices = AnimationIndices { first: 1, last: 6 }; let animation_indices = AnimationIndices { first: 1, last: 6 };
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_atlas_image(
transform: Transform::from_scale(Vec3::splat(6.0)),
texture, texture,
..default() TextureAtlas {
}, layout: texture_atlas_layout,
TextureAtlas { index: animation_indices.first,
layout: texture_atlas_layout, },
index: animation_indices.first, ),
}, Transform::from_scale(Vec3::splat(6.0)),
animation_indices, animation_indices,
AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)), AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
)); ));

View file

@ -73,15 +73,14 @@ fn spawn_sprites(
for (label, text_style, size, scale_mode) in cases { for (label, text_style, size, scale_mode) in cases {
position.x += 0.5 * size.x; position.x += 0.5 * size.x;
let mut cmd = commands.spawn(SpriteBundle { let mut cmd = commands.spawn((
transform: Transform::from_translation(position), Sprite {
texture: texture_handle.clone(), image: texture_handle.clone(),
sprite: Sprite {
custom_size: Some(size), custom_size: Some(size),
..default() ..default()
}, },
..default() Transform::from_translation(position),
}); ));
if let Some(scale_mode) = scale_mode { if let Some(scale_mode) = scale_mode {
cmd.insert(scale_mode); cmd.insert(scale_mode);
} }

View file

@ -27,10 +27,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
speed: 50.0, speed: 50.0,
}); });
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(asset_server.load("branding/icon.png")),
texture: asset_server.load("branding/icon.png"),
..default()
},
ImageScaleMode::Tiled { ImageScaleMode::Tiled {
tile_x: true, tile_x: true,
tile_y: true, tile_y: true,

View file

@ -79,15 +79,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let box_size = Vec2::new(300.0, 200.0); let box_size = Vec2::new(300.0, 200.0);
let box_position = Vec2::new(0.0, -250.0); let box_position = Vec2::new(0.0, -250.0);
commands commands
.spawn(SpriteBundle { .spawn((
sprite: Sprite { Sprite::from_color(Color::srgb(0.25, 0.25, 0.75), box_size),
color: Color::srgb(0.25, 0.25, 0.75), Transform::from_translation(box_position.extend(0.0)),
custom_size: Some(Vec2::new(box_size.x, box_size.y)), ))
..default()
},
transform: Transform::from_translation(box_position.extend(0.0)),
..default()
})
.with_children(|builder| { .with_children(|builder| {
builder.spawn(Text2dBundle { builder.spawn(Text2dBundle {
text: Text { text: Text {
@ -110,15 +105,10 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let other_box_size = Vec2::new(300.0, 200.0); let other_box_size = Vec2::new(300.0, 200.0);
let other_box_position = Vec2::new(320.0, -250.0); let other_box_position = Vec2::new(320.0, -250.0);
commands commands
.spawn(SpriteBundle { .spawn((
sprite: Sprite { Sprite::from_color(Color::srgb(0.20, 0.3, 0.70), other_box_size),
color: Color::srgb(0.20, 0.3, 0.70), Transform::from_translation(other_box_position.extend(0.0)),
custom_size: Some(Vec2::new(other_box_size.x, other_box_size.y)), ))
..default()
},
transform: Transform::from_translation(other_box_position.extend(0.0)),
..default()
})
.with_children(|builder| { .with_children(|builder| {
builder.spawn(Text2dBundle { builder.spawn(Text2dBundle {
text: Text { text: Text {

View file

@ -99,26 +99,24 @@ fn setup(
// padded textures are to the right, unpadded to the left // padded textures are to the right, unpadded to the left
// draw unpadded texture atlas // draw unpadded texture atlas
commands.spawn(SpriteBundle { commands.spawn((
texture: linear_texture.clone(), Sprite::from_image(linear_texture.clone()),
transform: Transform { Transform {
translation: Vec3::new(-250.0, -130.0, 0.0), translation: Vec3::new(-250.0, -130.0, 0.0),
scale: Vec3::splat(0.8), scale: Vec3::splat(0.8),
..default() ..default()
}, },
..default() ));
});
// draw padded texture atlas // draw padded texture atlas
commands.spawn(SpriteBundle { commands.spawn((
texture: linear_padded_texture.clone(), Sprite::from_image(linear_padded_texture.clone()),
transform: Transform { Transform {
translation: Vec3::new(250.0, -130.0, 0.0), translation: Vec3::new(250.0, -130.0, 0.0),
scale: Vec3::splat(0.8), scale: Vec3::splat(0.8),
..default() ..default()
}, },
..default() ));
});
let font = asset_server.load("fonts/FiraSans-Bold.ttf"); let font = asset_server.load("fonts/FiraSans-Bold.ttf");
@ -260,16 +258,15 @@ fn create_sprite_from_atlas(
vendor_handle: &Handle<Image>, vendor_handle: &Handle<Image>,
) { ) {
commands.spawn(( commands.spawn((
SpriteBundle { Transform {
transform: Transform { translation: Vec3::new(translation.0, translation.1, translation.2),
translation: Vec3::new(translation.0, translation.1, translation.2), scale: Vec3::splat(3.0),
scale: Vec3::splat(3.0),
..default()
},
texture: atlas_texture,
..default() ..default()
}, },
atlas_sources.handle(atlas_handle, vendor_handle).unwrap(), Sprite::from_atlas_image(
atlas_texture,
atlas_sources.handle(atlas_handle, vendor_handle).unwrap(),
),
)); ));
} }

View file

@ -15,27 +15,22 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
let sprite_handle = asset_server.load("branding/icon.png"); let sprite_handle = asset_server.load("branding/icon.png");
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(sprite_handle.clone()));
texture: sprite_handle.clone(), commands.spawn((
..default() Sprite {
}); image: sprite_handle.clone(),
commands.spawn(SpriteBundle {
sprite: Sprite {
// Alpha channel of the color controls transparency. // Alpha channel of the color controls transparency.
color: Color::srgba(0.0, 0.0, 1.0, 0.7), color: Color::srgba(0.0, 0.0, 1.0, 0.7),
..default() ..default()
}, },
texture: sprite_handle.clone(), Transform::from_xyz(100.0, 0.0, 0.0),
transform: Transform::from_xyz(100.0, 0.0, 0.0), ));
..default() commands.spawn((
}); Sprite {
commands.spawn(SpriteBundle { image: sprite_handle,
sprite: Sprite {
color: Color::srgba(0.0, 1.0, 0.0, 0.3), color: Color::srgba(0.0, 1.0, 0.0, 0.3),
..default() ..default()
}, },
texture: sprite_handle, Transform::from_xyz(200.0, 0.0, 0.0),
transform: Transform::from_xyz(200.0, 0.0, 0.0), ));
..default()
});
} }

View file

@ -70,28 +70,16 @@ fn setup(mut commands: Commands) {
fn spawn_curve_sprite<T: CurveColor>(commands: &mut Commands, y: f32, points: [T; 4]) { fn spawn_curve_sprite<T: CurveColor>(commands: &mut Commands, y: f32, points: [T; 4]) {
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::sized(Vec2::new(75., 75.)),
transform: Transform::from_xyz(0., y, 0.), Transform::from_xyz(0., y, 0.),
sprite: Sprite {
custom_size: Some(Vec2::new(75., 75.)),
..Default::default()
},
..Default::default()
},
Curve(CubicBezier::new([points]).to_curve().unwrap()), Curve(CubicBezier::new([points]).to_curve().unwrap()),
)); ));
} }
fn spawn_mixed_sprite<T: MixedColor>(commands: &mut Commands, y: f32, colors: [T; 4]) { fn spawn_mixed_sprite<T: MixedColor>(commands: &mut Commands, y: f32, colors: [T; 4]) {
commands.spawn(( commands.spawn((
SpriteBundle { Transform::from_xyz(0., y, 0.),
transform: Transform::from_xyz(0., y, 0.), Sprite::sized(Vec2::new(75., 75.)),
sprite: Sprite {
custom_size: Some(Vec2::new(75., 75.)),
..Default::default()
},
..Default::default()
},
Mixed(colors), Mixed(colors),
)); ));
} }

View file

@ -82,24 +82,14 @@ fn setup(mut commands: Commands) {
SelectedEaseFunction(*function, color), SelectedEaseFunction(*function, color),
)) ))
.with_children(|p| { .with_children(|p| {
p.spawn(SpriteBundle { p.spawn((
sprite: Sprite { Sprite::from_color(color, Vec2::splat(5.0)),
custom_size: Some(Vec2::new(5.0, 5.0)), Transform::from_xyz(SIZE_PER_FUNCTION + 5.0, 15.0, 0.0),
color, ));
..default() p.spawn((
}, Sprite::from_color(color, Vec2::splat(4.0)),
transform: Transform::from_xyz(SIZE_PER_FUNCTION + 5.0, 15.0, 0.0), Transform::from_xyz(0.0, 0.0, 0.0),
..default() ));
});
p.spawn(SpriteBundle {
sprite: Sprite {
custom_size: Some(Vec2::new(4.0, 4.0)),
color,
..default()
},
transform: Transform::from_xyz(0.0, 0.0, 0.0),
..default()
});
}); });
} }
} }

View file

@ -75,23 +75,16 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// This marker component ensures we can easily find either of the Birds by using With and // This marker component ensures we can easily find either of the Birds by using With and
// Without query filters. // Without query filters.
Left, Left,
SpriteBundle { Sprite::from_image(texture_left),
texture: texture_left, Transform::from_xyz(-200.0, 0.0, 0.0),
transform: Transform::from_xyz(-200.0, 0.0, 0.0),
..default()
},
bird_left, bird_left,
)); ));
commands.spawn(( commands.spawn((
Name::new("Bird Right"), Name::new("Bird Right"),
SpriteBundle { // In contrast to the above, here we rely on the default `RenderAssetUsages` loader setting
// In contrast to the above, here we rely on the default `RenderAssetUsages` loader Sprite::from_image(asset_server.load(bird_right.get_texture_path())),
// setting. Transform::from_xyz(200.0, 0.0, 0.0),
texture: asset_server.load(bird_right.get_texture_path()),
transform: Transform::from_xyz(200.0, 0.0, 0.0),
..default()
},
bird_right, bird_right,
)); ));
} }

View file

@ -99,25 +99,20 @@ fn main() {
.init_asset::<GzAsset>() .init_asset::<GzAsset>()
.init_asset_loader::<GzAssetLoader>() .init_asset_loader::<GzAssetLoader>()
.add_systems(Startup, setup) .add_systems(Startup, setup)
.add_systems(Update, decompress::<Image>) .add_systems(Update, decompress::<Sprite, Image>)
.run(); .run();
} }
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(( commands.spawn(Compressed::<Image> {
Compressed::<Image> { compressed: asset_server.load("data/compressed_image.png.gz"),
compressed: asset_server.load("data/compressed_image.png.gz"), ..default()
..default() });
},
Sprite::default(),
Transform::default(),
Visibility::default(),
));
} }
fn decompress<A: Asset>( fn decompress<T: Component + From<Handle<A>>, A: Asset>(
mut commands: Commands, mut commands: Commands,
asset_server: Res<AssetServer>, asset_server: Res<AssetServer>,
mut compressed_assets: ResMut<Assets<GzAsset>>, mut compressed_assets: ResMut<Assets<GzAsset>>,
@ -133,6 +128,6 @@ fn decompress<A: Asset>(
commands commands
.entity(entity) .entity(entity)
.remove::<Compressed<A>>() .remove::<Compressed<A>>()
.insert(asset_server.add(uncompressed)); .insert(T::from(asset_server.add(uncompressed)));
} }
} }

View file

@ -23,15 +23,14 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// If you are using a very small image and rendering it larger like seen here, the default linear filtering will result in a blurry image. // If you are using a very small image and rendering it larger like seen here, the default linear filtering will result in a blurry image.
// Useful note: The default sampler specified by the ImagePlugin is *not* the same as the default implementation of sampler. This is why // Useful note: The default sampler specified by the ImagePlugin is *not* the same as the default implementation of sampler. This is why
// everything uses linear by default but if you look at the default of sampler, it uses nearest. // everything uses linear by default but if you look at the default of sampler, it uses nearest.
commands.spawn(SpriteBundle { commands.spawn((
texture: asset_server.load("bevy_pixel_dark.png"), Sprite {
sprite: Sprite { image: asset_server.load("bevy_pixel_dark.png"),
custom_size: Some(Vec2 { x: 160.0, y: 120.0 }), custom_size: Some(Vec2 { x: 160.0, y: 120.0 }),
..Default::default() ..Default::default()
}, },
transform: Transform::from_xyz(-100.0, 0.0, 0.0), Transform::from_xyz(-100.0, 0.0, 0.0),
..Default::default() ));
});
// When a .meta file is added with the same name as the asset and a '.meta' extension // When a .meta file is added with the same name as the asset and a '.meta' extension
// you can (and must) specify all fields of the asset loader's settings for that // you can (and must) specify all fields of the asset loader's settings for that
@ -42,15 +41,14 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// A good reference when filling this out is to check out [ImageLoaderSettings::default()] // A good reference when filling this out is to check out [ImageLoaderSettings::default()]
// and follow to the default implementation of each fields type. // and follow to the default implementation of each fields type.
// https://docs.rs/bevy/latest/bevy/render/texture/struct.ImageLoaderSettings.html# // https://docs.rs/bevy/latest/bevy/render/texture/struct.ImageLoaderSettings.html#
commands.spawn(SpriteBundle { commands.spawn((
texture: asset_server.load("bevy_pixel_dark_with_meta.png"), Sprite {
sprite: Sprite { image: asset_server.load("bevy_pixel_dark_with_meta.png"),
custom_size: Some(Vec2 { x: 160.0, y: 120.0 }), custom_size: Some(Vec2 { x: 160.0, y: 120.0 }),
..Default::default() ..Default::default()
}, },
transform: Transform::from_xyz(100.0, 0.0, 0.0), Transform::from_xyz(100.0, 0.0, 0.0),
..Default::default() ));
});
// Another option is to use the AssetServers load_with_settings function. // Another option is to use the AssetServers load_with_settings function.
// With this you can specify the same settings upon loading your asset with a // With this you can specify the same settings upon loading your asset with a
@ -62,20 +60,19 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// settings changes from any loads after the first of the same asset will be ignored. // settings changes from any loads after the first of the same asset will be ignored.
// This is why this one loads a differently named copy of the asset instead of using // This is why this one loads a differently named copy of the asset instead of using
// same one as without a .meta file. // same one as without a .meta file.
commands.spawn(SpriteBundle { commands.spawn((
texture: asset_server.load_with_settings( Sprite {
"bevy_pixel_dark_with_settings.png", image: asset_server.load_with_settings(
|settings: &mut ImageLoaderSettings| { "bevy_pixel_dark_with_settings.png",
settings.sampler = ImageSampler::nearest(); |settings: &mut ImageLoaderSettings| {
}, settings.sampler = ImageSampler::nearest();
), },
sprite: Sprite { ),
custom_size: Some(Vec2 { x: 160.0, y: 120.0 }), custom_size: Some(Vec2 { x: 160.0, y: 120.0 }),
..Default::default() ..Default::default()
}, },
transform: Transform::from_xyz(0.0, 150.0, 0.0), Transform::from_xyz(0.0, 150.0, 0.0),
..Default::default() ));
});
commands.spawn(Camera2d); commands.spawn(Camera2d);
} }

View file

@ -61,8 +61,5 @@ fn main() {
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
texture: asset_server.load("branding/icon.png"),
..default()
});
} }

View file

@ -48,8 +48,5 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
"embedded://embedded_asset/files/bevy_pixel_light.png".into() "embedded://embedded_asset/files/bevy_pixel_light.png".into()
); );
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(asset_server.load(asset_path)));
texture: asset_server.load(asset_path),
..default()
});
} }

View file

@ -42,8 +42,5 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// path. // path.
assert_eq!(asset_path, "example_files://bevy_pixel_light.png".into()); assert_eq!(asset_path, "example_files://bevy_pixel_light.png".into());
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(asset_server.load(asset_path)));
texture: asset_server.load(asset_path),
..default()
});
} }

View file

@ -46,26 +46,16 @@ fn setup(
.spawn((SpatialBundle::default(), listener.clone())) .spawn((SpatialBundle::default(), listener.clone()))
.with_children(|parent| { .with_children(|parent| {
// left ear // left ear
parent.spawn(SpriteBundle { parent.spawn((
sprite: Sprite { Sprite::from_color(RED, Vec2::splat(20.0)),
color: RED.into(), Transform::from_xyz(-gap / 2.0, 0.0, 0.0),
custom_size: Some(Vec2::splat(20.0)), ));
..default()
},
transform: Transform::from_xyz(-gap / 2.0, 0.0, 0.0),
..default()
});
// right ear // right ear
parent.spawn(SpriteBundle { parent.spawn((
sprite: Sprite { Sprite::from_color(LIME, Vec2::splat(20.0)),
color: LIME.into(), Transform::from_xyz(gap / 2.0, 0.0, 0.0),
custom_size: Some(Vec2::splat(20.0)), ));
..default()
},
transform: Transform::from_xyz(gap / 2.0, 0.0, 0.0),
..default()
});
}); });
// example instructions // example instructions

View file

@ -68,15 +68,12 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
rotation_speed: 2.0, rotation_speed: 2.0,
min_follow_radius: 50.0, min_follow_radius: 50.0,
}, },
SpriteBundle { Sprite {
sprite: Sprite { image: texture,
color: bevy::color::palettes::tailwind::BLUE_800.into(), color: bevy::color::palettes::tailwind::BLUE_800.into(),
..default() ..Default::default()
},
transform: Transform::from_translation(Vec3::ZERO),
texture,
..default()
}, },
Transform::from_translation(Vec3::ZERO),
)); ));
} }
@ -99,15 +96,12 @@ fn user_input(
rotation: rng.gen_range(0.0..std::f32::consts::TAU), rotation: rng.gen_range(0.0..std::f32::consts::TAU),
rotation_speed: rng.gen_range(0.5..1.5), rotation_speed: rng.gen_range(0.5..1.5),
}, },
SpriteBundle { Sprite {
sprite: Sprite { image: texture,
color: bevy::color::palettes::tailwind::RED_800.into(), color: bevy::color::palettes::tailwind::RED_800.into(),
..default()
},
transform: Transform::from_translation(Vec3::ZERO),
texture,
..default() ..default()
}, },
Transform::from_translation(Vec3::ZERO),
)); ));
} }

View file

@ -18,23 +18,21 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// Spawn a root entity with no parent // Spawn a root entity with no parent
let parent = commands let parent = commands
.spawn(SpriteBundle { .spawn((
transform: Transform::from_scale(Vec3::splat(0.75)), Sprite::from_image(texture.clone()),
texture: texture.clone(), Transform::from_scale(Vec3::splat(0.75)),
..default() ))
})
// With that entity as a parent, run a lambda that spawns its children // With that entity as a parent, run a lambda that spawns its children
.with_children(|parent| { .with_children(|parent| {
// parent is a ChildBuilder, which has a similar API to Commands // parent is a ChildBuilder, which has a similar API to Commands
parent.spawn(SpriteBundle { parent.spawn((
transform: Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)), Transform::from_xyz(250.0, 0.0, 0.0).with_scale(Vec3::splat(0.75)),
texture: texture.clone(), Sprite {
sprite: Sprite { image: texture.clone(),
color: BLUE.into(), color: BLUE.into(),
..default() ..default()
}, },
..default() ));
});
}) })
// Store parent entity for next sections // Store parent entity for next sections
.id(); .id();
@ -42,15 +40,14 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// Another way is to use the add_child function to add children after the parent // Another way is to use the add_child function to add children after the parent
// entity has already been spawned. // entity has already been spawned.
let child = commands let child = commands
.spawn(SpriteBundle { .spawn((
transform: Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)), Sprite {
texture, image: texture,
sprite: Sprite {
color: LIME.into(), color: LIME.into(),
..default() ..default()
}, },
..default() Transform::from_xyz(0.0, 250.0, 0.0).with_scale(Vec3::splat(0.75)),
}) ))
.id(); .id();
// Add child to the parent. // Add child to the parent.

View file

@ -16,11 +16,8 @@ fn spawn_system(mut commands: Commands, asset_server: Res<AssetServer>) {
let mut rng = ChaCha8Rng::seed_from_u64(19878367467713); let mut rng = ChaCha8Rng::seed_from_u64(19878367467713);
for _ in 0..128 { for _ in 0..128 {
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(texture.clone()),
texture: texture.clone(), Transform::from_scale(Vec3::splat(0.1)),
transform: Transform::from_scale(Vec3::splat(0.1)),
..default()
},
Velocity(20.0 * Vec2::new(rng.gen::<f32>() - 0.5, rng.gen::<f32>() - 0.5)), Velocity(20.0 * Vec2::new(rng.gen::<f32>() - 0.5, rng.gen::<f32>() - 0.5)),
)); ));
} }

View file

@ -29,10 +29,7 @@ struct MyComponent;
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(asset_server.load("branding/icon.png")),
texture: asset_server.load("branding/icon.png"),
..default()
},
// Add the `Component`. // Add the `Component`.
MyComponent, MyComponent,
)); ));

View file

@ -106,7 +106,8 @@ struct CollisionSound(Handle<AudioSource>);
struct WallBundle { struct WallBundle {
// You can nest bundles inside of other bundles like this // You can nest bundles inside of other bundles like this
// Allowing you to compose their functionality // Allowing you to compose their functionality
sprite_bundle: SpriteBundle, sprite: Sprite,
transform: Transform,
collider: Collider, collider: Collider,
} }
@ -153,21 +154,15 @@ impl WallBundle {
// making our code easier to read and less prone to bugs when we change the logic // making our code easier to read and less prone to bugs when we change the logic
fn new(location: WallLocation) -> WallBundle { fn new(location: WallLocation) -> WallBundle {
WallBundle { WallBundle {
sprite_bundle: SpriteBundle { sprite: Sprite::from_color(WALL_COLOR, Vec2::ONE),
transform: Transform { transform: Transform {
// We need to convert our Vec2 into a Vec3, by giving it a z-coordinate // We need to convert our Vec2 into a Vec3, by giving it a z-coordinate
// This is used to determine the order of our sprites // This is used to determine the order of our sprites
translation: location.position().extend(0.0), translation: location.position().extend(0.0),
// The z-scale of 2D objects must always be 1.0, // The z-scale of 2D objects must always be 1.0,
// or their ordering will be affected in surprising ways. // or their ordering will be affected in surprising ways.
// See https://github.com/bevyengine/bevy/issues/4149 // See https://github.com/bevyengine/bevy/issues/4149
scale: location.size().extend(1.0), scale: location.size().extend(1.0),
..default()
},
sprite: Sprite {
color: WALL_COLOR,
..default()
},
..default() ..default()
}, },
collider: Collider, collider: Collider,
@ -200,16 +195,10 @@ fn setup(
let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR; let paddle_y = BOTTOM_WALL + GAP_BETWEEN_PADDLE_AND_FLOOR;
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_color(PADDLE_COLOR, Vec2::ONE),
transform: Transform { Transform {
translation: Vec3::new(0.0, paddle_y, 0.0), translation: Vec3::new(0.0, paddle_y, 0.0),
scale: PADDLE_SIZE.extend(1.0), scale: PADDLE_SIZE.extend(1.0),
..default()
},
sprite: Sprite {
color: PADDLE_COLOR,
..default()
},
..default() ..default()
}, },
Paddle, Paddle,
@ -294,16 +283,13 @@ fn setup(
// brick // brick
commands.spawn(( commands.spawn((
SpriteBundle { Sprite {
sprite: Sprite { color: BRICK_COLOR,
color: BRICK_COLOR, ..default()
..default() },
}, Transform {
transform: Transform { translation: brick_position.extend(0.0),
translation: brick_position.extend(0.0), scale: Vec3::new(BRICK_SIZE.x, BRICK_SIZE.y, 1.0),
scale: Vec3::new(BRICK_SIZE.x, BRICK_SIZE.y, 1.0),
..default()
},
..default() ..default()
}, },
Brick, Brick,

View file

@ -106,17 +106,14 @@ fn setup_contributor_selection(mut commands: Commands, asset_server: Res<AssetSe
translation: velocity, translation: velocity,
rotation: -dir * 5.0, rotation: -dir * 5.0,
}, },
SpriteBundle { Sprite {
sprite: Sprite { image: texture_handle.clone(),
custom_size: Some(Vec2::splat(SPRITE_SIZE)), custom_size: Some(Vec2::splat(SPRITE_SIZE)),
color: DESELECTED.with_hue(hue).into(), color: DESELECTED.with_hue(hue).into(),
flip_x: flipped, flip_x: flipped,
..default()
},
texture: texture_handle.clone(),
transform,
..default() ..default()
}, },
transform,
)) ))
.id(); .id();

View file

@ -135,10 +135,7 @@ fn setup(
// Spawn the Bevy logo sprite // Spawn the Bevy logo sprite
commands commands
.spawn(( .spawn((
SpriteBundle { Sprite::from_image(asset_server.load("branding/icon.png")),
texture: asset_server.load("branding/icon.png"),
..default()
},
BevyLogo, BevyLogo,
)) ))
.with_children(|commands| { .with_children(|commands| {

View file

@ -133,11 +133,8 @@ fn spawn_player(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(( commands.spawn((
Name::new("Player"), Name::new("Player"),
SpriteBundle { Sprite::from_image(asset_server.load("branding/icon.png")),
texture: asset_server.load("branding/icon.png"), Transform::from_scale(Vec3::splat(0.3)),
transform: Transform::from_scale(Vec3::splat(0.3)),
..default()
},
AccumulatedInput::default(), AccumulatedInput::default(),
Velocity::default(), Velocity::default(),
PhysicalTranslation::default(), PhysicalTranslation::default(),

View file

@ -32,7 +32,7 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
let len = 128.0; let len = 128.0;
let sprite_size = Some(Vec2::splat(len / 2.0)); let sprite_size = Vec2::splat(len / 2.0);
commands commands
.spawn(SpatialBundle::default()) .spawn(SpatialBundle::default())
@ -57,35 +57,29 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
// spawn black square behind sprite to show anchor point // spawn black square behind sprite to show anchor point
commands commands
.spawn(SpriteBundle { .spawn((
sprite: Sprite { Sprite::from_color(Color::BLACK, sprite_size),
custom_size: sprite_size, Transform::from_xyz(i * len - len, j * len - len, -1.0),
color: Color::BLACK, ))
..default()
},
transform: Transform::from_xyz(i * len - len, j * len - len, -1.0),
..default()
})
.observe(recolor_on::<Pointer<Over>>(Color::srgb(0.0, 1.0, 1.0))) .observe(recolor_on::<Pointer<Over>>(Color::srgb(0.0, 1.0, 1.0)))
.observe(recolor_on::<Pointer<Out>>(Color::BLACK)) .observe(recolor_on::<Pointer<Out>>(Color::BLACK))
.observe(recolor_on::<Pointer<Down>>(Color::srgb(1.0, 1.0, 0.0))) .observe(recolor_on::<Pointer<Down>>(Color::srgb(1.0, 1.0, 0.0)))
.observe(recolor_on::<Pointer<Up>>(Color::srgb(0.0, 1.0, 1.0))); .observe(recolor_on::<Pointer<Up>>(Color::srgb(0.0, 1.0, 1.0)));
commands commands
.spawn(SpriteBundle { .spawn((
sprite: Sprite { Sprite {
custom_size: sprite_size, image: asset_server.load("branding/bevy_bird_dark.png"),
custom_size: Some(sprite_size),
color: Color::srgb(1.0, 0.0, 0.0), color: Color::srgb(1.0, 0.0, 0.0),
anchor: anchor.to_owned(), anchor: anchor.to_owned(),
..default() ..default()
}, },
texture: asset_server.load("branding/bevy_bird_dark.png"),
// 3x3 grid of anchor examples by changing transform // 3x3 grid of anchor examples by changing transform
transform: Transform::from_xyz(i * len - len, j * len - len, 0.0) Transform::from_xyz(i * len - len, j * len - len, 0.0)
.with_scale(Vec3::splat(1.0 + (i - 1.0) * 0.2)) .with_scale(Vec3::splat(1.0 + (i - 1.0) * 0.2))
.with_rotation(Quat::from_rotation_z((j - 1.0) * 0.2)), .with_rotation(Quat::from_rotation_z((j - 1.0) * 0.2)),
..default() ))
})
.observe(recolor_on::<Pointer<Over>>(Color::srgb(0.0, 1.0, 0.0))) .observe(recolor_on::<Pointer<Over>>(Color::srgb(0.0, 1.0, 0.0)))
.observe(recolor_on::<Pointer<Out>>(Color::srgb(1.0, 0.0, 0.0))) .observe(recolor_on::<Pointer<Out>>(Color::srgb(1.0, 0.0, 0.0)))
.observe(recolor_on::<Pointer<Down>>(Color::srgb(0.0, 0.0, 1.0))) .observe(recolor_on::<Pointer<Down>>(Color::srgb(0.0, 0.0, 1.0)))
@ -131,15 +125,14 @@ fn setup_atlas(
let animation_indices = AnimationIndices { first: 1, last: 6 }; let animation_indices = AnimationIndices { first: 1, last: 6 };
commands commands
.spawn(( .spawn((
TextureAtlas { Sprite::from_atlas_image(
layout: texture_atlas_layout_handle, texture_handle,
index: animation_indices.first, TextureAtlas {
}, layout: texture_atlas_layout_handle,
SpriteBundle { index: animation_indices.first,
texture: texture_handle, },
transform: Transform::from_xyz(300.0, 0.0, 0.0).with_scale(Vec3::splat(6.0)), ),
..default() Transform::from_xyz(300.0, 0.0, 0.0).with_scale(Vec3::splat(6.0)),
},
animation_indices, animation_indices,
AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)), AnimationTimer(Timer::from_seconds(0.1, TimerMode::Repeating)),
)) ))

View file

@ -67,15 +67,14 @@ fn setup(mut commands: Commands, mut images: ResMut<Assets<Image>>) {
let image0 = images.add(image.clone()); let image0 = images.add(image.clone());
let image1 = images.add(image); let image1 = images.add(image);
commands.spawn(SpriteBundle { commands.spawn((
sprite: Sprite { Sprite {
image: image0.clone(),
custom_size: Some(Vec2::new(SIZE.0 as f32, SIZE.1 as f32)), custom_size: Some(Vec2::new(SIZE.0 as f32, SIZE.1 as f32)),
..default() ..default()
}, },
texture: image0.clone(), Transform::from_scale(Vec3::splat(DISPLAY_FACTOR as f32)),
transform: Transform::from_scale(Vec3::splat(DISPLAY_FACTOR as f32)), ));
..default()
});
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.insert_resource(GameOfLifeImages { commands.insert_resource(GameOfLifeImages {

View file

@ -423,10 +423,7 @@ mod ui {
pub fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) { pub fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(( commands.spawn((
StateScoped(InGame), StateScoped(InGame),
SpriteBundle { Sprite::from_image(asset_server.load("branding/icon.png")),
texture: asset_server.load("branding/icon.png"),
..default()
},
)); ));
} }

View file

@ -223,10 +223,7 @@ fn setup(mut commands: Commands) {
} }
fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
texture: asset_server.load("branding/icon.png"),
..default()
});
info!("Setup game"); info!("Setup game");
} }

View file

@ -120,10 +120,7 @@ fn cleanup_menu(mut commands: Commands, menu_data: Res<MenuData>) {
} }
fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
texture: asset_server.load("branding/icon.png"),
..default()
});
} }
const SPEED: f32 = 100.0; const SPEED: f32 = 100.0;

View file

@ -198,10 +198,7 @@ mod ui {
} }
pub fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) { pub fn setup_game(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
texture: asset_server.load("branding/icon.png"),
..default()
});
} }
pub fn setup_paused_screen(mut commands: Commands) { pub fn setup_paused_screen(mut commands: Commands) {

View file

@ -433,16 +433,16 @@ fn spawn_birds(
color color
}; };
( (
SpriteBundle { Sprite {
texture: bird_resources image: bird_resources
.textures .textures
.choose(&mut bird_resources.material_rng) .choose(&mut bird_resources.material_rng)
.unwrap() .unwrap()
.clone(), .clone(),
transform, color,
sprite: Sprite { color, ..default() },
..default() ..default()
}, },
transform,
Bird { velocity }, Bird { velocity },
) )
}) })

View file

@ -82,19 +82,16 @@ fn setup(
timer.set_elapsed(Duration::from_secs_f32(rng.gen::<f32>())); timer.set_elapsed(Duration::from_secs_f32(rng.gen::<f32>()));
commands.spawn(( commands.spawn((
SpriteBundle { Sprite {
texture: texture_handle.clone(), image: texture_handle.clone(),
transform: Transform { custom_size: Some(tile_size),
translation,
rotation,
scale,
},
sprite: Sprite {
custom_size: Some(tile_size),
..default()
},
..default() ..default()
}, },
Transform {
translation,
rotation,
scale,
},
TextureAtlas::from(texture_atlas_handle.clone()), TextureAtlas::from(texture_atlas_handle.clone()),
AnimationTimer(timer), AnimationTimer(timer),
)); ));

View file

@ -81,14 +81,9 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>, color_tint: Res<Color
let rotation = Quat::from_rotation_z(rng.gen::<f32>()); let rotation = Quat::from_rotation_z(rng.gen::<f32>());
let scale = Vec3::splat(rng.gen::<f32>() * 2.0); let scale = Vec3::splat(rng.gen::<f32>() * 2.0);
sprites.push(SpriteBundle { sprites.push((
texture: sprite_handle.clone(), Sprite {
transform: Transform { image: sprite_handle.clone(),
translation,
rotation,
scale,
},
sprite: Sprite {
custom_size: Some(tile_size), custom_size: Some(tile_size),
color: if color_tint.0 { color: if color_tint.0 {
COLORS[rng.gen_range(0..3)] COLORS[rng.gen_range(0..3)]
@ -97,8 +92,12 @@ fn setup(mut commands: Commands, assets: Res<AssetServer>, color_tint: Res<Color
}, },
..default() ..default()
}, },
..default() Transform {
}); translation,
rotation,
scale,
},
));
} }
} }
commands.spawn_batch(sprites); commands.spawn_batch(sprites);

View file

@ -53,27 +53,21 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut time: ResMu
// the sprite moving based on real time // the sprite moving based on real time
commands.spawn(( commands.spawn((
SpriteBundle { Sprite::from_image(texture_handle.clone()),
texture: texture_handle.clone(), Transform::from_scale(sprite_scale),
transform: Transform::from_scale(sprite_scale),
..default()
},
RealTime, RealTime,
)); ));
// the sprite moving based on virtual time // the sprite moving based on virtual time
commands.spawn(( commands.spawn((
SpriteBundle { Sprite {
texture: texture_handle, image: texture_handle,
sprite: Sprite { color: virtual_color,
color: virtual_color, ..Default::default()
..default() },
}, Transform {
transform: Transform { scale: sprite_scale,
scale: sprite_scale, translation: Vec3::new(0., -160., 0.),
translation: Vec3::new(0., -160., 0.),
..default()
},
..default() ..default()
}, },
VirtualTime, VirtualTime,

View file

@ -282,34 +282,20 @@ fn setup_sticks(
}) })
.with_children(|parent| { .with_children(|parent| {
// full extent // full extent
parent.spawn(SpriteBundle { parent.spawn(Sprite::from_color(
sprite: Sprite { DEAD_COLOR,
custom_size: Some(Vec2::splat(STICK_BOUNDS_SIZE * 2.)), Vec2::splat(STICK_BOUNDS_SIZE * 2.),
color: DEAD_COLOR, ));
..default()
},
..default()
});
// live zone // live zone
parent.spawn(SpriteBundle { parent.spawn((
transform: Transform::from_xyz(live_mid, live_mid, 2.), Sprite::from_color(LIVE_COLOR, Vec2::splat(live_size)),
sprite: Sprite { Transform::from_xyz(live_mid, live_mid, 2.),
custom_size: Some(Vec2::new(live_size, live_size)), ));
color: LIVE_COLOR,
..default()
},
..default()
});
// dead zone // dead zone
parent.spawn(SpriteBundle { parent.spawn((
transform: Transform::from_xyz(dead_mid, dead_mid, 3.), Sprite::from_color(DEAD_COLOR, Vec2::splat(dead_size)),
sprite: Sprite { Transform::from_xyz(dead_mid, dead_mid, 3.),
custom_size: Some(Vec2::new(dead_size, dead_size)), ));
color: DEAD_COLOR,
..default()
},
..default()
});
// text // text
let style = TextStyle { let style = TextStyle {
font_size: 13., font_size: 13.,

View file

@ -32,8 +32,5 @@ fn main() {
fn setup(mut commands: Commands, asset_server: Res<AssetServer>) { fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn(Camera2d); commands.spawn(Camera2d);
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_image(asset_server.load("branding/icon.png")));
texture: asset_server.load("branding/icon.png"),
..default()
});
} }

View file

@ -71,12 +71,8 @@ fn setup_2d(mut commands: Commands) {
..default() ..default()
}, },
)); ));
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_color(
sprite: Sprite { Color::srgb(0.25, 0.25, 0.75),
color: Color::srgb(0.25, 0.25, 0.75), Vec2::new(50.0, 50.0),
custom_size: Some(Vec2::new(50.0, 50.0)), ));
..default()
},
..default()
});
} }

View file

@ -147,12 +147,8 @@ fn setup_2d(mut commands: Commands) {
..default() ..default()
}, },
)); ));
commands.spawn(SpriteBundle { commands.spawn(Sprite::from_color(
sprite: Sprite { Color::srgb(0.25, 0.25, 0.75),
color: Color::srgb(0.25, 0.25, 0.75), Vec2::new(50.0, 50.0),
custom_size: Some(Vec2::new(50.0, 50.0)), ));
..default()
},
..default()
});
} }