3章:運用を見据えて作っておこう

ソーシャルゲームの良いところは、初動で遊んでくれたユーザだけでなく、継続的に遊んでくれたり、半年後から遊んでくれるユーザがいることです。 (悪いところはマスターアップ休暇が無いところです!!古き良き時代はリフレッシュできたのに!)

運用は開発と同じくらい(場合によってはそれ以上に)大切なことです。クライアントエンジニアとしては、リリースして半分、運用して半分、くらいの意識でいたいですね。

プッシュ通知#

一言で言うとどんなもの?

ユーザに対して「イベントが始まるよ」「お得なキャンペーンが!」「友達が呼んでるよ」など、ユーザが通知許可設定していればアプリを起動していないときでもメッセージを送れる機能です。

でも通知が多すぎるとユーザは鬱陶しいと思って通知をオフにしたり、ゲームを消してしまいます。ぎゃふん…

適切なプッシュ通知によってユーザのマインドシェアを維持して、アクティブユーザを保つためにも、このプッシュ通知は気合いを入れていきましょう。

最初はメチャクチャ混乱すると思いますが、プッシュ通知というのは「ローカルプッシュ通知」と「サーバプッシュ通知」という2種類の概念があります。

これの理解や実装が不完全だと何が起きるの?

  • 全体通知しか送れなくて運用施策打てなくて詰む
  • アイテムプレゼントプッシュ通知を想定してなくて運用施策打てなくて詰む

詳しく知りたい人は、この辺の単語でググってほしい

  • Firebase for Unity
  • APNS ,Firebase Cloud Messeging(FCM)
  • Amazon SNS モバイルプッシュ

サーバプッシュ通知#

イベントやキャンペーン開始の通知など、運営側都合の通知を行う際に使用します。 ローカルプッシュ通知と異なり、アプリ起動の有無に関わらず通知の配信が可能なため、基本的にはこちらの通知を使用する認識で問題ないでしょう。

Firebase Cloud Messagingを使うことが多いと思います。

ローカルプッシュ通知#

ソーシャルゲームで実際コレを使う場所は限られます。 なぜなら、 サーバプッシュ通知と異なりアプリの起動中しか通知時間や文言などの設定が出来ないためです。 ですので、基本的にはスタミナ回復通知や放置ゲーム要素の達成通知など、ユーザの操作に基づく通知などに使用します。

ローカルプッシュ通知には、端末の時間変更の影響を受けてしまったり、しばらくアプリを起動してくれていないユーザに通知出来ないなど、制約や注意点があります。 そのため、使いどころが大変難しいのですが、上手に使用するとサーバ側の負荷軽減にも繋がりますので、上手く使い分けていけるとよいですね。

ローカルプッシュ通知はUnity公式パッケージがありますので、これを使用することが多いと思われます。 https://docs.unity3d.com/Packages/com.unity.mobile.notifications@1.0/manual/

FirebaseCloudMessaging(FCM)#

事実上のデファクトスタンダードなプッシュ通知SDKです。GooglePlayStoreとAppStoreを対象にするならこれが多いです。(Xiaomiストアとか中国を視野に入れるとまた事情が変わってきます)
GooglePlayStoreはFCMしか選択肢が無い(他のSDKも、内部で結局このSDKを叩いている)です。

AppStoreの場合はAPNSがデフォルトのプッシュ通知システムで、FCMはiOS向けにAPNSをラップして居る。という状況です。 正直なところプッシュ通知はユーザ数が増えたり、一斉送信するときに、思わぬハマりポイントがあるので、有識者に相談する事をオススメします。

そしてこのドキュメントを読んでいるあなたも、遊んでいるソーシャルゲームで、いかにも誤送信っぽい一斉送信なテストのプッシュ通知を見ることがあるかもしれません。
見かけたときは、 Twitterに誤送信プッシュ通知スクショをアップして笑いものにするのは止めて くださると助かります。本当に…人に優しくなろう…人は分かり合えますから…

