2019年2月12日

インディー デベロッパー Bit Dragon は、どのようにしてクロスプラットフォーム プレイを Hyper Jam に実装したか

作成 Geordie Hall

こんにちは。メルボルンに拠点を置くスタジオ、Bit Dragon の共同創業者、Geordie Hall です。私たちの初めてのタイトルである Hyper Jam が、PCPS4Xbox One 向けに発売されました。Hyper Jam は、シンセウェイヴ サウンドに乗せて繰り広げられるハイスピードのアリーナ ブロウラーで、パークのダイナミックな選択システムを採用しています。

私たちは小さなチームではありますが、ローカル対戦、プライベート オンライン対戦、クロスプラットフォーム マッチメイキング (複数人のローカル プレイヤーが参加可能) に対応したゲームを完成させることができました。そのことを誇りに思っています。このゲームはすばらしい学習の機会となり、私たちはほぼあらゆる面で努力を求められました。Hyper Jam のために Unreal Engine を選択したことを嬉しく思っています。Unreal Engine が提供するツールのおかげで、プログラマー 3 人の小さなチームで、このような野心的なマルチプレイヤー ゲームを開発することができました。

非常にハイスピードなゲームです!

クロスプラットフォーム プレイへの道

多くのインディー マルチプレイヤー ゲームがそうであるように、私たちも当初は、オンライン機能を実験するために P2P 接続の Listen サーバーを使用したプライベート ロビーを重点的に使いました。そのうちに、ネットコードを改善するために、Dedicated サーバーを試して、比較してみることにしました。最初にプレイテストした時点で、Dedicated サーバーのほうが優れていると感じました。特にオーストラリアのインターネット回線ではそうなるようでした。発売時にクロスプラットフォーム対応することを決めてからは、Dedicated サーバーのコストは受け入れられるもののように思えてきました。クロスプラットフォームのマッチメイキングがもたらす可能性を考慮して、Dedicated サーバーを使うことにしました。

クロスプラットフォームのマッチメイキングには、いくつか大きなメリットがあります。最も明らかなメリットは、マッチメイキングのプールのプレイヤー数が増えることです。大規模なゲームでは、待ち時間が減り、プレイヤーのエクスペリエンスが改善されるでしょう。小規模なゲームでは、マッチが成立するか、成立せずにプレイヤーががっかりして去ってしまうかという違いになります。マッチメイキングのプールを共通のものにすると、いずれかのプラットフォームがほかに比べて人気がなかった場合にも、ゴーストタウンのようにならずに済みます。悪いレビューを避けて、ゲームの寿命を延ばすことができるでしょう。クロスプラットフォームのパーティもサポートできれば、オーディエンスを大きく広げることができます。

では、インディーのデベロッパーにとって、クロスプラットフォーム プレイを実現するのはどれほど難しいのでしょうか。オンライン サービスの開発が初めてであれば、当然ながら学習することは多くなり、予想したよりも多くの困難が待ち構えているでしょう。しかし、悪いことばかりではありません。オンライン ゲームのサービスを統合して利用しやすくするために、多くの企業が懸命に取り組んでいます。時間が経つほどに、オンライン ゲームは開発しやすくなっていくでしょう。Epic Games は、クロスプラットフォーム オンライン サービスを実現するためのスイートをこれから 1 年ほどかけて展開していくことを予定しています。デベロッパーにとっては選択肢が 1 つ増えることになるでしょう。

私たちのように、複数のプラットフォーム向けにオンライン ゲームを開発するなら、そのゲームはクロスプラットフォーム プレイに適しているでしょう。このまま読み進めて、私たちが学んだことを参考にしてください。

Dedicated サーバー

クロスプラットフォーム プレイの大きな前提条件の 1 つに、Dedicated サーバーがあります。P2P の Listen サーバーをすでに使っている方であれば、あるプラットフォームにホストした Listen サーバーから別のプラットフォームの Listen サーバーには接続できないことにお気付きかもしれません。一般的に、ネット ドライバーはプラットフォームごとに異なります。ネット ドライバーは、プラットフォームでの NAT トラバーサルを処理します。たとえば、SteamNetDriver は Steam Socket を使用します。しかし、クロスプラットフォーム プレイのためには、各プラットフォームが 1 つのサーバーに接続して (たとえば標準の IpNetDriver を使用して) 同じ言語でやりとりする必要があります。(私たちのように) プライベート対戦では Listen サーバーを使用したいという場合、使用するネット ドライバーを実行時に変更する必要があります。

P2P 接続は、プレイヤー同士が知り合いであるプライベート対戦ではうまく機能しますが、次に挙げるような性質があるため、マッチメイキングには適していません。

  • QoS チェックを適切に行ったとしても、プレイヤーのエクスペリエンスの良し悪しがホストのインターネット接続に依存する
  • クライアント側で予測を行う対戦ゲームとしては気を付けるべき、ホストが有利になってしまうという問題がある
  • ホスト マイグレーションが難しいが、この機能がないと、ほかのプレイヤーがホストによってゲームを台無しにされてしまうことがある
  • ホストを信頼できないという問題があり、ランキング モードを実現できない

