アプリボット社員総会Evokeを支える技術

こんにちは。18新卒の杉浦と大洞です。
アプリボットでは半期に一度、大規模な総会が行われており、総会の2部では毎回社員全員が楽しめるようなコンテンツを用意しています。
この記事では、2018年10月に行われた総会のために作ったコンテンツとそれを実現するにあたって使用した技術について紹介します。

作ったもの

今回の総会では、アプリボットの社員300人以上が同時に参加できるようなクイズアプリを作成しました。
モチーフとして某有名な賞金がもらえるクイズ番組を採用しました。
参加者は手元にあるアプリから順番に出題されるクイズに回答していき、最終的にランキングが発表されるといった形式です。
また、全クイズ中に一度だけ使えるヒントのような機能も2つ実装して、クイズの苦手な人でもより楽しめるようにしました。

技術選定

今回のアプリを実装するにあたって必要な要件としては以下のようなものがありました。

クライアント

  • 各問題の選択肢は2択か4択
  • 演出として文字だけのアプリじゃなくビジュアルでも楽しめるようにしたい

サーバー

  • 手元で任意のタイミングで問題を切り替えられる
  • 参加者全員の回答状況がリアルタイムにわかる

しかし、今回のアプリ開発のメンバーはゲームのクライアントエンジニア3人だけでした。
期間も1ヶ月半ほどしかなかったため、新しくサーバーやネイティブアプリの知識を1から学習し、実装するのは難しそうだったので、今ある技術を用いてどうにか実装する方針で考えました。

クライアント

まず、クライアントについては最終的にUnityで実装することに決めました。

例年の総会ではWebアプリとしてコンテンツを用意するのが主流であったため、先輩方の知見を活かしづらいというデメリットもありましたが、全メンバーが実装をすることが可能であり、複雑なアニメーションや音声を使った演出も用意に行えるためUnityを選定しました。

サーバー

サーバーに関してはメンバー全員があまり知識を持っておらず、まともに双方向リアルタイム通信を実装するのは難しそうでした。
そのため、早いうちに自前で実装することは諦めて、mBasSに頼ることにしました。
Unityで利用できるmBaaSとして、FirebaseとNiftyCloudがありましたが、今回は知見が多そうという理由と先輩におすすめされたという理由でFirebaseを選定しました。

実装

クライアント

今回はUnityで制作しましたが、ネイティブアプリにしたことで考慮すべき点がいくつかあったのでその内容と対処方法を紹介していきたいと思います。

実装方法について

今回は期間が短く、デザインの細かい修正をエンジニアがする工数がありませんでした。
なので、実装の段階でデザイナーがUnityを使ってデザインの配置変更を行えるような設計で実装しました。
UnityのScene上に全てのオブジェクトを配置してデザイナーが配置を変更できるようにし、実行時に必要なオブジェクトのみアクティブになるように管理する実装にしました。
desiner.png

リジョインについて

途中で飲み物を取りに行ったりご飯を食べたりする事を考慮し、どのタイミングでアプリを落としても問題なく動作するよう設計しました。
実装としてはアプリの画面を3シーン10画面に分割し、それぞれの画面が独立した実装になるよう設計しました。
以下がフローの具体例です。

リジョイン時のフロー


まず、上の図のようにアプリ起動時にSetupシーンをはさむことで、起動時に今アプリがどの状態かを判定してからゲームループの各シーンに移ります。

各シーンに遷移したあとのフロー(例としてMainシーン)


各シーンに移ったあと、Setupシーンで取得した現在の進行状況を確認し、表示すべき画面のCanvasをアクティブにし、そのCanvasのSetup完了後ゲームを再開します。

リジョインは配慮すべき事がかなりありましたが、事前に入念にデバッグを行っていたため大きな問題は起こらず、快適にさわれるクオリティを出せました。
また、リジョイン時にログイン情報の入力を省略できるようPlayerPrefsを使用して情報をキャッシュするようにもしました。

複数解像度対応について

今回作成したアプリでは、iPhone,iPhoneX,iPadの三種類の解像度の対応を行いました。

iPhoneのアスペクト比を基準としてCanvasをExpandで設定し、
iPhoneX,iPadで引き延ばす際には上下左右の領域を使用しないようにAnchorの設定はCenterMiddleで統一しました。

