湯婆婆ランキングをゲーム化 in Rust/WebAssembly

いつのまにか湯婆婆カレンダーに空きがあったのでなんとなく埋めようと思いました．

@torifukukaiou さんに用意していただいた [こちらのランキング](https://qiita.com/torifukukaiou/items/c8361231cdc56e493245) をゲーム化しました。コンテンツはそのままでビューをランキング形式からゲーム形式に変えた感じだと思っています．

![demo](https://raw.github.com/wiki/YushiOMOTE/mcp2/yubaba2dv2.gif)

デモはこちら: https://yushiomote.github.io/mcp2/
(WelGL2 なので一部モバイルブラウザでは動かないかもです．PC 推奨です)

* 湯婆婆 2D プラットフォーマー
* 千尋を操作して敵として出現する湯婆婆たちを倒します
   * `A`, `D` で左右移動、`W` でジャンプ、`J` で攻撃
   * 先にクリックしてフォーカス合せる必要あるかもです
* 湯婆婆 1 体はこちらのランキングの 1 記事に対応している
   * 記事の湯婆婆が具現化して襲ってくるイメージ
* 湯婆婆の HP は `LGTM の数 + 1`

クオリティ低いです。当たり判定ガバガバです．ジャンプ力以上の深い窪みがあって出れなくなる場所があります。湯婆婆多すぎて多分誰もクリアできないと思っています。160件くらいランキングにエントリしているので 160 体の湯婆婆が spawn しています．全ての湯婆婆の spawn 位置を確認できていません。湯婆婆が場外になってしまっているなどありましたら謹んで対応します。

コードがこちらに公開してあります。 https://github.com/YushiOMOTE/mcp2

# 実装の概要

正月に Bevy という Rust のゲームエンジンで遊んでいる頃に湯婆婆カレンダーの空きを発見して、ちょうどよいのでアセットをこしらえてゲームにしました。

## Bevy とは

Rust 製のよさげなゲームエンジンです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218662/74663967-3541-9da9-8303-c54e449fcaf4.png)

https://github.com/bevyengine/bevy

Web ブラウザ (WASM)、Android、iOS など色々なプラットフォームに対応しています。最近 0.4 になって WASM でのレンダリングに対応しました。筆者の環境は WSL2 で GUI を用意してなくて、最初から WASM 一択で試していましたがやりたいことできてます。

Bevy は Unity などで採用されている ECS (Entity Component System) という設計を使っててオブジェクト指向よりもさらに柔軟で多様なゲームオブジェクトを表現しやすくなっています。オブジェクト指向に比べて ECS と Rust は相性が良いように思いました。Rust は複雑な包含関係を持つと mutability 管理がネックになるので。Bevy の ECS は [Amethyst](https://github.com/amethyst/amethyst) など他の Rust ゲームエンジンの ECS よりも boilerplate が少ない印象を受けました。

Bevy では ECS 、グラフィックバックエンド、アセット管理などの様々な機能に対して Plugin が実装でき非常に拡張しやすい構造になっています。結果、[色々な便利 Plugin が用意されています](https://github.com/bevyengine/awesome-bevy#plugins-and-crates)。

ただ Bevy は、まだ絶賛開発中なので刻一刻と変化しているので注意が必要な印象でした。よって Plugin も最新の Bevy 本体に対応してたりしてなかったりするので注意が必要です。

## 地形の描画

地形の作成には `tiled` というツールを使いました．

https://www.mapeditor.org/

![tiled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218662/eeb4bb36-c790-dfcd-8eb1-bc3b39e6fef8.png)

このツールを使うと GUI で簡単にタイルマップを作成することができます．このエディタの出力するファイル仕様は [オープン](https://doc.mapeditor.org/en/stable/reference/tmx-map-format/) になっていて， Rust でも既存の crate を使って簡単に取り込むことができます．

![CD6A2BAB-C288-4B1F-92A0-C341E4B92714.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218662/f2a43df3-1d2c-1bae-77a9-d3b56b837426.jpeg)

タイル画像はこちらの [Tiny Platform Hill](https://luizmelo.itch.io/tiny-platformer-hills-asset-pack) という素材を使いました．

[bevy_tiled](https://github.com/StarArawn/bevy_tiled) という Plugin を使えば `tiled` が吐くファイルを読み込んでレンダリングまで一気にやってくれそうでしたが、現時点では WASM (wasm32-unknown-unknown) ではすっとは使えなそうでした．

なので，代わりに `tiled` のファイルを事前にパースして必要な情報だけバイナリに組み込んでおいて，実行時に自分で地形を生成するロジックを書きました． [tiled-rs](https://github.com/mattyhall/rs-tiled) という crate を使えば簡単に取り込めます．

## キャラクターの描画

コードしか書けない人間ですが，千尋と湯婆婆とHPゲージと波動拳を MS ペイントで一生懸命ぽちぽちしました。

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218662/b0cb4805-4429-3643-ff30-7198581a71a5.jpeg" alt="chihiro">

(注: 千尋のつもり)

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218662/42869843-0898-23a3-85cc-16b4e4d5f60d.jpeg" alt="yubaba">

(注: 湯婆婆のつもり)

<img width="80%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218662/451734a9-96fe-bb36-362f-078c5ff569f9.jpeg" alt="life">

(注: ハートのつもり)

Bevy ではスプライトアトラス（複数のスプライト画像の集合）をかんたんに取り込む機能もそろっています．

## 物理計算と衝突判定

物理計算には [bevy_rapier](https://github.com/dimforge/bevy_rapier) を使うと良さそうに見えましたが、今回は ECS を試す意味で手で実装しました。単純に重力加速度を毎フレームごとに加算する，壁や地面に接したら速度を殺す程度の処理です．

衝突判定も単純に矩形の重なりを判定しました。

`bevy_rapier` も別途試してみましたが、WASM でも動作していてよい印象を受けました。よりちゃんとした物理計算をしたい場合はつかいたいところです。

## デプロイ

Github Actions でコンパイルして， Github Pages にデプロイしています．

Github Actions で 1) こちらの[湯婆婆ランキングページ](https://qiita.com/torifukukaiou/items/c8361231cdc56e493245)をダウンロード & パースしてアセットの生成， 2) Rust をコンパイル ＆ WASM 化して，3) 生成したアセットもろとも Github Pages にデプロイしています。Github Actions の job を走らせると最新のランキングがゲーム化されます。

# まとめ

趣味で時々 Rust でゲームを作るのですが， Bevy はなかなかよい印象を受けています．ECS を採用していること， 少ない boilerplate， Plugin ベースの豊富な機能．今後の成長を期待しています．

また，何かちょっと試したい時の題材としての湯婆婆の包容力のすごさに驚いています．改めて[オリジナル](https://qiita.com/Nemesis/items/c7192a7c510788d2cba2)と[湯婆婆文化](https://qiita.com/torifukukaiou/items/c8361231cdc56e493245)に感謝です :bow: :bow: