🦀

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

2023/07/29に公開

はじめに

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

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

前回

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

Transformで移動、回転、拡縮

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

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

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

"Hello, world!"を動かす

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

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

//Componentの準備
#[derive( Component )] struct LeftText;
#[derive( Component )] struct CenterText;
#[derive( Component )] struct RightText;

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

        .add_systems
        (   Update,
            (   move_helloworld,   //移動
                rotate_helloworld, //回転
                scale_helloworld,  //拡大縮小
            )
        )
        .run()
}

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

    //2Dテキストを3つspawnする
    let mut text2d = Vec::new();
    for x in [ -400.0, 0.0, 400.0 ]
    {   let style = TextStyle { font_size: 50.0, ..default() };
        let text = Text::from_section( "Hello, world!", style.clone() );
        let transform = Transform::from_xyz( x, 0.0, 0.0 );
        text2d.push( Text2dBundle { text, transform, ..default() } );
    }
    cmds.spawn( ( text2d.pop().unwrap(), RightText  ) ); //NOTE:
    cmds.spawn( ( text2d.pop().unwrap(), CenterText ) ); //.pop()すると.push()の逆順になる為
    cmds.spawn( ( text2d.pop().unwrap(), LeftText   ) ); //Right→Center→Leftの順にspawnする
}

//移動
fn move_helloworld
(   mut qry_transform: Query<&mut Transform, With<LeftText>>,
    time: Res<Time>,
    mut angle: Local<f32>, //Local resource
)
{   let Ok ( mut transform ) = qry_transform.get_single_mut() else { return };

    //前回からの経過時間により角度を進める
    *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
}

//回転
fn rotate_helloworld
(   mut qry_transform: Query<&mut Transform, With<CenterText>>,
    time: Res<Time>,
)
{   let Ok ( mut transform ) = qry_transform.get_single_mut() else { return };

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

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

//拡大縮小
fn scale_helloworld
(   mut qry_transform: Query<&mut Transform, With<RightText>>,
    time: Res<Time>,
    mut angle: Local<f32>, //Local resource
)
{   let Ok ( mut transform ) = qry_transform.get_single_mut() else { return };

    //前回からの経過時間により角度を進める
    *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();
}

ComponetQuery

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

//Componentの準備
#[derive( Component )] struct LeftText;
#[derive( Component )] struct CenterText;
#[derive( Component )] struct RightText;

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

  • "Hello, world!"をspawnする箇所
    cmds.spawn( ( text2d.pop().unwrap(), RightText  ) ); //NOTE:
    cmds.spawn( ( text2d.pop().unwrap(), CenterText ) ); //.pop()すると.push()の逆順になる為
    cmds.spawn( ( text2d.pop().unwrap(), LeftText   ) ); //Right→Center→Leftの順にspawnする
  • 移動・回転・拡縮の関数の引数
//移動
fn move_helloworld
(   mut qry_transform: Query<&mut Transform, With<LeftText>>,
 :

//回転
fn rotate_helloworld
(   mut qry_transform: Query<&mut Transform, With<CenterText>>,
 :

//拡大縮小
fn scale_helloworld
(   mut qry_transform: Query<&mut Transform, With<RightText>>,
 :

移動・回転・拡縮の関数はそれぞれTransformを必要としています。
Query<&mut Transform, With< *Component* >>と書くことで、必要なTransformを取得しています。

Localリソース

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

Discussion