スマホアプリにおけるマルチプレイアクションゲーム開発の実例紹介...

50
スマホアプリにおけるマルチ プレイアクションゲーム開発 の実例紹介 株式会社アカツキ 田中 勇輔

Transcript of スマホアプリにおけるマルチプレイアクションゲーム開発の実例紹介...

スマホアプリにおけるマルチプレイアクションゲーム開発

の実例紹介

株式会社アカツキ 田中 勇輔

自己紹介

• 田中 勇輔 @csouls

• 株式会社アカツキ CTO

• Rubyとかインフラとか開発マネジメントが得意。たまにC++

今日話すこと

オンラインゲームをどのようにして作るのか?

オンラインアクションゲームの実装の実例

オンラインゲームをどのようにして作るのか?

何を作ったのか?

• メザマシフェスティバル

• 2Dスクロールアクション + ソーシャルゲーム

• 一人プレイの冒険と、最大四人プレイのフェスバトル

フェスバトル

• リアルタイム非同期4人同時プレイ奪い合いアクションゲーム

• 動きやモーション、ダメージ、アイテム取得/使用などのイベントを4人で連携しあう

リアルタイム

• コンピューターの文脈では「すぐにやること」でも「早く処理すること」でもなく、「ある処理に対して一定時間内に必ず結果を返すこと」

• オンラインゲームの世界では、1フレーム(1/60, 16.7ms)で同期する(様に見せる)こと

同期型と非同期型

• 同期型/非同期型: ここでは、全てのユーザで見える世界が同じものを「同期」、違うものを「非同期」とします

同期

Player1

Server

Player2

F1 F2 F3 F4 F5

同期 同期

• 一定の間隔で通信内容を同期・演算し、同じ世界を表示

※ フレーム同期、サーバ中継型の場合表示表示

表示 表示

同期

• 格闘ゲームやRTS

• 他にもターンベースで同期する形や、サーバを中継しない形も存在する

• 同期でしか実現できないことも多いが、通信/処理速度が遅い端末がいたら、世界が止まる

非同期

Player1

Server

Player2

F1 F2 F3 F4 F5

• それまでに通信できたものを演算し、すぐに表示

表示 表示 表示 表示

表示 表示 表示 表示

非同期

• MMO RPG等

• 通信レイテンシの差によってイベントの到達順序が入れ替わったりするので、必要であれば順序制御を行う必要がある

同期と非同期

• ゲームデザイナー/エンジニアが考えること

• 何を同期して何を非同期にするか

• 通信のラグをどうカバーするか

• 通信量や計算量をどのようにして少なくするか

モバイル環境 ※ OpenSignal ネットワーク統計データより

レイテンシ DL Speed UP Speed 信頼度

4G

DOCOMO 52 ms 5 Mb/s 1.3 Mb/s 86%

KDDI 40 ms 7.5 Mb/s 1.7 Mb/s 86%

SoftBank 35 ms 11.3 Mb/s 1.8 Mb/s 86%

3G

DOCOMO 616 ms 1.1 Mb/s 0.2 Mb/s 84%

KDDI 259 ms 0.8 Mb/s 0.1 Mb/s 88%

SoftBank 576 ms 1.4 Mb/s 0.3 Mb/s 83%

参照元: http://opensignal.com/networks/日本

モバイル環境

• ネットワークレイテンシ: 30~700ms

• Google Play サポート端末数: 7,319(Android OS Ver4.1以上)

モバイル環境• バラバラな環境の中で、1/60秒(16ms)で動作しているゲームループを遅延することなく、うまくアクションが同期するように見せる

• 1アクションのデータサイズは多くても数十~百Byteちょっとなので、そこまで大きな問題にはならない。レイテンシが辛い

非同期オンラインアクションバトル

• フェスバトルで実現したかったことは、キャラクターを任意のタイミングで自由に動かせること、4人で一緒に遊べること

非同期オンラインアクションバトル

• PvP -> 奪い合いバトル

• PvPだとアクションを同期する必要があり、モバイル環境下で4人分の位置とアクションを遅延なく同期するのは難しいと考えた

同期方式

• 非同期クライアント分散処理型

• メザマシフェスティバルでは、サーバは中継役(リフレクト型)で、ほぼ全ての処理をクライアントに任せている

同期項目(一部)同期項目 処理

ゲーム開始 全てのユーザが接続したので、ゲームを開始

時刻 チート対策のため、時刻とレイテンシのチェック

操作キャラ座標位置 ユーザーの位置とボスの位置を同期

モーション ユーザーの操作演出(ジャンプ、回避、攻撃等)

ダメージ ユーザー、敵の受けたダメージを反映

ポイント 取得したオーブの数を同期

アイテム取得 アイテムの取得を同期

アイテム使用 アイテムの使用を同期

ゲームオーバー ユーザーが画面からいなくなる

コンティニュー ユーザーが復帰する

ゲーム終了 結果画面を表示

位置同期システム

• プレイヤーがラグを感じるポイントはどこかというと、「キャラの座標位置の同期」

• シンプルに座標位置を通信してそのまま処理すると、他のプレイヤーが常にワープしながら動いている様な見え方になる