サーバプッシュ通知基盤#

ゲームのユーザ全体にプッシュ通知を送る、というのを頻繁に行っていると、プッシュ通知をオフにされてします。

そのため、必要なユーザに、必要な事だけを通知する、という気持ちで設計する必要があります。これを行うために必要なのがサーバプッシュ通知基盤です。 社内に既にあれば安心ですし、無い場合はFirebase Analysticsと組み合わせたユーザ属性のフィルタ、ログイン頻度ベースのフィルタ、ゲーム固有のレベルベースのフィルタなどを駆使して、必要な事だけをプッシュ通知で送っていきましょう。

マスターデータダウンロード#

一言で言うとどんなもの?

マスターデータは、「どのようなキャラクターがいるか?」「ステージはどういうステージがあるか?」などと言った設定データになります。 TextureやModelのようなリソースデータと違い、Excelの表で管理で出来るようなデータと考えるとしっくりくると思います。

「〇〇っていう敵が強すぎ、修正!」「説明文が誤字ってた、こっそり直したい!」みたいな時に効果を発揮します。

具体的には?

例えばステージの情報であれば、下記のようなデータを1ステージごとに持つ形になります。

  • ステージ固有のID
  • どのステージIDをクリア後に解禁されるのか?
  • 出てくる敵の配置情報や、敵自体の設定情報などです。

このデータさえあればステージを新たに追加できるようにする事が出来るというものです。

他にもキャラクターであれば、下記のようなデータを1キャラクターごとに持ちます

  • キャラクターを示すID
  • キャラクターのHP、攻撃力などのパラメーター
  • キャラクターの成長曲線
  • レア度
  • 強化で素材にしたときの経験値
  • 表示するときのモデルファイル名、一枚絵のTextureファイル名  (これは別途ダウンロードしたリソースデータを読みこむために使用します)

こういったキャラクターや、ステージの一覧をJSON等の形でサーバーから受け取って、その情報を元にUIの構築・処理していくことで、ステージやキャラクターの追加を行っています。 他にもガチャの抽選テーブルであったり、イベントに関する設定項目で合ったり、ログインボーナスの設定だったりといったものもマスターデータになります。

データはどこにある?

マスターデータはサーバー側にとっても必要な情報になってくることが多いです。 例えばステージに入ってプレイを開始する前に行われる通信で、「そのプレイヤーは本当にそのステージをプレイできる状況にあるか?」などをチェックしたりする際には、その情報が必要だからです。 他にもキャラクターを強化する際に、「指定されたキャラクターを素材にすると経験値がいくつ入るはずなのか?」と言ったことをサーバー側でも把握しておく必要があるからです。

そのため、マスターデータはDBサーバー(データベースサーバー)上に配置して、サーバーサイドのプログラムからアクセスできる形で置く事が多くなってきます。 そして、クライアント側のアプリケーションは、APIサーバーと呼ばれるサーバープログラムとの通信を通じて、データを取得していくという流れになってきます。

データ取得タイミング?

主にログイン時に様々なマスターデータをダウンロードすると言った作りになっている事が多いです。 ただ、一括で全てを行うのではなく、必要な粒度に分けてデータを都度ダウンロードするようになっています。

分かりやすい例では、ステージデータについてです。ステージに入ってプレイする時にはどんな敵がどういう配置で出現するのかが必要です。 しかし、ステージセレクト画面にはその情報が必要ないので、ログイン時の通信ではステージの詳細情報についてはダウンロードしません。 ステージに入るときにスタミナを消費する通信あるので、その時に合わせてステージの詳細の設定データをAPIサーバーを経由してもらう事が出来ます。

対してキャラクター情報のようなどこでも参照されうるようなデータについては、ログイン時に全て渡しておくと言った形を取ります。

クイズRPGのようなゲームを作った時は、このつくりは最大限効果が発揮されます。 ステージプレイの直前の通信で、必要最低限のクイズデータだけを送ると言った実装にします。 このようにする事で膨大なクイズデータを事前にダウンロードしなくてすみます。さらに端末側に送るクイズデータを少なくすることで、データ解析による被害を最小限に抑える事が出来ます。

