Closed13
作業メモ:bevy 0.9 → 0.10
メインウィンドウの表示
Bevy 0.9
let window = WindowDescriptor
{ title : APP_TITLE.to_string(),
width : SCREEN_PIXELS_WIDTH,
height : SCREEN_PIXELS_HEIGHT,
resizable: false,
..default()
};
app.add_plugins( DefaultPlugins.set( WindowPlugin { window, ..default() } ) );
Bevy 0.10
let window = Window
{ title : APP_TITLE.to_string(),
resolution: ( SCREEN_PIXELS_WIDTH, SCREEN_PIXELS_HEIGHT ).into(),
resizable : false,
..default()
};
let primary_window = Some( window );
app.add_plugins( DefaultPlugins.set( WindowPlugin { primary_window, ..default() } ) );
-
WindowDescriptor
がWindow
に改名され、その構造体のwidth
とheight
がresolution
にまとめられた。resolution
の型は意識する必要はなく(f32,f32).into()
を使って導出できる。 -
WindowPlugin
構造体のwindow
がprimary_window
に改名され、Option
でラップされた。
アンチエイリアスの設定
Bevy 0.9
app.insert_resource( Msaa { samples: 4 } );
Bevy 0.10
app.insert_resource( Msaa::Sample4 );
Stateのderiveと初期化
Bevy 0.9
#[derive( Clone, Copy, Eq, PartialEq, Hash, Debug )]
enum GameState
{ InitApp,
TitleDemo, DemoLoop,
GameStart, StageStart, MainLoop, StageClear, GameOver,
Pause, Debug,
}
app.add_state( GameState::InitApp );
Bevy 0.10
#[derive( Clone, Copy, Eq, PartialEq, Hash, Debug, Default, States )]
enum GameState
{ #[default] InitApp,
TitleDemo, DemoLoop,
GameStart, StageStart, MainLoop, StageClear, GameOver,
Pause, Debug,
}
app.add_state::<GameState>();
-
#[derive(…)]
にDefault
とStates
が増えた。#[default]
によって初期値を指定する。 -
.add_state()
の書き方が変わった。
SystemLabeのderive
Bevy 0.9
#[derive( SystemLabel, Clone )]
Bevy 0.10
#[derive( SystemSet, Clone, Debug, PartialEq, Eq, Hash )]
以下の指示に従って変更。
SystemLabel derives should be replaced with SystemSet. You will also need to add the Debug, PartialEq, Eq, and Hash traits to satisfy the new trait bounds.
フルスクリーンとウィンドウモードを切り替える関数
Bevy 0.9
use bevy::window::WindowMode::*;
fn toggle_window_mode( mut windows: ResMut<Windows> )
{ if let Some( window ) = windows.get_primary_mut()
{ let mode = if window.mode() == Windowed { SizedFullscreen } else { Windowed };
window.set_mode( mode );
}
}
Bevy 0.10
use bevy::window::WindowMode::*;
fn toggle_window_mode( mut windows: Query<&mut Window> )
{ if let Ok( mut window ) = windows.get_single_mut()
{ let mode = if window.mode == Windowed { SizedFullscreen } else { Windowed };
window.mode = mode;
}
}
- 関数の引数を
ResMut<Windows>
からQuery<&mut Window>
へ変更した(Window
がResource
からComponet
へクラスチェンジした影響)。それに合わせてwindows.get_primary_mut()
をwindows.get_single_mut()
へ変更した。 - ゲッタ・セッタがなくなった(?)らしく、
Window
構造体mode
への直接アクセスへ変更。
ECS Schedule v3 (1)
.add_system_set()
SystemSet
::on_enter()
::on_update()
::on_exit()
Bevy 0.9
app
.add_system_set
( SystemSet::on_enter( GameState::InitApp ) //<ENTER>
.with_system( start_fetching_assets ) //Assetのロード開始
.with_system( spawn_sprite_now_loading ) //アニメ用スプライトの生成
)
.add_system_set
( SystemSet::on_update( GameState::InitApp ) //<UPDATE>
.with_system( change_state_after_loading ) //ロード完了か判定しState変更
.with_system( move_sprite_now_loading ) //ローディングアニメ
)
.add_system_set
( SystemSet::on_exit( GameState::InitApp ) //<EXIT>
.with_system( despawn_entity::<SpriteTile> ) //アニメ用スプライトの削除
.with_system( spawn_game_frame ) //ゲームの枠の表示
);
Bevy 0.10 .add_system()を使う場合
app
.add_system( start_fetching_assets .in_schedule( OnEnter( GameState::InitApp ) ) )
.add_system( spawn_sprite_now_loading .in_schedule( OnEnter( GameState::InitApp ) ) )
.add_system( change_state_after_loading .in_set( OnUpdate( GameState::InitApp ) ) )
.add_system( move_sprite_now_loading .in_set( OnUpdate( GameState::InitApp ) ) )
.add_system( despawn_entity::<SpriteTile> .in_schedule( OnExit( GameState::InitApp ) ) )
.add_system( spawn_game_frame .in_schedule( OnExit( GameState::InitApp ) ) );
Bevy 0.10 .add_systems()を使う場合 (1)
app
.add_systems
( ( start_fetching_assets .in_schedule( OnEnter( GameState::InitApp ) ),
spawn_sprite_now_loading .in_schedule( OnEnter( GameState::InitApp ) ),
change_state_after_loading .in_set( OnUpdate( GameState::InitApp ) ),
move_sprite_now_loading .in_set( OnUpdate( GameState::InitApp ) ),
despawn_entity::<SpriteTile> .in_schedule( OnExit( GameState::InitApp ) ),
spawn_game_frame .in_schedule( OnExit( GameState::InitApp ) ),
),
);
Bevy 0.10 .add_systems()を使う場合 (2)
app
.add_systems
( ( start_fetching_assets,
spawn_sprite_now_loading, ).in_schedule( OnEnter( GameState::InitApp ) ),
)
.add_systems
( ( change_state_after_loading,
move_sprite_now_loading, ).in_set( OnUpdate( GameState::InitApp ) ),
)
.add_systems
( ( despawn_entity::<SpriteTile>,
spawn_game_frame, ).in_schedule( OnExit( GameState::InitApp ) ),
);
-
.add_system_set()
ではなく.add_system()
や.add_systems()
を使って関数を登録する。 -
SystemSet
というグルーピングの手段がなくなった代わりに、.add_systems()
はタプルによって関数を一度に複数登録できる。MAXはいくつなんだろう? -
.in_schedule()
や.in_set()
といったメソッドは関数単体や(関数, 関数, …)というタプルに生やせる。 -
::on_enter()
::on_update()
::on_exit()
の置き換えは下記の表のとおり。updateだけメソッドが違う理由は何だろう?
0.9 | 0.10 |
---|---|
::on_enter(…) | .in_schedule( OnEnter(…) ) |
::on_update(…) | .in_set( OnUpdate(…) ) |
::on_exit(…) | .in_schedule( OnExit(…) ) |
ECS Schedule v3 (2)
State
の操作
Bevy 0.9
fn change_state( mut state: ResMut<State<GameState>> )
{ let _ = state.overwrite_set( GameState::Next );
}
Bevy 0.10
fn change_state( mut next_state: ResMut<NextState<GameState>> )
{ next_state.set( GameState::Next );
}
-
State
を変更する場合、ResMut<State<GameState>>
を操作せず、ResMut<NextState<GameState>>
にセッタを使う。
Bevy 0.9
fn xxx( state: Res<State<GameState>> )
{ let current = state.current();
if *current == GameState::GameOver { … }
}
Bevy 0.10
fn xxx( state: Res<State<GameState>> )
{ let current = state.0;
if current == GameState::GameOver { … }
}
- 現在の
State
を知るには.0
で値を取り出す。(.current()
はなくなった?)
UI (1)
TextAlignment
VerticalAlign
HorizontalAlign
Text
の定義の変更
Bevy 0.9
pub struct TextAlignment {
pub vertical: VerticalAlign,
pub horizontal: HorizontalAlign,
}
pub enum VerticalAlign {
Top,
Center,
Bottom,
}
pub enum HorizontalAlign {
Left,
Center,
Right,
}
Bevy 0.10
pub enum TextAlignment {
Left,
Center,
Right,
}
-
VerticalAlign
にあたる要素がなくなり、シンプルになった。
Bevy 0.9
pub struct Text {
pub sections: Vec<TextSection, Global>,
pub alignment: TextAlignment,
}
Bevy 0.10
pub struct Text {
pub sections: Vec<TextSection>,
pub alignment: TextAlignment,
pub linebreak_behaviour: BreakLineOn,
}
- 構造体に
linebreak_behaviour
が増えた。とりあえずなら..default()
を使えば良いと思う。
UI (2)
Visibility
の定義の変更
Bevy 0.9
pub struct Visibility {
pub is_visible: bool,
}
Bevy 0.10
pub enum Visibility {
#[default]
Inherited,
Hidden,
Visible,
}
-
XXX.visibility.is_visible
にtrue
false
をセットするのではなく(is_visible
はもう無い)、XXX.visibility
に直接Visibility::Inherited
Visibility::Hidden
をセットする。 -
Inherited
とVisible
の違いは、親子関係の継承の有無。
An entity with
Visibility::Inherited
will inherit the Visibility of its [Parent
].
Note that an entity withVisibility::Visible
will be visible regardless of whether the [Parent
] entity is hidden.
ECS Schedule v3 (3)
.before()
.label()
.after()
による実行順の調整
Bevy 0.9
app
.add_system_set
( SystemSet::on_update( GameState::MainLoop )
.before( Mark::DetectCollisions ) //<before>
.with_system( player::scoring_and_clear_stage ) //スコアリング&クリア判定⇒StageClear
)
.add_system_set
( SystemSet::on_update( GameState::MainLoop )
.label( Mark::DetectCollisions ) //<label>
.with_system( chasers::detect_collisions ) //衝突判定⇒GameOver
)
.add_system_set
( SystemSet::on_update( GameState::MainLoop )
.after( Mark::DetectCollisions ) //<after>
.with_system( player::move_sprite ) //スプライト移動
.with_system( chasers::move_sprite ) //スプライト移動
)
;
Bevy 0.10
app
.add_system
( player::scoring_and_clear_stage //スコアリング&クリア判定⇒StageClear
.before( Mark::DetectCollisions ) //<before>
.in_set( OnUpdate( GameState::MainLoop ) )
)
.add_system
( chasers::detect_collisions //衝突判定⇒GameOver
.in_set( Mark::DetectCollisions ) //<label>
.in_set( OnUpdate( GameState::MainLoop ) )
)
.add_systems
( ( player::move_sprite, //スプライト移動
chasers::move_sprite, //スプライト移動
)
.after( Mark::DetectCollisions ) //<after>
.in_set( OnUpdate( GameState::MainLoop ) )
)
;
-
.label()
が.in_set()
に改名された。ソースコードが読みにくくなった気が…?
ECS Schedule v3 (4)
State
を利用していた場合の注意点
PAUSE処理にBevy 0.9
pub fn pause_with_key
( mut state: ResMut<State<GameState>>,
mut inkey: ResMut<Input<KeyCode>>,
)
{ //入力がないなら関数脱出
if ! inkey.just_pressed( KEY_PAUSE ) { return }
//PAUSEのトグル処理
if state.current().is_pause()
{ let _ = state.pop(); //PAUSEから復帰
}
else
{ let _ = state.push( GameState::Pause ); //PAUSEする
}
//NOTE: https://bevy-cheatbook.github.io/programming/states.html#with-input
inkey.reset( KEY_PAUSE );
}
Bevy 0.10
pub fn pause_with_key
( mut state: ResMut<State<GameState>>,
mut old_state: Local<GameState>,
mut inkey: ResMut<Input<KeyCode>>,
)
{ //入力がないなら関数脱出
if ! inkey.just_pressed( KEY_PAUSE ) { return }
//PAUSEのトグル処理
if state.0.is_pause()
{ state.0 = *old_state; //PAUSEから復帰
}
else
{ *old_state = state.0;
state.0 = GameState::Pause; //PAUSEする
}
//NOTE: https://bevy-cheatbook.github.io/programming/states.html#with-input
inkey.reset( KEY_PAUSE );
}
-
.push()
.pop()
は無くなった。(State
の実装が簡素化されキュー処理しなくなった) -
ResMut<NextState<GameState>>
を使わない。理由はPAUSEからの復帰時に.in_schedule( OnEnter( … ) )
の処理が実行されて都合が悪いため。(元から同処理が無いなら気にならないかも) -
ResMut<State<GameState>>
の設定値を直接操作する(state.0 = GameState::Pause;
のように)。 - PAUSEからの復帰元を保存するには
Local<GameState>
が便利。
外部crateをコメントアウトした状態で、bevyのmaster branchを使い自作ピコゲーのコンパイルを通した。
コメントアウトしたcrateは音関係だからピコ音が鳴らないけど、WASMでも動いたし一段落。
後はbevyのv0.10の正式リリース(3/4?)を待って更新しよう。
0.10のリリース前だけど一点。
ECS Schedule v3 (5)
.chain()
の利用
Bevy 0.10 .before()、.after()を使った場合
app
.add_system
( init_demoplay_record //demoでのrecordの初期化
.before( Mark::MakeMapNewData )
.in_schedule( OnEnter( GameState::TitleDemo ) )
)
.add_system
( map::make_new_data //新マップのデータ作成
.in_set( Mark::MakeMapNewData )
.in_schedule( OnEnter( GameState::TitleDemo ) )
)
.add_systems
( ( map::spawn_sprite, //スプライトをspawnする
player::spawn_sprite, //スプライトをspawnする
chasers::spawn_sprite, //スプライトをspawnする
)
.after( Mark::MakeMapNewData )
.in_schedule( OnEnter( GameState::TitleDemo ) )
);
Bevy 0.10 .chain()を使った場合
app
.add_systems
( ( init_demoplay_record, //demoでのrecordの初期化
map::make_new_data.in_set( Mark::MakeMapNewData ), //新マップのデータ作成
map::spawn_sprite, //スプライトをspawnする
player::spawn_sprite, //スプライトをspawnする
chasers::spawn_sprite, //スプライトをspawnする
)
.chain()
.in_schedule( OnEnter( GameState::TitleDemo ) )
);
- 単純に
.before()
→ラベル(.in_set()
)→.after()
の順番をまとめるなら、.chain()
が便利。 - 上の例で
.chain()
利用時に.in_set()
を残したが、ソースコードの他の場所でこのラベルを目印に関数を追加するような使い方をしないのであれば、削除してよい。
このスクラップは2023/03/21にクローズされました