Dedicated サーバーは、前述の問題をすべて解決しますが、明らかなデメリットとして、サーバーをホストするコストが生じます。この継続的なコストは、インディー デベロッパーとしては簡単に正当化できるものではありませんが、クロスプラットフォームで発売することを決めてから、投資を行うことにしました。

Listen サーバーしか使ったことがないという場合は、Dedicated サーバーは怖いと思うかもしれませんが、実際にはごくわかりやすいものです。サーバーには Windows と Linux を利用できます。Windows インスタンスよりも Linux インスタンスのほうが低コストで運用できる傾向があるので、時間をかけてでも Linux 用のビルドを利用するようにしたほうがいいでしょう。ありがたいことに、UE4 によって、Linux 用のビルドを簡単に利用できるようになっています。クロスコンパイル ツールチェーンをインストールすると、ターゲット プラットフォームに Linux を含めることができるようになります。従来、Clang は VC++ よりも若干扱いにくいものでしたが、その違いは徐々に少なくなってきています。また、使用しているプラグインが Linux をサポートしていることを確認する必要があります。Dedicated サーバーはウィジェットやサウンドなどを実行しないので、ゲームプレイのロジックは、外見を扱うオブジェクトから切り離しましょう。

デフォルトでは、Dedicated サーバーはヘッドレスで実行され、単純に 1 つのファイルにログを記録します。「-log」引数を与えると起動時にログ ウィンドウを表示させることができ、開発中には便利です。また、Dedicated サーバーは、UAT の引数を 1 つ追加するだけで、継続的インテグレーション (CI) のパイプラインと簡単に連携させることができます。Linux サーバーをテストする必要がある場合はローカルの仮想マシンか EC2 のインスタンスを起動できますが、開発テストの大半は Windows Server 1 台で十分でしょう。PIE で Dedicated サーバーを使うこともできます。これはブループリントのデバッグには非常に便利です。

クラウド ホスティング

Dedicated サーバーのバイナリとネットコードを問題なく実行できるようになったら、どこかにサーバーをホストして、クライアントが接続できるようにする必要があります。ホスティングの選択肢は多数あります。Amazon GameLift、Google Cloud Compute と Kubernetes、PlayFab などを利用できます。コスト、スケーリング、サポートについて主に注意しましょう。

プレイヤーの需要に合わせて、サーバーの規模を拡大したり縮小したりできる必要があります。理想的には、オフピーク時にはできるだけ小さな規模にできるといいでしょう。これらのシステムの多くでは、1 つの IP を割り当てられた 1 台の仮想マシンを起動して、N 個のサーバー プロセスを実行し、各プロセスが異なるポートをリッスンします。サーバー マネージャーがゲームのセッションを各サーバー プロセスに割り当て、それぞれの利用状況を追跡します。インスタンス上で空いているサーバー プロセスの数が一定のしきい値を下回ると、システムが別の仮想マシンを起動します。すると N 個のゲーム セッションがフリートに追加され、利用できるようになります。また、スケーリングのシステムは、新しいセッションをインテリジェントに割り当てて、スケールダウンを行ってリソースを有効活用できるものにするべきです。たとえば、5 つのゲーム セッションが 5 台のマシンに分散するのは望ましくありません。

プロバイダーの多くは、何らかの形でさまざまな構成を無料で試せるようにしています。これは試験的な利用には適しています。

インディーのデベロッパーにとって、コストは常に懸念となります。サーバーのコストを下げるためにどのくらいの手間をかける余地があるか、バランスを見極める必要があります。スケーリングのコストについて検討するときには、「サーバー 1 台あたりのプレイヤー数 * インスタンスあたりのサーバー数 * 同時接続するプレイヤー数」を主に考慮します。GameLift の価格設定のページでは、1 日を通じたプレイヤーの需要の一般的な変動例を示す曲線と、その変動が必要なインスタンス数に与える影響が示されています。ただし、この例は、インディー ゲームとしては数字が大きすぎるかもしれません。

CPU とメモリの両面でゲームを最適化すると、1 つのインスタンスに収められるサーバーの数が増加し、コスト削減につながります。ネットワークのトラフィックについて課金される場合もあります。ネットコードを最適化すると、ゲームプレイを改善できるだけでなく、サーバーの料金を下げることができる可能性があります。

新しいプレイヤーを受け入れるために、各リージョンで 1 つのインスタンスは実行したいところですが、可用性の要件によっては、スケーリングのためにスポット インスタンスあるいはプリエンプティブル インスタンスと呼ばれるインスタンスを利用できるかもしれません。これらのインスタンスは、大幅な割引が適用される代わりに、クラウド プロバイダーの都合で急に強制終了されることがあります。

