Add more to the 2d testbed for text (#18240)

# Objective

`Text2d` testing hasn't been as thorough as text in the UI, and it
suffered a bunch of bugs / perf issues in recent cycles.

## Solution

Add some more `Text2d` scenarios to the 2d testbed to catch bugs,
testing bounded and unbounded text with various justification.

## Testing

`cargo run --example testbed_2d` (press space a few times)

<img width="1280" alt="Screenshot 2025-03-10 at 1 02 03 PM"
src="https://github.com/user-attachments/assets/1e4ee39c-809b-4cc6-81bd-68e67b9625b5"
/>

---------

Co-authored-by: Ben Frankel <ben.frankel7@gmail.com>
This commit is contained in:
Rob Parrett 2025-03-10 15:04:14 -07:00 committed by GitHub
parent 906d788420
commit 4a41525cd0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -143,22 +143,115 @@ mod bloom {
}
mod text {
use bevy::color::palettes;
use bevy::prelude::*;
use bevy::sprite::Anchor;
use bevy::text::TextBounds;
pub fn setup(mut commands: Commands) {
let text_font = TextFont {
font_size: 50.0,
..default()
};
let text_justification = JustifyText::Center;
pub fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
commands.spawn((Camera2d, StateScoped(super::Scene::Text)));
for (i, justify) in [
JustifyText::Left,
JustifyText::Right,
JustifyText::Center,
JustifyText::Justified,
]
.into_iter()
.enumerate()
{
let y = 230. - 150. * i as f32;
spawn_anchored_text(&mut commands, -300. * Vec3::X + y * Vec3::Y, justify, None);
spawn_anchored_text(
&mut commands,
300. * Vec3::X + y * Vec3::Y,
justify,
Some(TextBounds::new(150., 55.)),
);
}
let sans_serif = TextFont::from_font(asset_server.load("fonts/FiraSans-Bold.ttf"));
const NUM_ITERATIONS: usize = 10;
for i in 0..NUM_ITERATIONS {
let fraction = i as f32 / (NUM_ITERATIONS - 1) as f32;
commands.spawn((
Text2d::new("Bevy"),
sans_serif.clone(),
Transform::from_xyz(0.0, fraction * 200.0, i as f32)
.with_scale(1.0 + Vec2::splat(fraction).extend(1.))
.with_rotation(Quat::from_rotation_z(fraction * core::f32::consts::PI)),
TextColor(Color::hsla(fraction * 360.0, 0.8, 0.8, 0.8)),
StateScoped(super::Scene::Text),
));
}
commands.spawn((
Text2d::new("Hello World"),
text_font,
TextLayout::new_with_justify(text_justification),
Text2d::new("This text is invisible."),
Visibility::Hidden,
StateScoped(super::Scene::Text),
));
}
fn spawn_anchored_text(
commands: &mut Commands,
dest: Vec3,
justify: JustifyText,
bounds: Option<TextBounds>,
) {
commands.spawn((
Sprite {
color: palettes::css::YELLOW.into(),
custom_size: Some(5. * Vec2::ONE),
..Default::default()
},
Transform::from_translation(dest),
StateScoped(super::Scene::Text),
));
for anchor in [
Anchor::TopLeft,
Anchor::TopRight,
Anchor::BottomRight,
Anchor::BottomLeft,
] {
let mut text = commands.spawn((
Text2d::new("L R\n"),
TextLayout::new_with_justify(justify),
Transform::from_translation(dest + Vec3::Z),
anchor,
StateScoped(super::Scene::Text),
));
text.with_children(|parent| {
parent.spawn((
TextSpan::new(format!("{anchor:?}\n")),
TextFont::from_font_size(14.0),
TextColor(palettes::tailwind::BLUE_400.into()),
));
parent.spawn((
TextSpan::new(format!("{justify:?}")),
TextFont::from_font_size(14.0),
TextColor(palettes::tailwind::GREEN_400.into()),
));
});
if let Some(bounds) = bounds {
text.insert(bounds);
commands.spawn((
Sprite {
color: palettes::tailwind::GRAY_900.into(),
custom_size: Some(Vec2::new(bounds.width.unwrap(), bounds.height.unwrap())),
anchor,
..Default::default()
},
Transform::from_translation(dest - Vec3::Z),
StateScoped(super::Scene::Text),
));
}
}
}
}
mod sprite {