【個人開発】BLACK PINK好きのためのクイズアプリ『BLINK GAMES』を作りました！

## はじめに
今回、個人アプリ『BLINK GAMES』を初めてリリースすることができました！
このアプリは、自分がK-POPアイドルのBLACKPINKがとにかく好きで、周りのBLACKPINK好きの友人も含めて一緒に楽しむことができないか？という考えから作成しました。

開発期間は２ヶ月ほどです。

Qiitaへの投稿も初めてなので至らない点が多々あるかと思いますが
アプリ作成時の、ポイントや苦労した箇所など書いたので読んでいただければ幸いです。

【Twitterアカウント】
https://twitter.com/key60542184

【今回作ったサービス】（**スマホ推奨**）
https://blink-games.app/

https://blink-games.app/

【GitHubアカウント】
https://github.com/y-yanagii/blackpink-test

# アプリ概要
K-POPアイドルの「BLACKPINK」好きのためのクイズゲームアプリです。
他数のモードや難易度でクイズや他のユーザと競うこともできます。

## ログイン〜MODE選択

<img src="https://i.gyazo.com/f5603e011c2ff3aef3a2ff1c91da0195.gif" width="300">

- BATTLE
- TEST
- CHALLENGE
- GAME

Twitter認証でログインしていただき、上記4つから遊びたいモードを選択します。
ゲストでログインしても、ランキングに載らないだけで全てのゲームを遊ぶことができます。

## BATTLE モード
- **1on1**


<img src="https://i.gyazo.com/f7fc1b6778aac56c731cb82dd17f0e07.gif" width="306"> <img src="https://i.gyazo.com/5169a56f265f45e334346cb94f122fc5.gif" width="300">

1on1では、コンピュータと1対1の早押しクイズです。
5問中正解数が多い方が勝ちというルールです。

## TEST モード
- **EASY**
- **NORMAL**
- **HARD**

<img src="https://i.gyazo.com/7d07e8dcfd5083095d942b61609d92cc.gif">
上記３つの難易度の中から選択し、4択クイズを10問解いていくゲームです。
正解数の降順、かつクリアタイムの昇順でランキングが決まります。毎回出題内容が変わります。

- **MUSIC**

<img src="https://i.gyazo.com/744464d5e4fa7db0e0db4beb83dc8f33.gif">
MUSICでは、iTunes APIから視聴データを取得し音源を聴いて曲名を答えるクイズゲームとなっています。

## CHALLENGE モード
- **MASTER**

最高難易度の4択クイズを10問解くゲームです。
こちらも正解数の降順、かつクリアタイムの昇順でランキングが決まります。毎回出題内容が変わります。

- **SUDDENDEATH**

<img src="https://i.gyazo.com/0b4e57b07dd1cec60ebc4dbdb77ad4a4.gif" width="300">　<img src="https://i.gyazo.com/c7c297da6166cf755aedcf788a595679.gif" width="293">

SUDDENDEATHでは、３回間違うまで全問解いていくクイズゲームです。
左上のハートが全て割れるまで続き、問題は全部で170問あります。
ここの問題はEASY〜MASTERを含めた全ての問題がランダムで出題されます。

## GAME モード
- **BUBBLE**

<img src="https://i.gyazo.com/9c42c033feab0755c8c37fa4bea654f7.gif" width="300">　<img src="https://i.gyazo.com/b2be1a86aec0b952c3b70834d3a0e117.gif" width="300">

隣り合う同色の泡を消して得点を稼ぐ落ち物パズルゲームです。
得点の計算は以下となっています。

```
得点　＝　消した泡の数　＊　（消した泡の数　ー　１）
```
よって、一度に消す泡が多いほど高得点になる仕組みとなっております。
消す泡がなくなるまで続き、また画面に表示されている泡を全て消すと+3000のボーナス点が加算されます。
このゲームは切り出して別のアプリにもしたのでロジック部分等は別の記事として書きました。
個人的に泡を押下した時の処理などとても勉強になりました。

https://qiita.com/yyanagisawa555/items/2cc81ee33ca132038aca

- **PUZZLE**

<img src="https://i.gyazo.com/d91634773ea62d009aa63b98e0fd054b.gif" width="300">　<img src="https://i.gyazo.com/27d04d76c96b6a9d7e8d1c6f76039dc4.gif" width="300">