また、サーバーの費用対効果を向上させるために、公開前に、推定されるプレイヤー数を考慮してコストを予測するといいでしょう。コストについては、公開から数か月、数年にわたって評価し続ける必要があります。サーバーをオフにせざるを得なくなる不測の事態 (P2P に切り換えるなどの方法で対処) についても考えておく価値はあります。

CI のパイプラインがすでにある場合、ゲームのサーバーとクライアントのビルドのアップロードを自動化できます。ナイトリー ビルドのテスト用にフリートを起動できるようにしておくと非常に役に立つことがありますが、その場合はホストのストレージ容量の制限などに気を配る必要があります。

サーバーをホストするリージョンを選択する際は、コストと需要の間で難しいバランスをとることになります。公開前は特に判断が難しいでしょう。AWS と Google Cloud はどちらも世界中をよくカバーしています。AWS は最近、GameLift を中国で利用できるようにしました。プレイヤーのレイテンシのデータをマッチメーカーに渡せば、どこでプレイヤーの需要が生じているか、サーバーがそれほど多く必要ないのはどのリージョンかということがわかりやすくなります。

公開時には、想定しうる範囲で最多のトラフィックを処理できるようにオーバープロビジョニングするといいかもしれません。公開日にはサポートも重要です。何かしら問題は発生し、できるだけ解決する必要があります。この記事が公開されるころ、ちょうど私がそうしていることでしょう!

マッチメイキング

Dedicated サーバーのフリートを作成し、拡張できる状態で、ゲームを受け付ける準備ができたら、プレイヤーを組み合わせて対戦させる方法が必要になります。多くのプラットフォームで、クロスプラットフォーム プレイを可能にするための何らかのファーストパーティ マッチメイキング API が提供されていますが、サーバー マネージャーとも通信できる、一元化されたマッチメーカーが必要です。

ホスティングと同様に、ゲームのバックエンドにも多数の選択肢があります。ホスティング、マッチメイキング、クライアント サイド SDK が完全に統合されたソリューションもあれば、サーバーとマッチメイキングを処理するプロバイダーもあります。ただし、どの場合でも、認証とクライアントの通信を処理するための独自のバックエンドは必要です。

最低限、クライアントは、特定のパラメータを持つマッチを探していることをバックエンドに伝える必要があります。それからバックエンドが各プラットフォームの認証トークンを使用してリクエストを認証し、マッチメイキング プールに追加します。マッチが発見されたら、マッチメーカーはサーバーにゲーム セッションを割り当て、各クライアントにサーバーの IP とポートを伝え、どのプレイヤーのジョインを許可するかサーバーに伝えます。このとき、チームやゲームのタイプなど、マッチメイキングに役立つデータも合わせて伝えます。

選択肢を評価するときは、現在の要件だけを考えるのではなく、将来の可能性についても考えましょう。そうすることで、将来優れた機能を追加できなくなる事態を回避できます。次のようなことを考慮してください。

  • マッチメイキングはルールベースにしたいか、ロビーベースにしたいか
  • 時間の経過に応じてルールを緩和できるようにしたいか
  • レイテンシの情報を考慮するか
  • 一度に複数のゲーム タイプのキューに加わることを許可するか
  • マッチメイキングでパーティをサポートするか
  • クロスプラットフォームのパーティを許可するか
  • 複数人のローカル プレイヤーをサポートするか
  • チームが必要で、複数のパーティからチームを組めるようにするか
  • プレイヤーがゲーム内でほかのことをしながら待機できる、非同期のマッチメイキングを可能にするか
  • どのプラットフォーム間で対戦できるかを制限できるようにする必要があるか(その必要がなくなることを願っています)
  • 回避やブロックのリストが必要か
  • スキルベースのマッチメイキングやランク モードを可能にするために、持続的なプレイヤー データにアクセスできる必要があるか
  • 進行中のマッチにジョインできるようにする、バックフィルをサポートするか

具体的なアドバイスをしても、すぐに時代遅れになってしまいそうですが、1 つ確実に言えるのは、この点についてはできるだけ早く考えたほうがいいということです。

マッチメイキング機能を評価する際は、プレイヤーの ID、フレンド、プレゼンス、パーティ、リーダーボード、アナリティクスなど、各バックエンド プロバイダーのその他のサービスについても確認してください。1 つのバックエンド プロバイダーを使用する場合、これらのサービスの品質を選択の判断に利用できます。これらはゲームに組み込むために時間がかかる機能です。あとから変更するのは難しい場合もあるので、慌てずに検討しましょう。ある領域ではすでにいずれかのプロバイダーを使っていて、マッチメイキングでは別のプロバイダーを使いたいという場合は、そうすることもできます。オンライン サービスには必然的に変動的な要素が関わってきます。どの部分をどこから調達するかは各自の判断によります。

