🦀
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,
}
"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