９x９のお馴染みのパズルゲームです。
クリアタイムを競ってランキングが決定します。
このゲームは上のバブルゲームの応用で作成することができました。

## その他

- **結果画面**

得点やランキング、勝敗などに応じてカードが表示され、そこからTwitterシェアや公式のSNSへ飛ぶこともできます。
また、答え合わせのリストや、さらに詳しくBLACKPINKを知りたい方への導線としてYoutube動画も埋め込んでいます。
<img src="https://i.gyazo.com/0c09bbe605d88e54c8fd5ecd45aee269.png" width="300"> <img src="https://i.gyazo.com/2132497724b55842fbff6c7c3b2780e1.gif" width="300">
<img src="https://i.gyazo.com/c275a7b494f4acd3ca3894ff3a876702.gif" width="296"> <img src="https://i.gyazo.com/69ceba4decb3d90220e0548d398658d0.png" width="300">

- **BLINKS**

ユーザ一覧です（BLINKはファンの愛称でその複数形です。）
ここから気になったblinkのTwitterに飛べたりもします。
<img src="https://i.gyazo.com/71befc3454174c17766f650f3d8ae809.png" width="300">

- **MY PROFILE**

プロフィール画面では、ユーザ情報を公開するか否かのステータスを変更できます。ステータスがprivateの場合は、
ランキングにも「???」で名前が乗る仕組みで、ここからログアウトも可能です。
また、それぞれモードごとのRankingを一目でわかるよう表示しています。
<img src="https://i.gyazo.com/0b13e4ebb5d23263f3e0b4d1de53a488.png" width="300">

- **RANKING**

モードごとのランキング画面です。順位をそれぞれ閲覧できます。
ここから気になったblinkのTwitterに飛べたりもします。
また、privateモードユーザの場合は「???」で表示されます。
<img src="https://i.gyazo.com/6d0dd20dc592cfe5976ea78b6a6dc769.gif" width="300">

- **メニュー表示**

<img src="https://i.gyazo.com/5c97e0c6506cc85860e058eb35175a01.png" width="300">

アイコンとラベルをつけることで一目で何を表示するのかをわかりやすくしました。

# 使用技術

- Vue.js 2.6.12
- Nuxt.js 2.15.4
- Firebase　9.12.0
  - FireStore
  - Firebase Cloud Functions
  - Firebase Authentication(Twitter)
  - Firebase Hosting
  - Emulatorツール(開発環境)
- 外部API
  - YouTube Player API
  - iTunes API
- スクレイピング
  - Puppeteer 9.1.1

# こだわったところ、苦労したところ
### 入力を無くし負担をなるべく排除
今回作成したアプリは、自分や同じ趣味を持つ友人たちに一番に使ってもらいたかったので、友人に何回もフィードバックをもらいながら進めました。
その結果、リアルなユーザの声を元に実装を行うことができたので「本当に必要なものはなにか？」を最後まで意識できたと思います。

### デザイン面
モバイルファーストだったということもあり、限られた大きさだったので
**目立たせたくない物に意識を置いて**、無駄な要素をとにかく除外し必要最低限の情報のみを選定し
**空間**を作るよう心がけました。
そうすることで、**目線が必然的にみて欲しいところへ動きユーザが迷いづらい見た目に近づけることができました。**