アプリの配布について

今回はネイティブアプリなので事前のインストールが必要でした。
300人以上にiOS,Androidの両方が配布でき、費用のかからないサービスはDeploygateのみだったのでDeploygateを使用しました。
Androidのインストールでいくつか不具合があったものの、全体の95%は問題なくインストールできました。

サーバー

今回は、クイズアプリかつリアルタイムに全ユーザーに状況が通知されなければならなかったため、FirebaseのRealTimeDatabaseを使用しました。

RealTimeDatabase

FirebaseのRealTimeDatabaseは公式サイトによると、

NoSQL クラウド データベースでデータの保管と同期を行うことができます。データはすべてのクライアントにわたってリアルタイムで同期され、アプリがオフラインになっても、利用可能な状態を保ちます。

とあるように、リアルタイムに同期可能なデータベースです。

クライアントから直接データベースへの書き込みや読み取りを行うような方法でやり取りを行うため、サーバー側は全く意識することなく実装を行うことができます。
また、データベースの更新通知を全ユーザーにリアルタイムに行うことができるため、今回の要件を満たしていました。

値段も非常に安く、同時接続100までは無料で使用でき、それ以上でも従量課金か月額$25のプランを選択することができます。
今回は、月額$25のプランを選びました。このプランでは、同時接続は100kまで可能になります。
余談ですが、おそらく今回のような参加人数の規模がある程度予想できるような場合は従量課金のプランのほうが安く済んだだろうなと思いました。

APIの実装

今回は、クライアント側とAPI側の実装担当者を分けました。
クライアント部分を実装している人がFirebaseを意識することなく、実装ができるように基本的に必要なAPIは以下のような形式で実装をしました。なお、以下のコードはサンプルであり、このままでは動作しません。

// 更新系
public void UpdateAnswer(string userId, int questionNumber, int answerNumber)
{
    // ここでRealTimeDatabaseへの書き込み処理
    FirebaseDatabase.DefaultInstance.GetReference("sample")
                .SetValueAsync(10);
}

// 読み取り系
public void GetCorrectAnswerCount(Action<int> onLoadedAnswerCount)
{
    // ここでRealTimeDatabaseからの読み取り処理
    FirebaseDatabase.DefaultInstance.GetReference("sample")
        .GetValueAsync()
        .ContinueWith((task) =>
        {
            DataSnapshot snapShot = task.Result;
            onLoadedAnswerCount?.Invoke(snapShot.Value);
        });
}

上記のように、更新系は引数に必要なidと更新したい値をもらうメソッドを作成し、読み取り系は読み取った結果をコールバックで返すことで、クライアント実装者は普通のメソッドを呼び出しているような感覚で実装できるようにしました。

実際には、更新待ちの実装があったり、コールバックによる実装ベースになるのでコードが追いづらくはなりましたが、クライアント側の人は最後までFirebaseがどう使われているかを意識することがなく実装できました。

ドキュメントの整備

当たり前ではあるかもしれませんが、上記のように作成したAPI全てに関して、どのような引数を取るのか、どのような値を返すのかをドキュメントとしてまとめ、クライアントを実装する人に提供しました。

あらかじめドキュメントとしてまとめて渡しておくことによって、クライアント実装者はそれを見て作業をすることができ、なおかつドキュメントに記載されているような動作をしていない場合は報告してもらうことでバグの発見もできたので、大変良かったと思いました。

感想

当日にはいくつかバグによる細かい問題はあったものの、全体の進行が止まるようなこともなく、順調にコンテンツを終えることができました。
今までと違ってネイティブアプリになったことや、特に大きな遅延もなくリアルタイムにクイズが進行できたので、参加者の社員さんからの評判もよく、嬉しかったです。
技術選定に関しても、得意なUnityを選んだことと、サーバーをFirebaseにすべて任せたことはとても良かったので、今後もこのような機会があれば同様に実装したいと思っています。

まとめ

今回は、総会で行ったコンテンツとそれを支える技術について紹介しました。
アプリボットではこのような社員同士で交流をするようなイベントが多く、それらをみんなで盛り上げようという根強い文化があります。
今後も、このような文化を大切に、より盛り上げられるようなコンテンツを作っていきたいと思っています。