mirror of
https://github.com/bevyengine/bevy
synced 2024-11-26 14:40:19 +00:00
135c7240f1
# Objective > Old MR: #5072 > ~~Associated UI MR: #5070~~ > Adresses #1618 Unify sprite management ## Solution - Remove the `Handle<Image>` field in `TextureAtlas` which is the main cause for all the boilerplate - Remove the redundant `TextureAtlasSprite` component - Renamed `TextureAtlas` asset to `TextureAtlasLayout` ([suggestion](https://github.com/bevyengine/bevy/pull/5103#discussion_r917281844)) - Add a `TextureAtlas` component, containing the atlas layout handle and the section index The difference between this solution and #5072 is that instead of the `enum` approach is that we can more easily manipulate texture sheets without any breaking changes for classic `SpriteBundle`s (@mockersf [comment](https://github.com/bevyengine/bevy/pull/5072#issuecomment-1165836139)) Also, this approach is more *data oriented* extracting the `Handle<Image>` and avoiding complex texture atlas manipulations to retrieve the texture in both applicative and engine code. With this method, the only difference between a `SpriteBundle` and a `SpriteSheetBundle` is an **additional** component storing the atlas handle and the index. ~~This solution can be applied to `bevy_ui` as well (see #5070).~~ EDIT: I also applied this solution to Bevy UI ## Changelog - (**BREAKING**) Removed `TextureAtlasSprite` - (**BREAKING**) Renamed `TextureAtlas` to `TextureAtlasLayout` - (**BREAKING**) `SpriteSheetBundle`: - Uses a `Sprite` instead of a `TextureAtlasSprite` component - Has a `texture` field containing a `Handle<Image>` like the `SpriteBundle` - Has a new `TextureAtlas` component instead of a `Handle<TextureAtlasLayout>` - (**BREAKING**) `DynamicTextureAtlasBuilder::add_texture` takes an additional `&Handle<Image>` parameter - (**BREAKING**) `TextureAtlasLayout::from_grid` no longer takes a `Handle<Image>` parameter - (**BREAKING**) `TextureAtlasBuilder::finish` now returns a `Result<(TextureAtlasLayout, Handle<Image>), _>` - `bevy_text`: - `GlyphAtlasInfo` stores the texture `Handle<Image>` - `FontAtlas` stores the texture `Handle<Image>` - `bevy_ui`: - (**BREAKING**) Removed `UiAtlasImage` , the atlas bundle is now identical to the `ImageBundle` with an additional `TextureAtlas` ## Migration Guide * Sprites ```diff fn my_system( mut images: ResMut<Assets<Image>>, - mut atlases: ResMut<Assets<TextureAtlas>>, + mut atlases: ResMut<Assets<TextureAtlasLayout>>, asset_server: Res<AssetServer> ) { let texture_handle: asset_server.load("my_texture.png"); - let layout = TextureAtlas::from_grid(texture_handle, Vec2::new(25.0, 25.0), 5, 5, None, None); + let layout = TextureAtlasLayout::from_grid(Vec2::new(25.0, 25.0), 5, 5, None, None); let layout_handle = atlases.add(layout); commands.spawn(SpriteSheetBundle { - sprite: TextureAtlasSprite::new(0), - texture_atlas: atlas_handle, + atlas: TextureAtlas { + layout: layout_handle, + index: 0 + }, + texture: texture_handle, ..Default::default() }); } ``` * UI ```diff fn my_system( mut images: ResMut<Assets<Image>>, - mut atlases: ResMut<Assets<TextureAtlas>>, + mut atlases: ResMut<Assets<TextureAtlasLayout>>, asset_server: Res<AssetServer> ) { let texture_handle: asset_server.load("my_texture.png"); - let layout = TextureAtlas::from_grid(texture_handle, Vec2::new(25.0, 25.0), 5, 5, None, None); + let layout = TextureAtlasLayout::from_grid(Vec2::new(25.0, 25.0), 5, 5, None, None); let layout_handle = atlases.add(layout); commands.spawn(AtlasImageBundle { - texture_atlas_image: UiTextureAtlasImage { - index: 0, - flip_x: false, - flip_y: false, - }, - texture_atlas: atlas_handle, + atlas: TextureAtlas { + layout: layout_handle, + index: 0 + }, + image: UiImage { + texture: texture_handle, + flip_x: false, + flip_y: false, + }, ..Default::default() }); } ``` --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: François <mockersf@gmail.com> Co-authored-by: IceSentry <IceSentry@users.noreply.github.com>
98 lines
2.9 KiB
Rust
98 lines
2.9 KiB
Rust
//! This example illustrates how `FontAtlas`'s are populated.
|
|
//! Bevy uses `FontAtlas`'s under the hood to optimize text rendering.
|
|
|
|
use bevy::{prelude::*, text::FontAtlasSets};
|
|
|
|
fn main() {
|
|
App::new()
|
|
.init_resource::<State>()
|
|
.insert_resource(ClearColor(Color::BLACK))
|
|
.add_plugins(DefaultPlugins)
|
|
.add_systems(Startup, setup)
|
|
.add_systems(Update, (text_update_system, atlas_render_system))
|
|
.run();
|
|
}
|
|
|
|
#[derive(Resource)]
|
|
struct State {
|
|
atlas_count: u32,
|
|
handle: Handle<Font>,
|
|
timer: Timer,
|
|
}
|
|
|
|
impl Default for State {
|
|
fn default() -> Self {
|
|
Self {
|
|
atlas_count: 0,
|
|
handle: Handle::default(),
|
|
timer: Timer::from_seconds(0.05, TimerMode::Repeating),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn atlas_render_system(
|
|
mut commands: Commands,
|
|
mut state: ResMut<State>,
|
|
font_atlas_sets: Res<FontAtlasSets>,
|
|
) {
|
|
if let Some(set) = font_atlas_sets.get(&state.handle) {
|
|
if let Some((_size, font_atlas)) = set.iter().next() {
|
|
let x_offset = state.atlas_count as f32;
|
|
if state.atlas_count == font_atlas.len() as u32 {
|
|
return;
|
|
}
|
|
let font_atlas = &font_atlas[state.atlas_count as usize];
|
|
state.atlas_count += 1;
|
|
commands.spawn(ImageBundle {
|
|
image: font_atlas.texture.clone().into(),
|
|
style: Style {
|
|
position_type: PositionType::Absolute,
|
|
top: Val::ZERO,
|
|
left: Val::Px(512.0 * x_offset),
|
|
..default()
|
|
},
|
|
..default()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
fn text_update_system(mut state: ResMut<State>, time: Res<Time>, mut query: Query<&mut Text>) {
|
|
if state.timer.tick(time.delta()).finished() {
|
|
for mut text in &mut query {
|
|
let c = rand::random::<u8>() as char;
|
|
let string = &mut text.sections[0].value;
|
|
if !string.contains(c) {
|
|
string.push(c);
|
|
}
|
|
}
|
|
|
|
state.timer.reset();
|
|
}
|
|
}
|
|
|
|
fn setup(mut commands: Commands, asset_server: Res<AssetServer>, mut state: ResMut<State>) {
|
|
let font_handle = asset_server.load("fonts/FiraSans-Bold.ttf");
|
|
state.handle = font_handle.clone();
|
|
commands.spawn(Camera2dBundle::default());
|
|
commands
|
|
.spawn(NodeBundle {
|
|
background_color: Color::NONE.into(),
|
|
style: Style {
|
|
position_type: PositionType::Absolute,
|
|
bottom: Val::ZERO,
|
|
..default()
|
|
},
|
|
..default()
|
|
})
|
|
.with_children(|parent| {
|
|
parent.spawn(TextBundle::from_section(
|
|
"a",
|
|
TextStyle {
|
|
font: font_handle,
|
|
font_size: 60.0,
|
|
color: Color::YELLOW,
|
|
},
|
|
));
|
|
});
|
|
}
|