Open10

bevy engineの勉強

アンコウアンコウ

ゲームエンジンのbevyに興味を持ったのでちょっと勉強してみる。rust自体もほぼ初心者で知らないことだらけだが。

アンコウアンコウ

自分のwindowsマシンにrust自体は入っているので、とりあえず最新版にする。

rustup self update
rustup update
アンコウアンコウ

プロジェクトフォルダを作ってbevyをcargoで導入する。

mkdir bevy-test
cd bevy-test
cargo init
cargo add bevy

bevyのバージョンは0.13.2だった。

アンコウアンコウ

vscodeを開く。拡張はrust-analyzerが入っていたが、とりあえずこれだけでいいか。
とりあえずrustが動くかhello worldやってみる。

cargo run

先にbevyを導入したからか色々コンパイルしてる。
ちゃんとHello, world!が表示されたのでOK.

アンコウアンコウ

ここからbevyコードを書いていく。とりあえず公式のQuickStartを見ながらやっていく。

bevy版のHelloWorldから。

use bevy::prelude::*;

fn hello_world() {
    println!("hello bevy!");
}

fn main() {
    App::new()
        .add_systems(Update, hello_world)
        .run();
}

bevyはECSを採用している。add_systemsでシステムを登録していく感じか。Updateスケジュールにhello_world関数を登録しているということかな。Updateは毎フレーム呼ばれるということだろう。
hello bevy!表示されたけど、1回だけなのか。

アンコウアンコウ

コンポーネントを作ってみる。

use bevy::prelude::*;

#[derive(Component)]
struct Person;

#[derive(Component)]
struct Name(String);

fn hello_world() {
    println!("hello bevy!");
}

fn add_people(mut commands: Commands) {
    commands.spawn((Person, Name("アンコウ".to_string())));
    commands.spawn((Person, Name("Ankou".to_string())));
}

fn greet_people(query: Query<&Name, With<Person>>) {
    for name in &query {
        println!("hello {}!", name.0);
    }
}


fn main() {
    App::new()
        .add_systems(Startup, add_people)
        .add_systems(Update, (hello_world, greet_people))
        .run();
}

PersonコンポーネントとNameコンポーネントを作って、add_people関数でこれらのコンポーネントを持ったエンティティを生成している感じかな。commands.spawnでエンティティを生成する。

add_peopleはStartupに登録している。アプリの起動時に呼ばれる。

greet_peopleは登録したエンティティをクエリで検索して名前を出力するシステム。
Query<&Name, With<Person>>この型が大事でこれで何を持ってくるのかが決まる感じ?
この場合、Personコンポーネントを持つエンティティのNameコンポーネントを引っ張ってくるということか。

アンコウアンコウ

データを更新するシステム

fn update_people(mut query: Query<&mut Name, With<Person>>) {
    for mut name in &mut query {
        if name.0 == "アンコウ" {
            name.0 = "チョウチンアンコウ".to_string();
            break;
        }
    }
}

変更する場合はqueryにmutを、変更するコンポーネントも&mutを付ける必要がある。

アンコウアンコウ

bevyはpluginという形で機能を追加していくらしい。
デフォルトプラグインがあって色々便利機能が入っているっぽい。

 App::new()
     .add_plugins(DefaultPlugins)

これで実行するとウィンドウが開いた。DefaultPluginsにウィンドウ関連の機能が入っているということか。
そして、Updateが呼ばれ続けるようになった。

アンコウアンコウ

プラグインの作成

pub struct HelloPlugin;

impl Plugin for HelloPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(Startup, add_people)
            .add_systems(Update, (hello_world, (update_people, greet_people).chain()));
    }
}

fn main() {
    App::new()
        .add_plugins((DefaultPlugins, HelloPlugin))
        .run();
}

Pluginトレイトを実装する。buildメソッドにはappが渡ってくるのでこれで機能を追加していくことができるわけか。

アンコウアンコウ

グローバルで唯一のデータとしてリソースがある。

#[derive(Resource)]
struct GreetTimer(Timer);