Bevyで始めるゲーム開発

# はじめに

この記事は

- Rustでゲーム開発をしてみたい
- UnityやUnrialEngineとは違うゲームエンジンに触れてみたい
- マイナーなものが好き
- 逆張りしたい

という方に向けて書いています。

## Bevyとは

**Bevy**とは、Rust製のデータ駆動型ゲームエンジンの一つです。特徴として、

- オープンソースである。
- [ECS](https://ja.wikipedia.org/wiki/%E3%82%A8%E3%83%B3%E3%83%86%E3%82%A3%E3%83%86%E3%82%A3%E3%83%BB%E3%82%B3%E3%83%B3%E3%83%9D%E3%83%BC%E3%83%8D%E3%83%B3%E3%83%88%E3%83%BB%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0)(Entity component system)を採用している。公式ではBevyECSと言っている。

などがあります。詳しくは[Bevyの公式サイト](https://bevyengine.org/)で。

## Bevyの導入

Bevyを導入するのはとても簡単です。その前に新しいプロジェクトを作成しましょう。

:::note warn
ここではRustのインストール済みであるとして進めます。
Rustを導入してない方はR[ustの公式サイト](https://www.rust-lang.org/ja/)でインストールしてください。
:::

では、プロジェクトを作成してBevyを導入しましょう。ここでは`Hello_bevy`としてプロジェクトを作成します。
```
cargo new Hello_bevy
cd hello_bevy
```

お手元のエディタで`./cargo.toml`ファイルを開いて以下を追加してください。

```
[dependencies]
bevy = "0.6"
```

次に最初のプログラムとして`main.rs`を変更します。
```rs
use bevy::prelude::*;

fn main() {
   App::new().add_system(hello_world_system).run();
}

fn hello_world_system() {
   println!("hello world");
}
```

ここまで完了したらコンソールで`cargo run`しましょう。すると、
```
Hello World
```
と出力されます。ですが、このプログラムではコンソールに`Hello World`と出力しているだけです。
「ゲームエンジンなんだから画面に描画しろよ」と言いたげですね。それは次章で行います。

## 画面の描画

まっさらでもなんでもいいからゲーム画面を描画したい。それは簡単にできます。
`main`内を以下のコードに書き換えて`cargo run`してください。

```rs
App::new()
    .add_plugins(DefaultPlugins)]
    .add_system(hello_world_system)
    .run();
```
するとまっさらな画面が現れたと思います。こんな感じで
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414005/b52f8466-4a71-6b7f-561c-b0d31d2a01a5.png" width="50%">
次に背景色を変更してみましょう。`App`に`.insert_resource(ClearColor(Color::rgb(0.69, 0.77, 0.87)))`を追加します。

```rs
App::new()
    .insert_resource(ClearColor(Color::rgb(0.69, 0.77, 0.87)))
    .add_plugins(DefaultPlugins)
    .add_system(hello_world_system)
    .run();
```
`cargo run`してどう変化したのか確かめてみましょう。

## フォントの導入

早速`Hello World`の描画を行いたいところですが、Bevyには標準でフォントが用意されていません。なのでフォントを用意する必要があります。追加するフォントはなんでもよいです。ですが、ここでは[Google Fonts](https://fonts.google.com/)でダウンロードできる[Noto Sans Japanese]((https://fonts.google.com/noto/specimen/Noto+Sans+JP))を使用します。

ダウンロードが終わったらダウンロードしたフォルダを解凍して`hello_bevy/`下に`assets`ディレクトリを作成してその中にフォントデータを格納してください。フォルダ構造は以下のようになります。

```
hello_bevy
└─── assets
│   │   NotoSansJP-Medium.otf
│
└─── src
│   │   main.rs
│
...
```
これで`Hello World`の描画に必要な素材は集まりました。

## Hello World

### 最小限のHello World

それでは`Hello World`を描画してみましょう。`hello_world_system`を以下のように変更します。
`Commands`はEntity Component（文字や画像などのオブジェクト？）を生成するためのもの
`AssetServer`は画像や音声、フォントなどを読み込むためのものと思ってください。
その程度の理解でいいのか？って大丈夫です。いずれわかります。

```rs
fn hello_world_system(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn_bundle(UiCameraBundle::default());

    commands.spawn_bundle(TextBundle {
        text: Text::with_section(
            "Hello World",
            TextStyle {
                font: asset_server.load("NotoSansJP-Medium.otf"),
                font_size: 100.0,
                ..Default::default()
            },
            TextAlignment::default(),
        ),
        ..Default::default()
    });
}
```

`cargo run`して確かめてみましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414005/71681949-a6f9-6581-328f-6dff1a940451.png" width="50%">

`Hello World`が左下に表示されていると思います。
それにしてもこれではしっくりきませんね。`Hello World`を中央に寄せてみましょう。

### 中央寄せ

いろいろ試してみましたがBevyで中央寄せを行うには親要素を追加するのがいいみたいです。むしろこの方法でしか出来なかった。
ということで親要素として`NodeBundle`を追加しました。これは**HTML**でいう`<div>`タグみたいなものと思って良いと思います。
`with_children`で子要素を作成します。


```rs
fn hello_world_system(mut commands: Commands, asset_server: Res<AssetServer>) {
    commands.spawn_bundle(UiCameraBundle::default());

    commands
        .spawn_bundle(NodeBundle {
            style: Style {
                size: Size::new(Val::Percent(100.0), Val::Percent(100.0)),
                align_items: AlignItems::Center,
                justify_content: JustifyContent::Center,
                ..Default::default()
            },
            color: Color::ORANGE.into(),
            ..Default::default()
        })
        .with_children(|parent| {
            parent.spawn_bundle(TextBundle {
                text: Text::with_section(
                    "Hello Bevy",
                    TextStyle {
                        font: asset_server.load("NotoSansJP-Medium.otf"),
                        font_size: 100.0,
                        color: Color::WHITE,
                        ..Default::default()
                    },
                    TextAlignment::default(),
                ),
                ..Default::default()
            });
        });
}
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/414005/f1c2174e-5441-1d7b-471e-9cbe317ae0a1.png" width="50%">

# 最後に
Bevyはサンプルプログラムが充実しています。気になった方は[BevyのGithub](https://github.com/bevyengine/bevy)からコードをクローンして実行してみてください。