bevy/examples/ui/ui_texture_atlas.rs
mwbryant 8b5bf42c28
UI texture atlas support (#8822)
# Objective

This adds support for using texture atlas sprites in UI. From
discussions today in the ui-dev discord it seems this is a much wanted
feature.

This was previously attempted in #5070 by @ManevilleF however that was
blocked #5103. This work can be easily modified to support #5103 changes
after that merges.

## Solution

I created a new UI bundle that reuses the existing texture atlas
infrastructure. I create a new atlas image component to prevent it from
being drawn by the existing non-UI systems and to remove unused
parameters.

In extract I added new system to calculate the required values for the
texture atlas image, this extracts into the same resource as the
existing UI Image and Text components.

This should have minimal performance impact because if texture atlas is
not present then the exact same code path is followed. Also there should
be no unintended behavior changes because without the new components the
existing systems write the extract same resulting data.

I also added an example showing the sprite working and a system to
advance the animation on space bar presses.

Naming is hard and I would accept any feedback on the bundle name! 

---

## Changelog

>  Added TextureAtlasImageBundle

---------

Co-authored-by: ickshonpe <david.curthoys@googlemail.com>
2023-06-19 21:52:02 +00:00

86 lines
2.8 KiB
Rust

//! This example illustrates how to use `TextureAtlases` within ui
use bevy::{prelude::*, winit::WinitSettings};
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(
// This sets image filtering to nearest
// This is done to prevent textures with low resolution (e.g. pixel art) from being blurred
// by linear filtering.
ImagePlugin::default_nearest(),
))
// Only run the app when there is user input. This will significantly reduce CPU/GPU use.
.insert_resource(WinitSettings::desktop_app())
.add_systems(Startup, setup)
.add_systems(Update, increment_atlas_index)
.run();
}
fn setup(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut texture_atlases: ResMut<Assets<TextureAtlas>>,
) {
// Camera
commands.spawn(Camera2dBundle::default());
let text_style = TextStyle {
color: Color::ANTIQUE_WHITE,
font_size: 20.,
..default()
};
let texture_handle = asset_server.load("textures/rpg/chars/gabe/gabe-idle-run.png");
let texture_atlas =
TextureAtlas::from_grid(texture_handle, Vec2::new(24.0, 24.0), 7, 1, None, None);
let texture_atlas_handle = texture_atlases.add(texture_atlas);
// root node
commands
.spawn(NodeBundle {
style: Style {
flex_direction: FlexDirection::Column,
width: Val::Percent(100.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
row_gap: Val::Px(text_style.font_size * 2.),
..default()
},
..default()
})
.with_children(|parent| {
parent.spawn((AtlasImageBundle {
style: Style {
width: Val::Px(256.),
height: Val::Px(256.),
..default()
},
texture_atlas: texture_atlas_handle,
texture_atlas_image: UiTextureAtlasImage::default(),
..default()
},));
parent.spawn(TextBundle::from_sections([
TextSection::new("press ".to_string(), text_style.clone()),
TextSection::new(
"space".to_string(),
TextStyle {
color: Color::YELLOW,
..text_style.clone()
},
),
TextSection::new(" to advance frames".to_string(), text_style),
]));
});
}
fn increment_atlas_index(
mut atlas_images: Query<&mut UiTextureAtlasImage>,
keyboard: Res<Input<KeyCode>>,
) {
if keyboard.just_pressed(KeyCode::Space) {
for mut atlas_image in &mut atlas_images {
atlas_image.index = (atlas_image.index + 1) % 6;
}
}
}