//! Shows text rendering with moving, rotating and scaling text. //! //! Note that this uses [`Text2dBundle`] to display text alongside your other entities in a 2D scene. //! //! For an example on how to render text as part of a user interface, independent from the world //! viewport, you may want to look at `games/contributors.rs` or `ui/text.rs`. use bevy::{ prelude::*, sprite::Anchor, text::{BreakLineOn, Text2dBounds}, }; fn main() { App::new() .add_plugins(DefaultPlugins) .add_systems(Startup, setup) .add_systems( Update, (animate_translation, animate_rotation, animate_scale), ) .run(); } #[derive(Component)] struct AnimateTranslation; #[derive(Component)] struct AnimateRotation; #[derive(Component)] struct AnimateScale; fn setup(mut commands: Commands, asset_server: Res) { let font = asset_server.load("fonts/FiraSans-Bold.ttf"); let text_style = TextStyle { font: font.clone(), font_size: 60.0, color: Color::WHITE, }; let text_justification = JustifyText::Center; // 2d camera commands.spawn(Camera2dBundle::default()); // Demonstrate changing translation commands.spawn(( Text2dBundle { text: Text::from_section("translation", text_style.clone()) .with_justify(text_justification), ..default() }, AnimateTranslation, )); // Demonstrate changing rotation commands.spawn(( Text2dBundle { text: Text::from_section("rotation", text_style.clone()) .with_justify(text_justification), ..default() }, AnimateRotation, )); // Demonstrate changing scale commands.spawn(( Text2dBundle { text: Text::from_section("scale", text_style).with_justify(text_justification), ..default() }, AnimateScale, )); // Demonstrate text wrapping let slightly_smaller_text_style = TextStyle { font, font_size: 42.0, color: Color::WHITE, }; let box_size = Vec2::new(300.0, 200.0); let box_position = Vec2::new(0.0, -250.0); commands .spawn(SpriteBundle { sprite: Sprite { color: Color::rgb(0.25, 0.25, 0.75), 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| { builder.spawn(Text2dBundle { text: Text { sections: vec![TextSection::new( "this text wraps in the box\n(Unicode linebreaks)", slightly_smaller_text_style.clone(), )], justify: JustifyText::Left, linebreak_behavior: BreakLineOn::WordBoundary, }, text_2d_bounds: Text2dBounds { // Wrap text in the rectangle size: box_size, }, // ensure the text is drawn on top of the box transform: Transform::from_translation(Vec3::Z), ..default() }); }); let other_box_size = Vec2::new(300.0, 200.0); let other_box_position = Vec2::new(320.0, -250.0); commands .spawn(SpriteBundle { sprite: Sprite { color: Color::rgb(0.20, 0.3, 0.70), 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| { builder.spawn(Text2dBundle { text: Text { sections: vec![TextSection::new( "this text wraps in the box\n(AnyCharacter linebreaks)", slightly_smaller_text_style.clone(), )], justify: JustifyText::Left, linebreak_behavior: BreakLineOn::AnyCharacter, }, text_2d_bounds: Text2dBounds { // Wrap text in the rectangle size: other_box_size, }, // ensure the text is drawn on top of the box transform: Transform::from_translation(Vec3::Z), ..default() }); }); for (text_anchor, color) in [ (Anchor::TopLeft, Color::RED), (Anchor::TopRight, Color::GREEN), (Anchor::BottomRight, Color::BLUE), (Anchor::BottomLeft, Color::YELLOW), ] { commands.spawn(Text2dBundle { text: Text { sections: vec![TextSection::new( format!(" Anchor::{text_anchor:?} "), TextStyle { color, ..slightly_smaller_text_style.clone() }, )], ..Default::default() }, transform: Transform::from_translation(250. * Vec3::Y), text_anchor, ..default() }); } } fn animate_translation( time: Res