これの理解や実装が不完全だと何が起きるの?

  • 誤字脱字修正したいだけなのにアプリ審査必須
  • 5MBのマスターデータjsonをパースしようとしてメモリ少ない端末が毎回クラッシュ

詳しく知りたい人は、この辺の単語でググってほしい

Firebase Cloud Firestore#

自社基盤#

エディタ拡張#

アセットバンドル#

これ読んでもらえれば…
https://qiita.com/neon-izm/items/b105130fac060ec40ad4

AddressableAssetSystems(AAS)かAssetBundle(AB)か#

UnityのAssetBundleは、かなり低レイヤーのAPIだけが用意されている状況でした。そのため各社がオレオレAssetBundleManagerを作っている、という状況でした。

それに対してUnity側がある程度の高レイヤーなシステムとしてAddressableAssetSystems(AAS)を提供しました。Unity2018.3以降であれば使うことが出来ます。 AASはABをラップした仕組みですが、触っていくとABの挙動を理解していないと意味不明になることがあるので、一旦ABを覚えておくのが良い気がします。

両者は対立する概念では無く低レベルAPIなのか高レベルAPIなのか、という感じの理解をしておくと良いと思います。 もしプロジェクトにこういった基盤が何も無ければ、おすすめとしてはAASです。あるいはABを使う場合はAutoyaを検討してください。僕のオススメUnityフレームワークです。

AssetBundle用のプロジェクトを分離するか同一運用するか#

AssetBundleのビルドは時間が掛かる上に、リポジトリサイズも肥大化しがちです。
例えばデザイナーさんが「新章のキャラデータを100MBほど追加しました!!」とコミットしたときに、クライアントエンジニアが全員100MBのキャラデータをgit pullしてimportが走ります。

それはちょっと作業効率的に良くないのではないか、ということで「アセットバンドルをビルドしてストレージサーバにアップする」だけの別プロジェクトを作る、と言う運用を行っているソーシャルゲームもあります。

  • メインロジック、UI、アウトゲーム用リポジトリ(ほとんどのクライアントエンジニアはこれを使う)
  • キャラデータや素材を詰め込んでビルドするAssetBundle用(デザイナーやアートの人と協力する人たちはこれも使う)

みたいな運用です。

参加したプロジェクトがこの形式であれば、合わせましょう。

ただし、私見を言うと単一プロジェクト運用がこれからは増えていきそうな予感があります。以下が理由です。

  • 動作確認フローが複雑になりやすい(確認に掛かる作業が複雑になると、面倒くさがって検証が雑になりやすいです)
  • 最新UnityではAssetImporter v2が入ったのでインポート速度は改善傾向にある
  • また、AASでもローカル-リモートのアセットバンドルロード切り替えを備えているけど、単一プロジェクト前提のコードになっている
  • 速いPC、速いCI、十分な回線速度があれば単一プロジェクトにまとめた運用でも意外と回る

機種変引継ぎ対応#

ここまでに何度か「機種変更時の引継ぎ」という言葉が出てきました。あなたも遊んでいたゲームが機種変更時にセーブデータを引継げなくて悲しい思いをしたことがあるかもしれません。

経験上、引継ぎ失敗した時に、サポートにお問い合わせをしてくれるユーザの割合はかなり低いです。無言でゲームから離れていきます。 メチャクチャ悲しいです。
そのため、機種変更引継ぎ部分はしっかり作っておくと、ちょっとしたイベント運用やUI改善よりも離脱率に効いてくる大事なポイントだと思っています。

上記の匿名ログインでゲームを始めたユーザに対して「そろそろメールアドレスとパスワードの登録もしてみませんか?(あるいは引継ぎ情報を登録しませんか)」とゲーム内で案内を行います。
その際、登録してくれた場合にちょっとしたプレゼントやユーザの利益になる(たとえば魔法石500個とか)ようにしておきましょう。

