🦀
chip2. "Hello, world!"を動かす
はじめに
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,
}
"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();
}
Componet
とQuery
#[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