作業メモ:bevy 0.14 → 0.15
2024/10/23時点でv0.15.0-rc.1が公開されていたのでマイグレーションしてみる
2024/10/28時点でv0.15.0-rc.2が公開されていたのでマイグレーションしてみる
2024/11/06時点でv0.15.0-rc.3が公開されていたのでマイグレーションしてみる
2024/11/20からMaster branchでマイグレーションしてみる
-
Msaa
がResourceからComponentへ変更された。
そのため以前の様にapp.insert_resource( Msaa::Sample4 );
と書けない。
Cameraをspawnする時にMsaa
をセットする。
use bevy::prelude::*;
fn main()
{ App::new()
.insert_resource( Msaa::Sample4 )
.add_plugins( DefaultPlugins )
.run();
}
use bevy::prelude::*;
fn main()
{ App::new()
.add_plugins( DefaultPlugins )
.add_systems( Startup, spawn_camera )
.run();
}
fn spawn_camera( mut cmds: Commands )
{ cmds.spawn( ( Camera3d::default(), Msaa::Sample4 ) );
}
-
Camera2dBundle
が非推奨になった。代わりにCamera2d
を使う。
なおCamera2d::default()
と書くとclippyにwarningをもらうのでCamera2d
だけでいいらしい。 -
Camera3dBundle
が非推奨になった。代わりにCamera3d
を使う。 -
DirectionalLightBundle
が非推奨になった。代わりにDirectionalLight
を使う。
「✕✕が非推奨になった。代わりに○○を使う。」が多いのはv0.15で導入された新機能Required Componentsによるもので、Bundleは廃止路線のようですね。
v0.15のText UI関係は、破壊的変更が多いらしい。
-
Text2dBundle
が非推奨になった。代わりにText2d
を使う。 - (未確認だけど)
TextBundle
も非推奨だろきっと。代わりにText
だろ絶対。 - 各設定の場所
- v0.14:
Text
(justify,linebreak)、TextSection
(string)、TextStyle
(font,font_size,color) - v0.15:
Text
/Text2d
(string)、TextFont
(font,font_size)、TextColor
(color)、TextLayout
(justify,linebreak)
- v0.14:
use bevy::{ prelude::*, color::palettes::* };
fn main()
{ App::new()
.add_plugins( DefaultPlugins )
.add_systems( Startup, spawn_helloworld )
.run();
}
fn spawn_helloworld( mut cmds: Commands )
{ cmds.spawn( Camera2dBundle::default() );
let style = TextStyle { font_size: 100.0, color: css::YELLOW.into(), ..default() };
let text = Text::from_section( "Hello, world!", style );
cmds.spawn( Text2dBundle { text, ..default() } );
}
use bevy::{ prelude::*, color::palettes::* };
fn main()
{ App::new()
.add_plugins( DefaultPlugins )
.add_systems( Startup, spawn_helloworld )
.run();
}
fn spawn_helloworld( mut cmds: Commands )
{ cmds.spawn( Camera2d );
cmds.spawn( (
Text2d::new( "Hello, world!" ),
TextFont { font_size: 100.0, ..default() },
TextColor ( css::YELLOW.into() ),
) );
}
3Dメッシュ関係のメモ。
-
PbrBundle
が非推奨になった。代わりにMesh3d
(形状)とMeshMaterial3d
(色/テクスチャ)を組み合わせる。
use bevy::{ prelude::*, color::palettes::* };
fn main()
{ App::new()
.add_plugins( DefaultPlugins )
.add_systems( Startup, spawn_sphere )
.run();
}
fn spawn_sphere
( mut cmds: Commands,
mut meshes: ResMut<Assets<Mesh>>,
mut materials: ResMut<Assets<StandardMaterial>>,
)
{ //3Dカメラと光源
let position = Vec3::new( -2.0, 2.0, 2.0 );
cmds.spawn
( ( Camera3d::default(),
Transform::from_translation( position ).looking_at( Vec3::ZERO, Vec3::Y ),
) );
let position = Vec3::new( 1.0, 3.0, 2.0 );
cmds.spawn
( ( DirectionalLight { illuminance: 3000.0, shadows_enabled: true, ..default() },
Transform::from_translation( position ).looking_at( Vec3::ZERO, Vec3::Y ),
) );
//3D球体
cmds.spawn
( ( Mesh3d ( meshes.add( Sphere::default() ) ),
MeshMaterial3d ( materials.add( Color::Srgba ( css::YELLOW ) ) ),
) );
}
-
NodeBundle
が非推奨になった。代わりにNode
を使う。 - v0.14まで
NodeBundle
のメンバーだったStyle
は、v0.15で廃止された。その中にあったWEB CSS 似のパラメータ38つはそのまま丸ごとNode
に移されている。
pub struct Node {
pub display: Display,
pub position_type: PositionType,
pub overflow: Overflow,
pub overflow_clip_margin: OverflowClipMargin,
pub left: Val,
pub right: Val,
pub top: Val,
pub bottom: Val,
pub width: Val,
pub height: Val,
pub min_width: Val,
pub min_height: Val,
pub max_width: Val,
pub max_height: Val,
pub aspect_ratio: Option<f32>,
pub align_items: AlignItems,
pub justify_items: JustifyItems,
pub align_self: AlignSelf,
pub justify_self: JustifySelf,
pub align_content: AlignContent,
pub justify_content: JustifyContent,
pub margin: UiRect,
pub padding: UiRect,
pub border: UiRect,
pub flex_direction: FlexDirection,
pub flex_wrap: FlexWrap,
pub flex_grow: f32,
pub flex_shrink: f32,
pub flex_basis: Val,
pub row_gap: Val,
pub column_gap: Val,
pub grid_auto_flow: GridAutoFlow,
pub grid_template_rows: Vec<RepeatedGridTrack>,
pub grid_template_columns: Vec<RepeatedGridTrack>,
pub grid_auto_rows: Vec<GridTrack>,
pub grid_auto_columns: Vec<GridTrack>,
pub grid_row: GridPlacement,
pub grid_column: GridPlacement,
}
-
TextBundle
はv0.15で非推奨になり今後はText
を使うようになる。
v0.14までTextBundle
の中にあったStyle
がv0.15で廃止され、その中身がNode
に移されたことにより、v0.15からはText
にCSSレイアウトを反映したい場合はNode
も明示的に設定しないといけない。
use bevy::{ prelude::*, color::palettes::* };
fn main()
{ App::new()
.add_plugins( DefaultPlugins )
.add_systems( Startup, spawn_css_layout )
.run();
}
fn spawn_css_layout( mut cmds: Commands )
{ cmds.spawn( Camera2d ); //2Dカメラ
//クロージャ
let node_text =
| text: &str, align_self: AlignSelf, justify_self: JustifySelf |
{ ( Node { align_self, justify_self, ..default() }, //CSSレイアウトの反映にNodeが必要
Text::new( text.to_string() ),
TextFont { font_size: 30.0, ..default() },
TextColor ( css::YELLOW.into() ),
BackgroundColor ( css::RED.into() ),
)
};
cmds.spawn
( Node //レイアウト用の親ノード
{ width : Val::Percent ( 100.0 ),
height: Val::Percent ( 100.0 ),
display: Display::Grid, //CSSグリッドレイアウト
grid_template_columns: RepeatedGridTrack::fr( 3, 1.0 ), //3列
..default()
}
)
.with_children //テキスト表示用の子ノード
( |cmds|
{ cmds.spawn( node_text( "TOP/LEFT" , AlignSelf::Start , JustifySelf::Start ) );
cmds.spawn( node_text( "TOP" , AlignSelf::Start , JustifySelf::Center ) );
cmds.spawn( node_text( "TOP/RIGHT" , AlignSelf::Start , JustifySelf::End ) );
cmds.spawn( node_text( "LEFT" , AlignSelf::Center, JustifySelf::Start ) );
cmds.spawn( node_text( "CENTER" , AlignSelf::Center, JustifySelf::Center ) );
cmds.spawn( node_text( "RIGHT" , AlignSelf::Center, JustifySelf::End ) );
cmds.spawn( node_text( "BOTTOM/LEFT" , AlignSelf::End , JustifySelf::Start ) );
cmds.spawn( node_text( "BOTTOM" , AlignSelf::End , JustifySelf::Center ) );
cmds.spawn( node_text( "BOTTOM/RIGHT", AlignSelf::End , JustifySelf::End ) );
}
);
}
ゲームパッド関係は、破壊的変更が入ってスッキリした。
- ゲームパッドの入力を処理する関数は、v0.14では4つくらい引数を取った(全部Resource)。v0.15では1つQueryを書くだけでいいのでスッキリ。
- 対戦ゲーム等で複数のゲームパッドを接続する場合、v0.14では
Gamepad
のフィールドid
で識別した。v0.15ではQuery<(Entity, &Gamepad)>
としてEntityで識別する。
fn input_gamepad
( gamepads : Res<Gamepads>, //Queryに変わった
input_button: Res<ButtonInput<GamepadButton>>, //要らなくなった
axis_stick : Res<Axis<GamepadAxis>>, //要らなくなった
axis_button : Res<Axis<GamepadButton>>, //要らなくなった
)
{ for gamepad in gamepads.iter()
{ if gamepad.id == xxx //xxxはusize型で、接続時にアサインされたIDとする
{ ....
}
}
}
fn input_gamepad
( qry_gamepads: Query<(Entity, &Gamepad)>,
)
{ for ( entity, gamepad ) in qry_gamepads
{ if entity == xxx //xxxはEntity型で、以下同文
{ ....
}
}
}
-
GamepadButtonType
がGamepadButton
にリネームされてスッキリ。 -
gamepad.get_pressed()
やgamepad.pressed( .... )
でボタンの状態を取得できる。
for ( _, gamepad ) in &qry_gamepads
{ //十字ボタン&トリガー
gamepad.get_pressed().for_each
( | &button |
match button
{ GamepadButton::DPadUp => { .... },
GamepadButton::DPadDown => { .... },
GamepadButton::DPadRight => { .... },
GamepadButton::DPadLeft => { .... },
GamepadButton::RightTrigger => { .... },
GamepadButton::LeftTrigger => { .... },
_ => (),
}
);
}
-
GamepadAxisType
がGamepadAxis
にリネームされてスッキリ。 -
gamepad.get( .... )
がOptionでラップされたアナログ入力の変化量を返してくれる。
for ( _, gamepad ) in &qry_gamepads
{ //スティック&トリガー(アナログ入力)
if let Some( value ) = gamepad.get( GamepadAxis::LeftStickY ) { .... }
if let Some( value ) = gamepad.get( GamepadAxis::LeftStickX ) { .... }
if let Some( value ) = gamepad.get( GamepadButton::RightTrigger2 ) { .... }
if let Some( value ) = gamepad.get( GamepadButton::LeftTrigger2 ) { .... }
}
WindowMode
の機能が拡張されていた。
- ウィンドウ⇔フルスクリーンを切り替えるだけだったv0.14の
WindowMode
に対して、v0.15では複数ディスプレイ接続中にどのモニタを使うかMonitorSelection
で選択できるようになった。 - 使い方に悩んだら取り敢えず
MonitorSelection::Primary
で良いんじゃなかろうか。
ダライアスみたいなマルチモニターゲーム用の機能かな?
pub enum WindowMode {
Windowed,
BorderlessFullscreen,
SizedFullscreen,
Fullscreen,
}
pub enum WindowMode {
Windowed,
BorderlessFullscreen(MonitorSelection),
SizedFullscreen(MonitorSelection),
Fullscreen(MonitorSelection),
}
pub enum MonitorSelection {
Current,
Primary,
Index(usize),
Entity(Entity),
}
Gizmoのメモ。
-
.grid()
の引数が変更された。v0.14の第一・第二引数(positionとrotation)を、v0.15ではまとめてIsometry3d
で渡す。その時、positionの軸が変わるようだ。
gizmos.grid
( Vec3::Z * 0.5,
Quat::from_rotation_x( PI * 0.5 ),
UVec2::new( 5, 5 ),
Vec2::splat( 1.0 ),
css::GREEN,
)
.outer_edges();
let posi_rote = Isometry3d::new( Vec3::NEG_Y * 0.5, Quat::from_rotation_x( PI * 0.5 ) );
gizmos.grid
( posi_rote,
UVec2::new( 5, 5 ),
Vec2::splat( 1.0 ),
css::GREEN,
)
.outer_edges();
-
grid_2d()
も同様。ただし2Dなので、v0.15ではIsometry2d
を使ってpositionとrotationを渡す。rotationはf32
ではなくRot2::radians( f32 )
になる。
let posi_rote = Isometry2d::new( Vec2::ZERO, Rot2::radians( PI * 0.5 ) );
-
SpriteBundle
が非推奨になった。代わりにSprite
を使う。
スプライト画像のHandle<Image>
が、v0.14では独立したComponetだったのに対し、v0.15ではSprite
のフィールドになっている。
pub struct Sprite {
pub color: Color,
pub flip_x: bool,
pub flip_y: bool,
pub custom_size: Option<Vec2>,
pub rect: Option<Rect>,
pub anchor: Anchor,
}
pub struct SpriteBundle {
pub sprite: Sprite,
pub transform: Transform,
pub global_transform: GlobalTransform,
pub texture: Handle<Image>, //スプライト画像
pub visibility: Visibility,
pub inherited_visibility: InheritedVisibility,
pub view_visibility: ViewVisibility,
}
pub struct Sprite {
pub image: Handle<Image>, //スプライト画像
pub texture_atlas: Option<TextureAtlas>,
pub color: Color,
pub flip_x: bool,
pub flip_y: bool,
pub custom_size: Option<Vec2>,
pub rect: Option<Rect>,
pub anchor: Anchor,
pub image_mode: SpriteImageMode,
}
Textのセクションの考え方が個人的にちょっと改悪に見える‥‥。
というのは、セクションの先頭だけ特別扱いする理由が自分には分からないからなんだけど。
- v0.14では、Textのセクションは
Vec
だった。要素は先頭から末尾まですべて同じ扱い。 - v0.15では先頭要素だけ
Text
でspawnし、残りの要素はTextSpan
でpawnする。
先頭が親要素、残りが子要素の位置づけ。
親はそのText UIノードの代表で、CSSレイアウトのNode
等を持てる。
use bevy::{ prelude::*, color::palettes::* };
fn main()
{ App::new()
.add_plugins( DefaultPlugins )
.add_systems( Startup, spawn_text_sections )
.run();
}
fn spawn_text_sections( mut cmds: Commands )
{ cmds.spawn( Camera2dBundle::default() ); //2Dカメラ
let font_size = 60.0;
let sections = vec!
[ TextSection
{ value: "first, ".to_string(),
style: TextStyle { font_size, color: css::RED.into(), ..default() }
},
TextSection
{ value: "second, ".to_string(),
style: TextStyle { font_size, color: css::GREEN.into(), ..default() }
},
TextSection
{ value: "third\n".to_string(),
style: TextStyle { font_size, color: css::BLUE.into(), ..default() }
},
TextSection
{ value: "end.".to_string(),
style: TextStyle { font_size, color: css::BLACK.into(), ..default() }
},
];
cmds.spawn( TextBundle::from_sections( sections ) );
}
use bevy::{ prelude::*, color::palettes::* };
fn main()
{ App::new()
.add_plugins( DefaultPlugins )
.add_systems( Startup, spawn_text_sections )
.run();
}
fn spawn_text_sections( mut cmds: Commands )
{ cmds.spawn( Camera2d ); //2Dカメラ
let font_size = 60.0;
cmds.spawn
( ( Text::new( "first, " ),
TextFont { font_size, ..default() },
TextColor ( css::RED.into() ),
) )
.with_children
( | cmds |
{ cmds.spawn
( ( TextSpan::new( "second, " ),
TextFont { font_size, ..default() },
TextColor ( css::GREEN.into() ),
) );
cmds.spawn
( ( TextSpan::new( "third\n" ),
TextFont { font_size, ..default() },
TextColor ( css::BLUE.into() ),
) );
cmds.spawn
( ( TextSpan::new( "end." ),
TextFont { font_size, ..default() },
TextColor ( css::BLACK.into() ),
) );
}
);
}
Time
のメモ。
-
Time
のメソッドtime.elapsed_seconds_wrapped()
が、v0.15ではtime.elapsed_secs_wrapped()
にリネームされた。(…seconds…→…secs… 省略形にしたのか (^_^;)
Textの書き換えに、いくつか方法がある。
A) セクションが分かれていないケース(Text
だけのケース)
1. Query<&mut Text, With<XXXX>>
する
2. let Ok ( mut text ) = query.get_single_mut() else { .... };
とかでラップを剥く
3. text.0 = "ZZZZ".to_string()
で書き換える。
B) セクションが複数に分かれているケース(Text
+TextSpan
×n個のケース)
1. Text
部分は A) と同じ
2. TextSpan
部分もほぼ A) と同じだが、Query<&mut TextSpan, With<XXXX>>
になる。
Queryのiter()ではセクションの順序が保証されない点は要注意。順序が重要なら C) を使う。
C) インデックスを使ってセクションを指定する方法(Text
とTextSpan
を区別しなくて済む)
use bevy::{ prelude::*, color::palettes::* };
fn main()
{ App::new()
.add_plugins( DefaultPlugins )
.add_systems( Startup, spawn_text_sections )
.add_systems( Update, uapdate_text.run_if( run_once ) ) //一度だけ実行
.run();
}
fn spawn_text_sections( mut cmds: Commands )
{ cmds.spawn( Camera2d ); //2Dカメラ
cmds.spawn
( ( Text::new( "" ), //placeholder
TextFont { font_size: 50.0, ..default() },
TextColor ( css::RED.into() ),
) )
.with_children
( | cmds |
{ cmds.spawn
( ( TextSpan::new( "" ), //placeholder
TextFont { font_size: 50.0, ..default() },
TextColor ( css::GREEN.into() ),
) );
cmds.spawn
( ( TextSpan::new( "" ), //placeholder
TextFont { font_size: 50.0, ..default() },
TextColor ( css::BLUE.into() ),
) );
}
);
}
fn uapdate_text
( query: Query<Entity, With<Text>>, //Text(親)のEntityをQueryする
mut writer: TextUiWriter,
)
{ let Ok ( entity ) = query.get_single() else { return };
//TextとTextSpanの区別なくインデックス(0~2)でアクセスできる
// for ( index, s ) in ( 0.. ).zip( [ "One, ", "Two, ", "Three" ] )
// { if let Some ( mut text ) = writer.get_text( entity, index ) { *text = s.into() }
// }
let mut s = [ "One, ", "Two, ", "Three" ].iter();
writer.for_each_text( entity, | mut text | { *text = s.next().unwrap().to_string() } );
}
Textセクションの操作ちょっと複雑だなぁ。なんかまた将来 破壊的変更 入りそう ( ̄~ ̄;) 。
気付いたことメモ。
- 子を先にspawnして親を後からspawnする場合に使うことがある
push_children()
が、v0.15ではadd_children()
にリネームされているようだ。
cmds.spawn( 親 ).push_children( &[ 子 ] );
cmds.spawn( 親 ).add_children( &[ 子 ] );