Phaser.jsとfirebaseでドラクエ風バトルゲームを作ってみた。

# はじめに
仕事も落ち着き、古いGigazinのゲームカテゴリを読み漁っていたら、
名前を入れると召喚されたドラクエ風モンスターが戦う「さくさくモンスターバトル」

https://gigazine.net/news/20080729_sakusaku_battle/

の記事を発見。
自分でも作れるのでは？と思いつくってみました。

# 仕様
残念なことに、さくさくモンスターバトルはもう閉鎖されており、実際触ってどんなことができるかはネットの記事を読んで想像するしかありません...

けど、初見で感じたシンプルさ

- 名前を入れてモンスター作成
- 名前によってステータスが変わる
- モンスター通しを戦わせる
- 勝ったモンスターはサーバーに登録される

まずはこの仕様でつくってみようと思います。

# 出来上がったもの
https://monster-battle-54e78.firebaseapp.com/

firebase Hostingに置いています。

![68747470733a2f2f71696974612d696d6167652d73746f72652e73332e61702d6e6f727468656173742d312e616d617a6f6e6177732e636f6d2f302f3536313134352f35653861653533362d303539302d303865372d303931372d3734316131613232613631312e6a706567.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561145/d02bcbd5-a2c9-5c3c-39c9-14d65621139f.png)


![gameImage2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561145/e848e7c5-0d4d-4ff3-2e34-b8349a6700bf.jpeg)

名前は「モンスターバトル」としました。
せっかく作ったモンスター画像を見返したかったので図鑑も追加しました。
初めはGB版ドラクエモンスターズの画像を使っていたのですが、流石にまずそうだったのでパロディしたモンスターにしました。合計50匹作成しています。
ロゴもパロディ...インスパイア系で作っています。

2021.6.6 追記
他言語化（英語のみ）をしてみました。

https://qiita.com/saitotsushin/items/db48a29cebc4d57e086b

# 追加要素
- twitterアカウントでのログイン機能
- ログインすると直近１匹のモンスターの保存と図鑑が使用できる
- ランダムでモンスターと対戦できる闘技場

# ツールなど
![monster-battle-ツール.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561145/4483ebe7-cada-c7b2-f6bb-33853fef3cca.png)

アーキテクチャー図を描いてみたかったのですが、何で作ったらいいかわからなかったので（draw.ioとかがいいのでしょうか？）、とりあえず、使ったツールを描いてみました。

振り返ってみると色々使ってることと、並べるとそれっぽく見えて優秀な人に見えるなぁと、初学物としての感想です。

## ゲーム部分
ゲームエンジンはPhaser.jsを使用しています。Javascript製のゲームエンジンライブラリは数多くありますが、

- サンプルが豊富なので大体サンプルを見れば、できるできないが想像できる。
- 人気があるゲームエンジンライブラリみたいなので困ったら質問できそう。
- ベースがPixi.jsなのでPixi.jsでも検索できそう。

といったところです。

サンプル集

https://docs.tony93.top/phaser3-examples/public/index.html?dir=display/tint/&q=

豊富なのですが、やはり初学者にはゲーム作り自体が難しいです。ヒットボックス？オブジェクトプール？などゲーム特有のアルゴリズムだったり考え方だったり、webアプリケーションとは違ったアプローチが多い！

アルゴリズムだったりはゲームエンジンに関係なく調べられるのですが、いざ実装するとなると戸惑います。
ここはgoogle検索で「Phaser.js How Make ~~」みたいな感じで調べていました。
使用しているユーザー数が多いのでPhaser.jsを選びましたが、母数が多いというのはいいことで、自分と同じところでつまづいている人を見つけることができるので、わりとすぐ解決方法にたどり着きます。

# 制作期間
約１ヶ月
合計100時間は使った気がします。
そのうちモンスターだったりの素材作りが20時間以上使っているような...

当初３日くらいを想定していたのですが、やはり想定の10倍はかかることを痛感しました。
先人の言葉は信じるものです。

# まずは作ってみたかった
正直なところwebpackもnode.jsもよくわかっていないです。
開発環境を整える（動かすまで）でつまずくのが僕のセオリーだったのですが、
phaser.jsのwebpackの設定＆サンプルゲームを配布している人がいた＆出会えたことはラッキーでした。

https://github.com/nkholski/phaser3-es6-webpack

# スプライト画像
モンスター画像やタイトル画像など一枚ずつ読み込むのでは通信回数が増えるため一枚の画像にまとめる方法としてスプライトシート化があります。
調べると「TexturePacke」を使おう！と出てきますが、有料です...

https://www.codeandweb.com/texturepacker

調べているうちに無料のwebサービスを発見。
Leshy SpriteSheet Tool

https://www.leshylabs.com/apps/sstool/

アニメーション用：JSON-TP-Array
それ以外：JSON-TP-Hash
でjsonを書き出すと良いです。

## 素材探し
無料で素材を提供しているサイト

ぴぽや倉庫

https://pipoya.net/sozai/

Denzi日記

http://www3.wind.ne.jp/DENZI/diary/

を利用しようとしたのですが、実装してみたらしっくり来ず、自分で書くことにしました。

![image-monster.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561145/57e3fbbf-138f-f0e4-9b2d-bec71c772651.jpeg)

ドット絵なので簡単だろうと思い始めましたが、難しい...!
鳥山明先生の天才的なデフォルメがあり、それをドット（50x50ピクセル）におさめるセンス...

イラストはざっくりと描いて、ドットで細か所は削ったりと一人でやると自由にできますね。

![monsters.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561145/512a2abc-6e54-4e61-5e73-0933a2f31b78.jpeg)


# FireStore
コレクションは
・chanpions
・users

chanpionsは「チャンピオンにいどむ」で使用。
勝てば取得したchanpionsのドキュメントにランキング（rank）を持たせて管理。

```
this.db.collection("chanpions")
  .limit(5)
  .orderBy("rank","asc")
  .get().then((querySnapshot) => {
    ~~
  })
  .catch((error) => {
  ~~
});
```

usersは図鑑と作成したモンスターの管理。
TwitterログインをFirebase Authenticationでチェック後にuserIdをkeyにユーザーのデータを参照する。
Firebaseでユーザーごとの登録データはどう管理するのか、結構調べたのだが、
Firebase AuthenticationでUIDが振られるので、ドキュメントを登録する際にUIDで登録するのがいいらしい。なるほど。

![monster-battle_-_Cloud_Firestore_-_Firebase_コンソール-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/561145/57589131-1e16-4bbd-cb54-d39a04559a70.png)

# 感想
Phaser.js、Firebase、GitHub、Sourcetree、Leshy SpriteSheet Tool...
全て無料or無料枠があり実質0円で作り始められるなんて...

ゲーム部分ついてはモンスターのアップデートだったり、育成機能など付けてみたりとバージョン管理もしてみたいです。