🦀

chip3. "Hello, world!"の見た目をいじる

2023/07/31に公開

はじめに

2024/09/14時点の内容です。

  • rustc 1.81.0
  • bevy 0.14.2
    bevyは開発初期段階のOSSで、まだまだ破壊的なアップデートが入ります。
    でも、面白いですよ。

前回

chip2. "Hello, world!"を動かす

文字の色を変えたりはどこで?

前々回では、"Hello, world!"をspawnするのに以下のコードを使いました。文字の大きさをTextStylefont_sizeで指定していることがわかります。

    //2Dテキストをspawnする
    let style = TextStyle { font_size: 100.0, ..default() };
    let text = Text::from_section( "Hello, world!", style );
    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 inherited_visibility: InheritedVisibility,
    pub view_visibility: ViewVisibility,
    pub text_layout_info: TextLayoutInfo,
    pub sprite_source: SpriteSource,
}

bevy::text::Text

Text
pub struct Text {
    pub sections: Vec<TextSection>, //文字列は`Vec`に分割格納されている
    pub justify: JustifyText, //ノードの内側における右・左・中央寄せ
    pub linebreak_behavior: BreakLineOn,
}

bevy::text::TextSection

TextSection
pub struct TextSection {
    pub value: String, //表示する文字列
    pub style: TextStyle, //装飾
}

bevy::text::TextStyle

TextStyle
pub struct TextStyle {
    pub font: Handle<Font>, //フォント指定
    pub font_size: f32, //文字の大きさ
    pub color: Color, //文字の色
}

"Hello, world!"の見た目をいじる

前々回のソースコードを改造して、"Hello, world!"の1文字ごとに色と大きさを変えます。
けっこうハデ

use bevy::
{   prelude::*,
    log::LogPlugin, //ログ出力の制御
};
use std::f32::consts::TAU; // TAU = 2π

//Componentの準備
#[derive( Component )] struct HelloWorld;

//メイン関数
fn main() -> AppExit
{   App::new()
        .add_plugins
        (   //ウインドウやスケジュール等、各種の面倒を見てもらう
            DefaultPlugins
                .set( LogPlugin { filter: "warn".into(), ..default() } )
        )
        .add_systems( Startup, spawn_helloworld ) //テキストを表示する
        .add_systems( Update, change_letter_style ) //文字の色と大きさを変える
        .run()
}

//テキストを表示する
fn spawn_helloworld( mut cmds: Commands )
{   //2Dカメラをspawnする
    cmds.spawn( Camera2dBundle::default() );

    //"Hello, world!"を1文字ごとに分割した`Text`を作る
    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() };

    //2Dテキストをspawnする
    cmds.spawn( ( Text2dBundle { text, ..default() }, HelloWorld ) );
}

//文字の色と大きさを変える
fn change_letter_style
(   mut qry_text: Query<&mut Text, With<HelloWorld>>,
    time: Res<Time>,
    mut angle: Local<f32>, //Local resource
)
{   let Ok ( mut text ) = qry_text.get_single_mut() else { return };

    //前回からの経過時間により角度を進める
    *angle += TAU * time.delta().as_secs_f32();
    *angle -= if *angle > TAU { TAU } else { 0.0 };

    //文字ごとに色を変える
    for ( i, char ) in text.sections.iter_mut().enumerate()
    {   //hue(色相)
        let mut hue = *angle + i as f32 * 0.3;
        hue -= if hue > TAU { TAU } else { 0.0 };

        //sin()を使って文字の大きさを伸縮させる
        let mut angle = *angle + i as f32 * 0.5;
        angle -= if angle > TAU { TAU } else { 0.0 };
        let size = ( ( 2.0 + angle.sin() ) * 500.0 ).floor() / 10.0 ;

        //文字の色と大きさを変える
        char.style.color = Color::hsl( hue.to_degrees(), 1.0, 0.5 );
        char.style.font_size = size; //font_size 50~150
    }
}

おまけ:Text2dBundleTextBundle

bevy::text::Text2dBundlebevy::ui::node_bundles::TextBundleはどちらもテキストを表示するために使うバンドルです。2つの使い分けはたぶんこんな感じ。

  • 2Dゲームのスプライトと同じ感覚でテキストを使いたい場合はText2dBundleを使う。座標系がスプライトと同じだし、移動・回転・拡縮の操作も同じ。
  • Webアプリの感覚でCSSによるイアウトを使いたい場合はTextBundleを利用する。flexレイアウトやgridレイアウトが使える。有効な属性はbevy::ui::Styleを参照のこと。

冒頭でも注意書きをしましたが、近々1年以内にUIは大改造されるので、あまり現在の仕様にこだわらない方がよさそうです。

Discussion