### 問題の作成を自動化し運用も考慮
問題や選択値の情報をFirestoreのtestsコレクションという名前で持たせているのですが、問題を増やすたびFirebaseのコンソールから手作業で、ドキュメントを型から生成するのは絶対ミスが起きるので安易に問題を増やせません。
そこで、問題作成用の管理画面を作成しJavaScript側でtestsコレクションのドキュメントと同じ型のオブジェクトを用意し、難易度と問題文、選択値を入力するだけで問題を作成できるよう簡易化しました。
その結果フィールドの型の入力ミスや裏で持たせているフラグ等の初期値を間違うことなく登録できるようになりました。
[![Image from Gyazo](https://i.gyazo.com/4f7c66cc551ac1e5136714cf32c1f34f.gif)](https://gyazo.com/4f7c66cc551ac1e5136714cf32c1f34f)

### Firestoreへの読み取り回数を抑えた実装
ローカル環境で実装途中に突然、Firestoreの1日の読み取り回数が上限数に達してしまい、1日読み取り機能が使用できなくなってしまったことがありました。
原因は問題情報取得時に、全件取得した後にJS側で難易度等でフィルタリングしていたので、問題を解くたび最大読み取り数で問題情報取得してしまっていました。良くないですね、、、
この辺りはFirestore自体が初めてだったので悩みました。結果、ドキュメント毎に連番を持たせ
問題情報取得時に、JS側でランダムに決めた連番リストを渡してそのリストで絞った状態でドキュメントを取得することで解決させました。
また、このタイミングでEmulatorツールを導入し、開発中は全てそちらで読み取りや書き込みを行うことにしました。（遅い）
この辺りはもっとベストな方法がある気がするので引き続き調査します。

### BATTLEモードのCOM操作
BATTLEモード時のCOMの動きは毎回違う動きに（COM側が答える時間や答えた時の正解不正解を1問ずつ変化）させたかったので
まず何秒後に答えるかをランダムで保持させてその時間をsetTimeoutに設定、さらにその解答が正解か不正解かもtrue,falseのランダムで持たせかつ、問題が切り替わるたびにsetTimeoutに時間を設定することで対応しました。
その結果、COMの動作にリアルさを出すことができました。（解答が早かったり、解答を間違えたりが1問ずつランダムに行われる）

<img src="https://i.gyazo.com/2c8877cac53dd22c3854cde9c07f8705.gif" width="300">

### BUBBLEゲームの実装
落ち物パズルゲームをどうしても入れたくて実装イメージが5割程度で走り出してしまいました。。。
実際には消すだけでは無く、隣り合う色の判定、消えた後に落ちてくる泡の計算、縦列が全部消えた時の判定等、考慮しなければならないことがたくさんあり、結果的に実装に丸３日ほど使いました。
苦労はしましたが、ロジックを書いててめちゃくちゃ楽しかったですw
し個人的にとても勉強になりました！詳しい実装は別記事にまとめてみました↓↓！

https://qiita.com/yyanagisawa555/items/2cc81ee33ca132038aca

### 音源データの問題作成の自動化
MUSICテストの問題作成は通常の問題とは違い、音源情報と音源元への埋め込み情報が必要でした。
ここは管理画面では対応しきれなかったので、外部APIの戻り値とスクレイピング（Puppeteer(Node.jsライブラリ)）を使用し問題作成を完全に自動化することができました。
問題登録の自動化の流れとしては以下です。

1. １曲ずつ埋め込みコードと曲名を取得（ここをスクレイピングで取得）
    [![Image from Gyazo](https://i.gyazo.com/43bf01b232ac65c9a84c0520f840fe63.gif)](https://gyazo.com/43bf01b232ac65c9a84c0520f840fe63) 
1. iTunes APIの戻り値と1.で取得した曲名でもって照らし合わせ、一致する曲名でペアを生成
1. 2.でマッチさせた曲名を正解の選択値とし、それとは別で持っている曲名リストから不正解の選択値をセット
1. 曲数分ループ1.~3.をループ
1. 作成したリストをtestsコレクションに合うよう加工し、jsonファイルに書き出し
1. 書き出したjsonファイルを読み込み、Firestoreへimport

### エラーとユーザ登録をSlackへ通知
運用で異変にいち早く気づけるよう通知機能を実装しました。

### フレームワークやWebアプリのバックエンドサービスのキャッチアップ
今回RUNTEQで勉強していた言語ではないものやフレームワークだったり、Firebaseを使った実装だったので公式のチュートリアルやUdemyを活用し、１週間だけキャッチアップの時間にあててから作成を開始しました。
なのでベストな実装があまりできていないことは今後の課題です。

# 今後、改善していきたいところ

1. 1on1でのユーザ同士の早押しクイズの実装（現状、COM対戦のみ）
1. BLACKPINK好きが交流できる場をアプリで作れたらなと思います。
1. Twitter情報のアップデート（現状一度登録してTwitterの情報を更新してもアプリ上登録時のユーザ情報が表示されてしまう）

# 最後に
今後も、自分と関わってくれる周りの人たちを技術でもって幸せに
できるようなエンジニアになれるよう精進いたします。

この記事を最後までご覧くださり本当にありがとうございました！
気になった点はコメントで教えてもらえると嬉しいです！

【Twitterアカウント】
https://twitter.com/key60542184

【今回作ったサービス】（**スマホ推奨**）
https://blink-games.app/

【GitHubアカウント】
https://github.com/y-yanagii/blackpink-test