use bevy::prelude::*;
use bevy_bitmap_text::*;
const DEMO_TEXT: &str = "Hello 你好世界!\nbevy_bitmap_text 位图文字渲染";
const FONT_NAME: &str = "SourceHanSansCN-Light";
const DEFAULT_SIZE: u32 = 32;
const SIZE_PRESETS: &[u32] = &[16, 24, 32, 48, 64, 96];
fn main() {
App::new()
.add_plugins(DefaultPlugins.set(WindowPlugin {
primary_window: Some(Window {
title: "bevy_bitmap_text demo".into(),
resolution: (960, 640).into(),
..default()
}),
..default()
}))
.add_plugins(BitmapTextPlugin::default())
.add_systems(Startup, setup)
.add_systems(Update, size_button_system)
.run();
}
#[derive(Component)]
struct DemoText;
#[derive(Component)]
struct SizeButton(u32);
fn setup(mut commands: Commands, mut cache: ResMut<DynamicGlyphCache>) {
commands.spawn(Camera2d);
let font_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("examples/assets/SourceHanSansCN-Light.otf");
let font_data = std::fs::read(&font_path).expect("Failed to read font file");
cache
.add_font(FontId::from_name(FONT_NAME), &font_data)
.expect("Failed to load font");
info!("Loaded font: {FONT_NAME}");
commands.spawn((
DemoText,
TextBlock::from_segments(parse_text_to_segments(DEMO_TEXT).segments),
TextBlockStyling {
font: FontId::from_name(FONT_NAME),
size_px: DEFAULT_SIZE,
world_scale: DEFAULT_SIZE as f32,
color: bevy::color::Srgba::WHITE,
align: TextAlign::Left,
anchor: TextAnchor::CENTER,
line_height: 1.4,
..default()
},
Transform::from_xyz(0.0, 80.0, 0.0),
));
commands
.spawn(Node {
width: Val::Percent(100.0),
height: Val::Percent(100.0),
flex_direction: FlexDirection::Column,
justify_content: JustifyContent::End,
align_items: AlignItems::Center,
padding: UiRect::all(Val::Px(20.0)),
row_gap: Val::Px(10.0),
..default()
})
.with_children(|parent| {
parent.spawn((
Text::new("Font: Source Han Sans CN Light - Adobe - SIL OFL 1.1"),
TextFont {
font_size: 12.0,
..default()
},
TextColor(Color::srgba(0.6, 0.6, 0.6, 0.8)),
));
parent
.spawn(Node {
flex_direction: FlexDirection::Row,
column_gap: Val::Px(8.0),
..default()
})
.with_children(spawn_size_buttons);
});
}
fn spawn_size_buttons(row: &mut bevy::ecs::relationship::RelatedSpawnerCommands<ChildOf>) {
for &size in SIZE_PRESETS {
let bg = if size == DEFAULT_SIZE {
Color::srgba(0.2, 0.7, 0.2, 1.0)
} else {
Color::srgba(0.3, 0.3, 0.4, 1.0)
};
row.spawn((
SizeButton(size),
Button,
Node {
width: Val::Px(64.0),
height: Val::Px(36.0),
justify_content: JustifyContent::Center,
align_items: AlignItems::Center,
..default()
},
BackgroundColor(bg),
))
.with_children(|btn| {
btn.spawn((
Text::new(format!("{size}px")),
TextFont {
font_size: 14.0,
..default()
},
TextColor(Color::WHITE),
));
});
}
}
fn size_button_system(
button_query: Query<(&Interaction, &SizeButton), Changed<Interaction>>,
mut text_query: Query<(&mut TextBlock, &mut TextBlockStyling), With<DemoText>>,
mut bg_query: Query<(&SizeButton, &mut BackgroundColor)>,
) {
for (&interaction, size_btn) in button_query.iter() {
if interaction != Interaction::Pressed {
continue;
}
let target = size_btn.0;
info!("Switching to {target}px");
for (mut block, mut styling) in text_query.iter_mut() {
styling.size_px = target;
styling.world_scale = target as f32;
block.set_changed();
}
for (sb, mut bg) in bg_query.iter_mut() {
*bg = if sb.0 == target {
BackgroundColor(Color::srgba(0.2, 0.7, 0.2, 1.0))
} else {
BackgroundColor(Color::srgba(0.3, 0.3, 0.4, 1.0))
};
}
}
}