Rustで書かれたゲームエンジンamethyst勉強記#2-2

<< [#2 画像の表示](https://qiita.com/9laceef/items/383ca6525a4125f089eb)

# ご注意！
この記事の内容は2019/06/17現在の最新版amethystクレート(v0.11.0)では仕様が変わっており動きません！随時更新していきますので、しばしお待ちください。
もし更新が待てなかったり直接尋ねたいことなどありましたらコメントにてお願いいたします。

### はじめに

この記事は#2の番外編です。また記事を書いている時期が[#4](https://qiita.com/9laceef/items/04e6221ff62fa3fe1b25)と#5の間なので、書き方がすこし手馴れてきてい（ると思い?）ます。

今回は以前表示させた画像の色をだんだん変化させていこうと思います。
例えば選択肢がいくつか並んでいる中で、選択中のものを[白→赤→白→...]とゆっくり変化させて目立つようにできるかな？と思っています。

サンプルコードは[こちら](https://github.com/glaceef/amethyst-test)。今回は`examples/02-2_colored_image`になります。

## `main.rs`

\#2と比較して、`ColorSystem`とコンポーネントが一つ増えていますね。他は多少名前が変わっているくらいなので、これら2つを解説していきます。

```rust:main.rs
struct ExampleState;

impl SimpleState for ExampleState {
    fn on_start(&mut self, data: StateData<'_, GameData<'_, '_>>) {
        let world = data.world;
        initialise_camera(world);
        initialise_image(world);
    }
}

struct ColorSystem(u32);

impl<'s> System<'s> for ColorSystem {
    type SystemData = WriteStorage<'s, Rgba>;

    fn run(&mut self, mut colors: Self::SystemData) {
        if let Some(ref mut color) = (&mut colors).join().next() {
            let c = 1.0 - (self.0 as f32).to_radians().sin().abs();
            color.1 = c;
            color.2 = c;
        }
        self.0 = if self.0 == 359 { 0 } else { self.0 + 1 };
    }
}

fn main() -> amethyst::Result<()> {
    // amethyst::start_logger(Default::default());

    let config = DisplayConfig::load("./examples/02-2_colored_image/config.ron");
    let pipe = Pipeline::build().with_stage(
        Stage::with_backbuffer()
            .clear_target([0.0, 0.0, 0.0, 1.0], 1.0)
            .with_pass(DrawFlat2D::new().with_transparency(
                ColorMask::all(),
                ALPHA,
                Some(DepthMode::LessEqualWrite),
            )),
    );
    let render_bundle = RenderBundle::new(pipe, Some(config));

    let transform_bundle = TransformBundle::new();

    let game_data = GameDataBuilder::new()
        .with_bundle(render_bundle)?
        .with_bundle(transform_bundle)?
        .with(ColorSystem(0), "color-system", &[]);

    let mut game = Application::new("./examples/02-2_colored_image/", ExampleState, game_data)?;

    game.run();

    Ok(())
}

pub fn initialise_camera(world: &mut World) {
    let mut transform = Transform::default();
        transform.set_xyz(250.0, 250.0, 0.0);
    world
        .create_entity()
        .with(Camera::from(Projection::orthographic(
            -250.0, 250.0, -250.0, 250.0
        )))
        .with(transform)
        .build();
}

fn initialise_image(world: &mut World) {
    let texture_handle = {
        let loader = world.read_resource::<Loader>();
        let texture_storage = world.read_resource::<AssetStorage<Texture>>();
        loader.load(
            "logo.png",
            PngFormat,
            TextureMetadata::srgb_scale(),
            (),
            &texture_storage,
        )
    };

    let mut transform = Transform::default();
        transform.set_xyz(250.0, 250.0, 0.0);
    world
        .create_entity()
        .with(texture_handle)
        .with(Rgba::red()) // new!
        .with(transform)
        .build();
}
```

## `Rgba`コンポーネント

```rust
    world
        .create_entity()
        .with(texture_handle)
        .with(Rgba::RED) // new!
        .with(transform)
        .build();
```

`initialise_image`関数の最後です。`with`が一つ増え、`Rgba`コンポーネントが増えています。これを操作することで画像の色味を変化させることができます。次の`ColorSystem`にて色の変化を行なっています。
ちなみにここの`Rgba::RED`という記述、エディション2018から正式に追加された**関連定数**というものですね。知っていましたか？

## `struct ColorSystem`

```rust
struct ColorSystem(u32);

impl<'s> System<'s> for ColorSystem {
    type SystemData = WriteStorage<'s, Rgba>;

    fn run(&mut self, mut colors: Self::SystemData) {
        if let Some(ref mut color) = (&mut colors).join().next() {
            let c = 1.0 - (self.0 as f32).to_radians().sin().abs();
            color.1 = c;
            color.2 = c;
        }
        self.0 = if self.0 == 359 { 0 } else { self.0 + 1 };
    }
}
```

最低限の処理のみをしています。`Rgba`コンポーネントを操作するために、可変参照ストレージを`SysteData`に指定しています。
与えられているのは先ほどの画像エンティティ１つのみなので、`join()`したあと`next()`で取得しています。`join`で返されるのは不変or可変参照のタプルのイテレータになります。
`Rgba`コンポーネントの型は`(f32, f32, f32, f32)`でそれぞれ`赤,青,緑,透明度`を表すパラメータになっています。4つめの要素をいじれば画像が半透明になります。

今回は短いですが、以上で解説は終了です。
それでは、`cargo run --example 02-2`で実行してみましょう！

### おわりに

以上、番外編でした。
\#2に追加すると長いですし、新しい記事にするにしては内容が少ないですし...。どうしたものかなと悩んでいましたが、このように新しい記事とさせていただきました。
この内容、意外と必要になる気がします。
それでは。