# Bevy
Bevy (0.7) を、非公式ブックを参照して学習したときのメモ。
基本的に 非公式ブック (opens new window) を使用して学習したことを記録する。
# 目的
Rustに入門したが、まだいまいち使えていない感じがするため、 複雑(であろう)ゲームプログラミングを題材に、 アプリケーションソフトウェアの設計・実装を経験したい。 Rustを公式ブックや市販の入門書を読んだ後、 AIZU ONLINE JUDGE の ADSL1 をやってみたり、 paiza の過去に説いた問題を Rust で解いてみたりした。 CUI上の単発コマンド的なアプリケーション実装方法は見えたが、 その他の領域での(例えばGUIアプリケーションの)実装はどのようなものか、 いまいち見えてこない。 Rustは "オブジェクトの海" に否定的な認識だが、それが使えない状況下で GUIアプリケーション等インタラクティブなソフトウェアをどのように実装するのか、 知りたい。
# 環境
WSL2 上のUbuntu 20.04 上で開発する。 ターゲットはまず Webassembly、つぎに Windows。
WSL2 上にはすでに rustup が入っている。
# 構築
非公式ブックのここ (opens new window) に詳しい。
rustup で Wasm32 をターゲットを追加する。
$ rustup target add wasm32-unknown-unknown
とりあえずの実行環境として "wasm-server-runner" を入れる。
$ cargo install wasm-server-runner
プロジェクトを作成。
$ cargo init --bin hello_bevy
$ cd hello_bevy
Cargo.toml を編集する。
- bevy 0.7 を dependencies に追加
- (option) 最適化オプションの調整 (opens new window)
[package]↲
name = "hello_bevy"↲
version = "0.1.0"↲
edition = "2021"↲
↲
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/man ifest.html↲
↲
[dependencies]↲
bevy = "0.7"↲
↲
↲
[profile.dev]↲
opt-level=1↲
↲
[profile.dev.package."*"]↲
opt-level=3↲
.cargo/config を作成し、 run
時に "wasm-server-runner" を使用するよう設定する。
[target.wasm32-unknown-unknown]↲
runner = "wasm-server-runner"↲
src/main.rs の内容を編集する。
use bevy::prelude::*;↲
↲
fn main() {↲
App::new()↲
.add_plugins(DefaultPlugins)↲
.run();↲
}↲
ビルド時は target を指定する。初回のビルドはなかなか時間がかかる。
$ cargo run --release --target wasm32-unknown-unknown
表示されたURLへアクセスすると灰色の画面がでる。
# 未整理メモ
# 非公式ブックのNew to Bevy? Guided Tutorial! (opens new window) 読み下し
Bevy フレームワーク基本構成
- ECS : Entity-Component-System。Bevyはアプリケーションのデータを Bevy ECS にて管理する。これは一種のDBMSと考えてよい(はず)。DBの基本構成要素が Entity と Component である。
- Entity : Bevy上のなにかを表現するモノ。その実態は単純なID。後述のComponentを関連付けることができる。RDBでいえば組(タプル)、表でいえば行の立ち位置。
- Component : Entityに関連付けるデータ。任意のRust型がComponentの型として定義できる。RDBでいえば属性(アトリビュート)、表でいえば列の立ち位置。
- Resource : 単一のグローバルなデータ。Entityと関連しない。
- System : Bevyが実行する関数。まさにシステム(の一部)を実現する。引数は特殊なルールに従う必要がある。指定可能な引数は Query(を通してComponent/Entity)・Resource・Command・Event。これらの相互作用を記述することができる。AppBundlerによりBevyに登録し、Bevyが実行する。
- Query : Systemの引数として、参照したい Entityの Component を記述するモノ。
- Command : ECS へのコマンド。Entity/Component・Resourceを生成・削除含め操作する。
- Event : イベントの実装。システム間のデータフローに使う。
- AppBundler : アプリビルダ。いわゆるビルダーパターンでアプリケーションを構築する。
# 背景色
Resource ClearColor
により背景色変更。
App::new()↲
.insert_resource(ClearColor(Color::rgb(0.2, 0.8, 0.2)))↲
.add_plugins(DefaultPlugins)↲
.run();↲
# デバッグツール追加 bevy_editor_pls (opens new window)
crate.io に登録されてなさそうなので、GitHubリポジトリを直接参照。
Cargo.toml [dependencies]
に以下追加。
bevy_editor_pls = { git = "https://github.com/jakobhellermann/bevy_editor_pls.git" }
プラグイン EditorPlugin
を追加。
use bevy::prelude::*;
use bevy_editor_pls::prelude::*;
fn main() {
App::new()
.insert_resource(ClearColor(Color::rgb(0.2, 0.8, 0.2)))
.add_plugins(DefaultPlugins)
.add_plugin(EditorPlugin)
.run();
}
# Bevy Lint (opens new window)
Bevy コードに対する lint らしい。
インストール手順 (opens new window) に従いインストール。
cargo install cargo-dylint dylint-link
openssl-sys v0.9.73
のインストールに失敗していたので、エラーメッセージに従い、
libssl-dev
と pkg-config
をインストール( apt install
)。
コマンド実行時にもエラーがあったので、
libasound2-dev
libudev-dev
# Examples (opens new window) を動かしてみる。
下記2個をコピペして動かしてみる。
2Dの矩形を描くサンプル (opens new window) のコード(
fn
setup
周り )をコピペ。スプライトを動かすサンプル (opens new window)
- こちらはアセットファイルを準備する必要あり。
アセットはプロジェクトディレクトリの assets/
下に置くものらしい。
bevy_hello$ mkdir assets
bevy_hello$ cd assets
assets$ wget https://github.com/bevyengine/bevy/raw/latest/assets/branding/icon.png
以下はサンプルを切り貼りして作ったコード。
use bevy::prelude::*;
use bevy_editor_pls::prelude::*;
fn main() {
App::new()
.insert_resource(ClearColor(Color::rgb(0.4, 0.4, 0.8)))
.add_plugins(DefaultPlugins)
.add_plugin(EditorPlugin)
.add_startup_system(setup)
.add_system(sprite_movement)
.run();
}
fn setup(mut commands: Commands,
asset_server: Res<AssetServer>) {
commands.spawn_bundle(OrthographicCameraBundle::new_2d());
commands.spawn_bundle(SpriteBundle {
sprite: Sprite {
color: Color::rgb(0.25, 0.25, 0.25),
custom_size: Some(Vec2::new(50.0, 50.0)),
..default()
},
..default()
});
commands.spawn_bundle(SpriteBundle {
texture: asset_server.load("icon.png"),
transform: Transform::from_xyz(100., 0., 0.),
..default()
})
.insert(Direction::Up);
}
#[derive(Component)]
enum Direction {
Up,
Down,
}
fn sprite_movement(
time: Res<Time>,
mut sprite_position: Query<(&mut Direction, &mut Transform)>) {
for (mut logo, mut transform) in sprite_position.iter_mut() {
match *logo {
Direction::Up => transform.translation.y += 150. * time.delta_seconds(),
Direction::Down => transform.translation.y -= 150. * time.delta_seconds(),
}
if transform.translation.y > 200. {
*logo = Direction::Down;
} else if transform.translation.y < -200. {
*logo = Direction::Up;
} else {
// nothing
}
}
}
# ビルドしたWasmをサーバで動かす
以下参考に・・・ Wasm (opens new window)
環境 にて作成した環境を引継ぎ使用する。以下その手順。
- ビルドして wasm ファイルを作成する
- wasmファイルを実行するための環境を作る
- 今回は
wasm-bindgen-cli
(opens new window) を使用するwasm-bindgen-cli
を使うと、wasmファイルを実行するために必要な js ファイルを作成してくれる wasm-bindgen-cli
の生成したjsを読み込む html を作成する- アセットファイルを配置する
- 今回は
- サーバの静的ファイルとして配置する
# ビルドして wasm ファイルを作成する
ビルド cargo build --target wasm32-unknown-unknown
すると、 target
下に成果物ができる。
プロジェクト名を bevy_hello
にしていると、以下にできている。
target/wasm32-unknown-unknown/debug/bevy_hello.wasm
本来は --release
でビルドし、 target/wasm32-unknown-unknown/release/bevy_hello.wasm
だが、今回はサボって debug
ビルドのものを配置する。
# wasmファイルを実行するための環境を作る
今回は生成物を wasm-bindgen/wasm/
に出力するものとする。
wasm-bindgen-cli
をインストールする。
$ cargo install wasm-bindgen-cli
wasm-bindgen-cli
を実行し、wasm読み込みファイル一式を出力する。
$ wasm-bindgen --out-name hello --out-dir wasm-bindgen/wasm/target --target web target/wasm32-unknown-unknown/debug/bevy_hello.wasm
Example の WASM/Build&Run (opens new window) の
example HTML file (opens new window) をコピーして、 wasm-bindgen/wasm/index.html
に配置し、その中のjs名を修正する。今回は hello.js
に変更する。
<html>
<head>
<meta charset="UTF-8" />
<style>
body {
background: linear-gradient(
135deg,
white 0%,
white 49%,
black 49%,
black 51%,
white 51%,
white 100%
);
background-repeat: repeat;
background-size: 20px 20px;
}
canvas {
background-color: white;
}
</style>
</head>
<script type="module">
import init from './target/hello.js'
init()
</script>
</html>
アセットを使用していれば、 wasm-bindgen/wasm/assets/
配下にアセットファイルをコピーする。
bevy_hello$ cp -r assets wasm-bindgen/wasm/
この時点で wasm-bindgen/
以下は下記のようになっている(はず)。
bevy_hello$ cd wasm-bindgen
wasm-bindgen$ tree
.
└── wasm
├── assets
│ └── icon.png
├── index.html
└── target
├── hello.d.ts
├── hello.js
├── hello_bg.wasm
└── hello_bg.wasm.d.ts
3 directories, 6 files
# サーバの静的ファイルとして配置する
wasm-bindgen/wasm/
以下をサーバの静的ファイルとして丸っとコピーする。
bevy_hello$ cp -r wasm-bindgen/wasm/* <静的ファイル置き場所>
# TODO
- [ ] (nowon) New to Bevy? Guided Tutorial! (opens new window) の読み下し
- [ ] System は Bevy によりどのように実行されるのか
- [ ] Plugin の使い方
- [ ] 便利そうな 3rd Party Plugin