ユーザがメールアドレスを手打ちして、パスワードを考えて登録して、メールアプリを開いて、メール本文のリンクを踏んで、ブラウザ側で認証を確認する、というのはメチャクチャ大変な大作業なので、大作業を行ってくれたユーザが気分良くゲームを続けられそうなプレゼントを提案しましょう。

出来ればユーザが気分良く遊んでいる時に邪魔しないタイミングで、なおかつちょっと良いことがあったタイミングを見計らって案内していきましょう(ストアレビュー依頼も同じ考え方です)

一言で言うとどんなもの?

新しい端末へ、サーバ上にあるユーザーデータの紐づけを行います。

ソーシャルゲームでは、主にサーバ側でユーザーデータを保管しています。 機種変更で旧端末から新端末へゲームデータを移行したい場合などに使用します。

これの理解や実装が不完全だと何が起きるの?

  • 致命的なバグとしては、ユーザーデータ消失や他人のデータでの誤引継ぎがされてしまうこともあり得ます
  • 認証の仕方が甘いとアカウント乗っ取りに利用されてしまうことさえあります
  • ユーザーが今まで費やしてきた時間やお金が絡んでくるため、会社としての信用問題に関わります

AppStore規約における注意点
2017年のApple審査ガイドライン変更で「単一の引継ぎコード」を用いた引継ぎ実装はリジェクトされることとなりました。  2020年現在では主に

  • プレイヤーID+引継ぎコード
  • プレイヤーID+任意のパスワード
  • メールアドレス+引継ぎコード
  • メールアドレス+任意のパスワード
  • 自社サービスアカウント
  • 外部サービスアカウント

などを用いた引継ぎが主流となっています。自社サービスアカウントが既にあるなら自社サービスアカウントを使うのが一番オススメです!

お問い合わせ識別#

ゲーム内にお問い合わせを送る画面を用意しておきましょう。これを用意しておくと、ユーザからのフィードバック頻度がだいぶ変わります。

メンテナンスモードを作ろう#

一言で言うとどんなもの?

運用があるゲームはメンテナンス無しで続けることは、ほとんど不可能です。
そのためサーバのメンテ状態を確認して、メンテ中なら「メンテ中です!」とダイアログを出す(出来れば終了予定やお知らせを差し込む) 仕組みが必要です。

これは大体サーバのresponseステータスコードをメンテ用に定義しておいて、http response時に判定してメンテ中なら無限ダイアログを出す、という方式にします。

これの理解や実装が不完全だと何が起きるの?

  • メンテ中にアクセスするユーザがいてデータ不整合で凄い事になります。
  • チームメンバーからすごく怒られます

詳しく知りたい人は、この辺の単語でググってほしい

APIサーバーとは別のお知らせシステム#

メンテナンス中やAPIサーバーがトラブルを起こした時にお問い合わせをしてもらったり、現在の状況をアナウンスするウェブサイトなどはAPIサーバーとは別に設ける事をお勧めします。
また、これらのサイトへのリンクはアプリ起動時のタイトル画面に外部ブラウザを開くボタンという形で用意しておくとユーザーも操作しやすいです。
このボタンを押せる状態を担保するため、タイトル画面ではユーザー操作が行われるまでは自動的にAPIサーバーと通信しない様にしておくと、エラーダイアログにお知らせサイトへの遷移を防がれる事が無くなります。
自動で通信開始して、あらゆるエラーをかいくぐる実装をしているタイトルもありますが、すごいと思います。 このタイトル画面に問い合わせサイトへのリンクを設ける場合は、問い合わせフォームにユーザーIDやバージョン情報を供給出来ると色々捗るので、ご検討ください。
お知らせサイトはFacebookやTwitterなど、メジャーなブログ的サイトを流用するとお手軽です。

アプリのクラッシュレポート収集#

一言で言うとどんなもの?

