はじめに
bevy記事2本目です。
今回もECSに関する詳しい内容は記述しません。
あくまで、Bevyの基本的な用語や利用方法について順を追って記録していくのが目的です。
前回: BevyEngine初期設定(0.14)
次回: まだ
作業環境
OS: Windows
cargo: 1.80.1
bevy: 0.14
App
前回このようなコードを書いたがAppの中はどうなっているかを簡単に説明していく。
use bevy::prelude::*;
fn main() {
App::new().run();
}
- World
Entity,Component,Resourceやこれらに関連するメタデータに対する操作を保存している。 - Schedule
登録されたシステムを特定の順序で実行するために必要なデータを保持している。 - runner
Scheduleで登録された内容をいい感じに解釈して実行してくれる。
ユーザー側が操作するのはWorldとScheduleのみなのでこれからEntiry,Component,Resource,Systemの追加方法を確認していく。
Entity、Component、System
- コンポーネントの実装方法
Component
を#[derive()]
に追加することでコンポーネントとして定義することができる。
#[derive(Component)]
struct Person;
#[derive(Component)]
struct Name(String);
- Worldにコンポーネントを追加する方法
Command
を利用してWorld
に追加することができる。
また、spawn
を呼ぶことでEntity
を作成することができる。
fn add_people(mut commands: Commands) {
commands.spawn((Person, Neta("Elaina Proctor".to_string())));
commands.spawn((Person, Neta("Renzo Hume".to_string())));
commands.spawn((Person, Neta("Zayna Nieves".to_string())));
}
- 作成した処理をWorldに追加する方法
add_systems
を利用して処理を追加することができる。
Startup
は処理が実行されるタイミングを指定しておりゲーム起動時に一度だけ実行される。
add_systems
にSystemを追加するとWorldに登録されたEntiryやComponentなどを引数から受け取れるようになる。
今回は引数にCommandsを指定しているで実行時に自動的にCommandsが渡される。
fn main() {
App::new()
.add_systems(Startup, add_people)
.run();
}
add_systems
から指定できるスケジュールの種類はこちらの記事にまとめています。
Query
Query
を利用することで登録したComponentを取得することができる。
With
にPerson
を指定することでPerson
を含むEntity
内のName
を取得できます。
// イミュータブルの場合
fn greet_people(query: Query<&Name, With<Person>>) {
for name in query.iter() {
println!("hello {}!", name.0);
}
}
// ミュータブルの場合
fn update_people(mut query: Query<&mut Name, With<Person>>) {
for mut name in &mut query {
if name.0 == "Elaina Proctor" {
name.0 = "Elaina Hume".to_string();
break; // We don't need to change any other names.
}
}
}
フィルターの種類はこちらの記事にまとめています。
Resource
Resourceは「グローバルで一意な」データを扱うことができる機能です。
経過時間やアセット(サウンド、テクスチャ、メッシュ)などが管理できます。
- リソースの作り方
Resource
を#[derive()]
に追加するだけです。
#[derive(Resource)]
struct HelloTimer(Timer);
- リソースの登録方法
insert_resource
でリソースを登録できます。
fn main() {
App::new()
.insert_resource(HelloTimer(Timer::from_seconds(2.0, TimerMode::Repeating)))
.run();
}
- リソースの受け取り方
Res<>
を使うとイミュータブルの状態で受け取れる。
ResMut<>
を使うとミュータブルの状態で受け取れる。
fn greet_people(time: Res<Time>, mut timer: ResMut<GreetTimer>) {
// タイマーを毎フレーム更新してカウントしたらtrueを返す
if timer.0.tick(time.delta()).just_finished() {
println!("hello");
}
}
Chain
処理A、処理Bの順番で実行したい場合.chain()
を利用する。
以下のコードの場合は(system_a, system_b).chain()
と書くことでsystem_a
、system_b
の順番で実行されるようになる。
hello_world
は順序関係なしにUpdate
が始まったタイミング実行される
fn main() {
App::new()
.add_systems(Startup, startup_system)
.add_systems(Update, (hello_world, (system_a, system_b).chain()))
.run();
}
Plugin
準備された機能を一つ登録するだけで利用できるようにする。
UIを使いたければUIPlugin
、レンダリングをしたければRenderPlugin
を追加すればより複雑なシステムでも簡単に利用できるようになる。
また、DefaultPlugins
を追加することでゲームを開発するうえで必要なシステムを利用することができる。
だた、余計なプラグインも一緒に追加されるてしまいビルド時間や無駄な処理負荷の原因になるため慣れてきたら必要なものだけPluginを設定するようにしたほうが良いかも。
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.run();
}
オリジナルプラグイン
Pluginトレイトを利用することでプラグインとして認識させることができる
pub struct HelloPlugin;
impl Plugin for HelloPlugin {
fn build(&self, app: &mut App) {
// ここにアプリを追加する
}
}
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(HelloPlugin)
.run();
}
さいごに
基本的な使い方はここで終わりです。
次回からは2Dや3Dなどもっとゲームらしい箇所に踏み込んでいこうかと思います。
ここでは説明していない内容をもっと詳しく知りたい場合は以下のサイトがかなり参考になるかもしれません。
利用してみてください。
Example:https://github.com/bevyengine/bevy/tree/latest/examples#examples
ドキュメント:https://docs.rs/bevy/latest/bevy/
アセット:https://bevyengine.org/assets/
チートブック:https://bevy-cheatbook.github.io/
前回: BevyEngine初期設定(0.14)
次回: まだ
スケジュールまとめ: https://qiita.com/komeml/items/43aa6c1cca9789be9666
フィルターまとめ: https://qiita.com/komeml/items/3e6f9e614db9342deb1b