🦀

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

に公開

はじめに

2025/04/26時点の内容です。

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

前回

chip1. RustとBevyで"Hello, world!"

Transformで移動、回転、拡縮

bevyでモノを動かす場合お世話になるのがTransformです。
見てのとおり、移動(translation)、回転(rotation)、拡縮(scale)ができます。

Transform
pub struct Transform {
    pub translation: Vec3,
    pub rotation: Quat,
    pub scale: Vec3,
}

https://docs.rs/bevy/0.16.0/bevy/transform/components/struct.Transform.html

"Hello, world!"を動かす

前回のソースコードを改造して、3つ表示した"Hello, world!"を移動・回転・拡大縮小させます。

main()の変更
use bevy::
{   prelude::*,
    log::LogPlugin, //ログ出力の制御
};

fn main() -> AppExit
{   //ログレベル調整
    let filter = "warn,wgpu_hal=error".into();

    //アプリを生成、Pluginを登録、Systemを登録、そして実行
    App::new()
        .add_plugins( DefaultPlugins.set( LogPlugin { filter, ..default() } ) )

        //初期化時に一回だけ実行するSystemを登録(Startup)
        .add_systems( Startup, spawn_helloworlds )

        //繰り返し実行するSystemを登録(Update)
        .add_systems
        (   Update,
            (   move_helloworld,   //移動
                rotate_helloworld, //回転
                scale_helloworld,  //拡大縮小
            )
        )

        .run() //実行
}
Text2dを3つspawnする
//Queryで使うマーカーの宣言
#[derive( Component )] struct MovingHW;
#[derive( Component )] struct RotatingHW;
#[derive( Component )] struct ScalingHW;

fn spawn_helloworlds( mut cmds: Commands )
{   //2Dカメラをspawnする
    cmds.spawn( Camera2d );

    //2Dテキストを3つspawnする
    cmds.spawn
    (   (   Text2d::new( "Hello, world!" ),
            TextFont { font_size: 50.0, ..default() },
            Transform::from_xyz( 400.0, 0.0, 0.0 ), //X軸を400.0にセット
            MovingHW, //マーカーComponent
        )
    );
    cmds.spawn
    (   (   Text2d::new( "Hello, world!" ),
            TextFont { font_size: 50.0, ..default() },
            Transform::from_xyz( 0.0, 0.0, 0.0 ), //X軸を0.0にセット
            RotatingHW, //マーカーComponent
        )
    );
    cmds.spawn
    (   (   Text2d::new( "Hello, world!" ),
            TextFont { font_size: 50.0, ..default() },
            Transform::from_xyz( -400.0, 0.0, 0.0 ), //X軸を-400.0にセット
            ScalingHW, //マーカーComponent
        )
    );
}
移動・回転・拡縮の各System
//stdライブラリ
use std::f32::consts::TAU; //TAU = 2π

//"Hello, world!"を動かす
fn move_helloworld
(   mut qry_transform: Query<&mut Transform, With<MovingHW>>,
    time: Res<Time>,
    mut angle: Local<f32>, //Local resource
) -> Result
{   let mut transform = qry_transform.single_mut()?;

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

    //楕円軌道の移動
    transform.translation.x = angle.cos() * 400.0; //横軸は半径400
    transform.translation.y = angle.sin() * 200.0; //縦軸は半径200

    Ok(())
}

//"Hello, world!"を回転する
fn rotate_helloworld
(   mut qry_transform: Query<&mut Transform, With<RotatingHW>>,
    time: Res<Time>,
) -> Result
{   let mut transform = qry_transform.single_mut()?;

    //前回からの経過時間により角度を進める
    let angle = TAU * time.delta().as_secs_f32() * 0.4;
    let quat = Quat::from_rotation_z( angle );

    //四元数の回転(Quatは掛けた角度の分だけ回転が進む)
    transform.rotation *= quat;

    Ok(())
}

//"Hello, world!"を拡縮する
fn scale_helloworld
(   mut qry_transform: Query<&mut Transform, With<ScalingHW>>,
    time: Res<Time>,
    mut angle: Local<f32>, //Local resource
) -> Result
{   let mut transform = qry_transform.single_mut()?;

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

    //拡大縮小(sin()がマイナスになると表示が反転するのでabs()する)
    transform.scale = Vec3::ONE * angle.sin().abs();

    Ok(())
}

ComponetとQuery

#[derive( Component )]を付けて宣言した3つの型はComponentとして扱われます。

//Queryで使うマーカーの宣言
#[derive( Component )] struct MovingHW;
#[derive( Component )] struct RotatingHW;
#[derive( Component )] struct ScalingHW;

これらの型は、以下の2か所に登場します。

  • "Hello, world!"のEntityをspawnする箇所にマーカーとして登場
    cmds.spawn
    (   (   Text2d::new( "Hello, world!" ),
            TextFont { font_size: 50.0, ..default() },
            Transform::from_xyz( 400.0, 0.0, 0.0 ), //X軸を400.0にセット
            MovingHW, //マーカーComponent
        )
    );
  • 移動・回転・拡縮のSystemの引数
//"Hello, world!"を動かす
fn move_helloworld
(   mut qry_transform: Query<&mut Transform, With<MovingHW>>,
    time: Res<Time>,
    mut angle: Local<f32>, //Local resource
) -> Result
{   let mut transform = qry_transform.single_mut()?;
 :
 :
 :
    Ok(())
}

移動・回転・拡縮の各System(関数)の引数にはQuery<&mut Transform, With< **Component** >>と書いてあり、これによってマーカーComponentで目印をつけられたEntityのTransformを検索し取得することができます。

Localリソース

移動と拡縮のSystemの引数にLoaclが登場しています。
LoaclはSystemの中だけで参照・更新できるResourceで、Systemの最初の実行時に一度だけDefault()で初期化され、その後は値を保持し続けます。Systemを繰り返し呼び出しても値を維持できるので便利です。

Discussion