リリースのたびにアプリが絶対にクラッシュしないことを保証するのは非常に難しいです。
機能追加によって新しいバグができたり、利用するライブラリにバグがあるなど様々な原因でアプリは落ちるため、開発中にすべてのバグを見つけるのは困難を極めます。

バグの早期発見のため、アプリを利用しているユーザーから提供されるエラーログやクラッシュレポートを分析してバグの特定の足がかりにします。
スマホのアプリの場合は自動化するフレームワークを導入することがほとんどです。

これの理解や実装が不完全だと何が起きるの?

  • 毎回テスターのバグチェックに依存するため、バグの発見が遅くなります
  • 特定の端末のみで発生しているバグ などはさらに発見が遅くなります
  • アプリのユーザー評価を大きく下げる原因になります

詳しく知りたい人は、この辺の単語でググってほしい

  • Firebase Crashlytics
  • Sentry
  • Unity Cloud Diagnostics (これはあんまり使われてないかも?)

KPI (重要業績評価指標)#

一言で言うとどんなもの?

ユーザーの行動を分析して、今後の運用や機能追加の方針を決めるための指標です。

「何割のユーザーが課金してくれたんだろう」とか「どこでやめてしまうユーザーが多いんだろう」などを統計で出すことで、今後の機能追加の方針を決めたり、「ユーザーはこんな行動をするんだ…ふ~ん」と納得したりします。

基本的に、AdjustやUnity AnalyticsといったKPIサービスを利用し、ソースコードの適所にKPI用のコードを仕込む事で統計を取ります。

これの理解や実装が不完全だと何が起きるの?

  • ユーザーにとって必要ない機能を追加して、無駄に時間を取られます
  • マネタイズで失敗して今後の運用に支障をきたしてしまいます
  • 無能運営と罵られます

詳しく知りたい人は、この辺の単語でググってほしい

用語#

DAU (プレイ人数/日)#

MAU (プレイ人数/月)#

DPU (課金率)#

ARPPU (課金単価)#

継続率#

あると嬉しいデバック機能#

時間ずらし#

特定の期間にイベントと称した新たなゲームやマップ、関連する報酬などを提供するシステムが良くあります。これらのデバックを行う際にゲーム環境の日時を任意の時刻にする機能があると大変便利です。
もちろんエクセル上の日付データを調整する事でも動作確認は出来ますが、日付を入力する項目は大抵多数になり全ての箇所が正しい状態になっているか、デバック用から本番用に切り替えているかを担保するのは大変です。
表計算ソフト上でその多数のセルを連携させて少ない工数で切り替え可能なデータにする事でもそこそこ確認は出来ますが、いかんせん本番用データとは違うデータでのデバックを強いられます。
そこで、本番と同じ日時のイベントデータを入れて、環境の時刻をイベント発動時刻に調整してデバック可能とする本機能の実装をおすすめします。
サーバーや端末の時刻をずらすのは大変なので、実際の時刻との差をサーバーとクライアントで共有し、各々のプログラムはその差を加味した時刻を元にイベント発動などの評価を行う様に作る事で実現します。
リアルタイムとの差をサーバーが保持する領域に秒数の数字等で保持し、クライアントはログイン時にサーバーから差のデータを取得してそれを元に挙動を調整する形が無難かと思います。

ゲームデーターコピー機能#

特定の状態やアカウントで無いと発現しないバグが現れた場合、その原因を確認するのはそのアカウントで無いと難しい場合があります。
こんな時に、現象が起きているアカウントのゲームデータをまるっと他のアカウントに移植する機能があると大変便利です。
そのゲームデータ中に原因があった場合は、手元の端末が連携しているアカウントにまるっと移植する事でバグの発現を確認出来るようになります。
ゲームデータのアウトプットとインプット、2つの機能から構成されますが、アウトプットの機能は本番環境にあるとトラブルに遭ってるプレイヤーの状態を開発環境に移植して確認が出来る場合があり、問い合わせの対応が捗ることもあります。