位置同期システム• PSO2: 歩き始めた時に結果をある程度決めてしまう

(※ CEDEC2010 セガの節政さんの公演より)

• メザマシフェスティバル: ジャンプ中に微妙な移動ができるため、結果が1通信で決まらない

• ワープさせずに位置を合わせるためには、位置同期の仕組みをうまく考える必要がある

位置同期システム

• 対応として、同期イベントをキューとしてためておき、シミュレーションする方式をとった

• 最新のキューとその一つ前を用いて計算

• 「現在、どの速度で、どの位置にいるか」の情報を通信して、キューの間の位置及び速度の補完を行い、現在のプレイヤー位置を求める

• 計算コストが少ないアルゴリズムを実装

位置同期システム

※特許出願中の内容

※特許出願中の内容

同期システム

• 補完の計算コストが少ない

• 同期の間隔がバラバラで予測しづらい動きの場合は、速く(遅く)動いたりする

• レイテンシが一定であれば、うまく補完できる

同期システム

• 間隔をどれくらいにするか?

• たくさん同期しすぎていたら捌き切れない。次のキューで補完されるが、荒くなる。短いと、ばらつきが多くなる

• たどり着いたのは、3回/1秒

同期システム

• つまり、0.3秒 + 必ずかかるレイテンシの時間だけ前の世界をシュミレートしている

• PvPは実現できないが、フェスバトルの内容であれば、うまく全員がリアルタイムにアクションしているように見える

チート対策

チート対策• ゲームデザインとして、ボスは最後に倒した人が2人いたら、どちらも恩恵を受けられるようにした

• 10秒遅延していると、10秒間ボスを殴れる。遅延しているユーザーが有利になる!

• レイテンシの閾値を越えるとエラーにする + 時刻を途中で書き換えらえれたら検知する仕組みを実装

チート対策

• 取得したオーブ数をメモリ上で改ざんされる問題

• 改ざんされた場合、ハッシュ値で検知してエラーとなる仕組みを実装

使っている技術やサービス

インフラ

Load Balancer

• EC2のtagをもとに、各クラスタ(lobby/game server)の各ノードごとのコネクション数を毎秒取得、RedisのSortedSetで保管/更新

• APIサーバーからリアルタイムで最も接続数の少ないノードを読み出し、クライアントにエンドポイントを返す

Autoscaling Server• 設定した閾値に応じてサーバーを自動で追加/縮小

• 追加は最短で3分に一度、縮小は1時間に一度のスパンに制限

• 縮小は深夜帯のみトリガー

• 追加より縮小の方がリスクを伴うためシビアに設定

Autoscaling Server

• ゼロダウンタイム

• Socket.ioプロセスが立ち上がり接続が確立できるまでLB側で有効なノードとして認識しない

• 縮小は、ノードに対するユーザーからの接続がない状態でしかトリガーされない

LBとAutoscaling Serverの可用性• Multi-AZ && 自動FailOver

• Lobbyクラスタ用LB、Gameクラスタ用LBの2台構成、別AZに配備

• それぞれがお互いをSocket.ioプロセスベースで監視し合い、障害発生時に一方がもう一方の機能を吸収する形で自動FailOverを行う

• サーバーが復旧した際は自動FailBack

監視• CloudWatch + Slack連携

• 破壊的なイベント発生時やサーバーの状態を定期的にSlackで通知

LB状態通知 Autoscale結果通知

LoadBalancerはELBではなく、独自実装

LB実装の経緯

• Socket.ioとELBの相性が悪い

• ELBのTCP Listenerを使った場合、Socket.ioのコネクション確立に必要なStickySessionがサポートされておらず、handshakingが確立できない

LB実装の経緯

• 対処の一つとしては、ELBの下にnginxやHAProxyを立ててip-hashでバランスすることでstickinessを担保する → しかし、ELBの下にさらにnginx立てて・・は辛い。

https://medium.com/@Philmod/load-balancing-websockets-on-ec2-1da94584a5e9

LB実装の経緯• Proxy運用コスト…。

• そもそもnginxだとupstreamの動的変更が出来ない(※)ため、ぶら下がるec2インスタンスの変更に手動対応が必要 → オートスケール実現不可 ※ 実際は有償版のnginxPlus購入で可能なようだが、結局追加モジュー

ルを書く必要がある。

→ 今回の実装方法に至る

実装した結果• LBが直接ユーザーからのコネクションを受けることがないため、障害点になるリスクが低い

• 本質的な部分(※)の実装は薄く、モジュール化可能 ※ 各ノードの任意の状態(コネクション数やCPU使用率など)を常時監視し、設定した閾値に応じて任意のスクリプトをトリガー

• 今回のsocket.ioのようなニッチなケースに限らず、http以外のプロトコルでAutoscalingさせたい時等に使える

• SPDY/HTTP2やwebRTC等

最後に

まだまだ改善したいことがあります

• パフォーマンス

• 特にマルチプレイ中のCPU使用率が高すぎる。コツコツとチューニングしていく必要がある

• 操作性

• 「片手持ち」の条件下でできる限りのことはやってみたが、お客様はもっと良いものを求めている

WE ARE HIRING!

http://aktsk.jp/recruit/ or @csouls

ありがとうございました!