バージョン管理と互換性

Dedicated サーバーの準備ができて、特にクロスプラットフォーム プレイに対応する場合は、クライアントとサーバーのバージョン管理と、それがマッチメイキングに与える影響について考える必要があります。この点については、あまりうまく統合されたソリューションを見たことがありませんので、ご自身で何か考え出す必要があるかもしれません。

ネットワーク機能の互換性を損なうアップデートをリリースする必要がある場合、どのような影響があるか検討が必要です。クライアントをアップデートすることなく、ネットワーク機能の互換性を持つサーバーのビルドを新しくリリースできるでしょうか。特定のプラットフォームでクロスプラットフォーム プレイを不可能にする必要が生じた場合に、ほかのプラットフォームを特定のバージョンにするように求めることができるでしょうか。

クライアントのアップデートがすべてのリージョンのすべてのプラットフォームに展開されるには、時間がかかることがあります。古いサーバーをすぐにシャットダウンしてしまうと、アップデートがまだ提供されていないプレイヤーがいるかもしれませんので、注意が必要です。また、アップデートが利用できるようになったとしても、対戦中にはアップデートを開始したくないでしょう。

シームレスなアップデートのエクスペリエンスを作るのは、必ずしも難しいことではありませんが、事前の計画が必要です。私たちは、アップデート期間中には新旧両方のバージョンからマッチを受け付けるようにしました。古いサーバーも残しておくことで、プレイヤーがマッチを完了できるようにしました。クライアントがアップデートを確認できるようにして (新しいマッチを開始する前にアップデートを適用し)、無理のない時間が過ぎたところで古いサーバーを落とし、古いクライアントからのリクエストを拒否するようにしました。サーバーのみが対象のパッチをデプロイする必要がある場合、マッチメーカーによって、新しいパッチが適用されたフリートに新しいマッチを割り当てるようにして、古いフリートでのすべてのマッチが終了した時点で、古いフリートをバックグラウンドで終了させることができます。

ネットワーク機能の互換性について、クライアントとサーバーのビルドをテストすることも重要です。既存のリリース ブランチに修正を加える場合は特に重要性が高くなります。ブループリントのネイティブ化機能を使う場合、ネイティブ化されていないクライアントからネイティブ化されたサーバーに接続するとき (PIE または Cook on the Fly など) に、互換性の問題が発生する可能性があります。コンソール変数 net.IgnoreNetworkChecksumMismatch を 1 に設定すると、エディタでのテスト中に「Net GUID Mismatch」エラーでキックされることを回避できます。

これに関連して、コンフィギュレーション ファイルの変数 TimeoutMultiplierForUnoptimizedBuilds を確認してください。この変数で、エディタ内でのネット ドライバーのタイムアウトしきい値を増加させることができます。接続のタイムアウトとラグのしきい値は比較的短くなっているため、エディタ内でのテストでは、何かの読み込みやコンパイルに想定以上の時間がかかった場合、移動中にタイムアウトになることがよくあります。ネットワーク対応のゲームを作成する場合、間違いなく、複数の PIE ウィンドウとマルチプロセスの PIE をすでに使っているでしょう。しかし、これらの機能がほかのエンジンの機能と比べてどのくらい優れているかについては、知っておく価値があると思います。

プラットフォームの要件

特にオンライン ゲームでは、各プラットフォームで極めて具体的な要件が生じることがあります。この点については、クロスプラットフォームの開発を行っていくうちに学んでいくでしょう。クロスプラットフォーム プレイでは、ほかのプレイヤーがどのネットワークに接続しているかの表示 (または非表示)、プレイヤー名のサニタイズと衝突の処理、プレイヤーの権限の検証、ほかのプラットフォーム固有の API の呼び出しなどが関わってくることがあります。

各プラットフォームに早い段階で問い合わせて、要件を順守するために必要な情報すべてを入手して、スケジュールに影響するような予想外の事態を回避しましょう。

クロスプラットフォーム プレイのすすめ

インディー スタジオがマルチプレイヤー ゲームを開発するのは難しい場合もありますが、クロスプラットフォーム プレイを実装すると、マッチメイキングのプールが大きくなり、クロスプラットフォーム開発の見返りが増えます。インディー スタジオにとっては膨大な作業量に思えるかもしれませんが、ゲームの大きなセールスポイントになりますし、サービス プロバイダーが成熟し、プラットフォームがオープンになっていくなかで、徐々に難易度は下がっていくでしょう。

みなさまのゲームにクロスプラットフォーム プレイを追加するために何を考慮すればいいか、この記事が概要を示すことができましたら幸いです。

Hyper Jam は、SteamPS4Xbox One 向けに発売中です!