🦀
chip3. "Hello, world!"の見た目をいじる
はじめに
2023/07/31時点の内容です。
- rustc 1.71.0
- bevy 0.11.0
bevyは開発初期段階のOSSで、まだまだ破壊的なアップデートが入ります。
でも、面白いですよ。
前回
文字の色を変えたりはどこで?
前々回では、"Hello, world!"をspawnするのに以下のコードを使いました。文字の大きさをTextStyle
のfont_size
で指定していることがわかります。
//2Dテキストを作る
fn spawn_text2d_helloworld( mut cmds: Commands )
{ let textstyle = TextStyle { font_size: 100.0, ..default() };
let text = Text::from_section( "Hello, world!", textstyle );
cmds.spawn( Text2dBundle { text, ..default() } );
}
情報を束ねている構造体bevy::text::Text2dBundle
から順に見ていくと、装飾に使えそうなフィールドが複数の構造体に分散している様子がわかります。
Text2dBundle
pub struct Text2dBundle {
pub text: Text, //文字列を格納している`text`
pub text_anchor: Anchor,
pub text_2d_bounds: Text2dBounds,
pub transform: Transform, //前回いろいろいじった`transform`
pub global_transform: GlobalTransform,
pub visibility: Visibility,
pub computed_visibility: ComputedVisibility,
pub text_layout_info: TextLayoutInfo,
}
Text
pub struct Text {
pub sections: Vec<TextSection, Global>, //文字列は`Vec`に分割格納されている
pub alignment: TextAlignment,
pub linebreak_behavior: BreakLineOn,
}
TextSection
pub struct TextSection {
pub value: String, //文字列
pub style: TextStyle, //装飾
}
TextStyle
pub struct TextStyle {
pub font: Handle<Font>, //フォント指定
pub font_size: f32, //文字の大きさ
pub color: Color, //文字の色
}
"Hello, world!"の見た目をいじる
前々回のソースコードを改造して、"Hello, world!"の1文字ごとに色と大きさを変えます。
けっこうハデ
chip3
use bevy::prelude::*;
fn main()
{ App::new()
.add_plugins( DefaultPlugins ) //各種の面倒を見てもらう
.add_systems
( Startup,
( spawn_camera2d, //カメラを作る
spawn_text2d_helloworld, //2Dテキストを作る
)
)
.add_systems
( Update,
( bevy::window::close_on_esc, //[ESC]キーで終了
change_color_helloworld, //文字の色を変える
change_size_helloworld, //文字の大きさを変える
)
)
.run();
}
//カメラを作る
fn spawn_camera2d( mut cmds: Commands )
{ cmds.spawn( Camera2dBundle::default() );
}
//マーカーの準備
#[derive( Component )] struct HelloWorld;
//2Dテキストを作る
fn spawn_text2d_helloworld( mut cmds: Commands )
{ //"Hello, world!"を1文字ごとに分割
let mut sections = Vec::new();
for char in "Hello, world!".chars()
{ let value = char.to_string();
let style = TextStyle { font_size: 100.0, ..default() };
sections.push( TextSection { value, style } );
}
let text = Text { sections, ..default() };
cmds.spawn( ( Text2dBundle { text, ..default() }, HelloWorld ) );
}
//文字の色を変える
fn change_color_helloworld
( mut q_text: Query<&mut Text, With<HelloWorld>>,
time: Res<Time>,
mut angle: Local<f32>,
)
{ let Ok ( mut text ) = q_text.get_single_mut() else { return };
let time_delta = time.delta().as_secs_f32(); //前回の実行からの経過時間
*angle += 360.0 * time_delta;
*angle -= if *angle > 360.0 { 360.0 } else { 0.0 };
//text.sectionsをイテレーターで回して、文字ごとに色を変える
for ( i, char ) in text.sections.iter_mut().enumerate()
{ //hue(色相)
let mut hue = *angle + 10.0 * i as f32;
hue -= if hue > 360.0 { 360.0 } else { 0.0 };
//文字の色を変更
char.style.color = Color::hsl( hue, 1.0, 0.5 );
}
}
//文字の大きさを変える
fn change_size_helloworld
( mut q_text: Query<&mut Text, With<HelloWorld>>,
time: Res<Time>,
mut angle: Local<f32>,
)
{ let Ok ( mut text ) = q_text.get_single_mut() else { return };
let time_delta = time.delta().as_secs_f32(); //前回の実行からの経過時間
*angle += 360.0 * time_delta;
*angle -= if *angle > 360.0 { 360.0 } else { 0.0 };
//text.sectionsをイテレーターで回して、文字ごとに大きさを変える
for ( i, char ) in text.sections.iter_mut().enumerate()
{ //sin()を使って文字の大きさを伸縮させる
let mut angle = *angle + 10.0 * i as f32;
angle -= if angle > 360.0 { 360.0 } else { 0.0 };
let size = ( 2.0 + angle.to_radians().sin() ) * 50.0;
//文字の大きさを変更
//Note:小数点以下を処理しないと実行時にメモリフットプリントが爆発する
char.style.font_size = ( size * 10.0 ).floor() / 10.0;
}
}
Text2dBundle
とTextBundle
閑話 bevy::text::Text2dBundle
とbevy::ui::node_bundles::TextBundle
はどちらもテキストを表示するために使う構造体です。
2つの使い分けは、
- 2Dゲームのスプライトと同じ感覚でテキストを使いたい場合は
Text2dBundle
を使う。座標系がスプライトと同じだし、移動・回転・拡縮の操作も同じ。 - Webアプリの感覚でCSSによるイアウトを使いたい場合は
TextBundle
を利用する。使える属性はbevy::ui::Style
を参照のこと。おそらく外部プロジェクトtaffyの進展に合わせて今後もさらに機能が増強されていくはず。
Discussion