paint-brush
戦争ロボット10周年を祝い、技術的な観点から振り返る@pauxi
3,667 測定値
3,667 測定値

戦争ロボット10周年を祝い、技術的な観点から振り返る

Paul Xi31m2024/04/30
Read on Terminal Reader

長すぎる; 読むには

この投稿では、10 年にわたる War Robots の技術的な側面、つまり、興味深い点、問題点、実験、ゲームのリマスターなどについて見ていきます。
featured image - 戦争ロボット10周年を祝い、技術的な観点から振り返る
Paul Xi HackerNoon profile picture
0-item
1-item


War Robots は今年 4 月に 10 周年を迎えます。現在に至るまで、プレイヤー向けに新機能をリリースするだけでなく、技術的な改善も行いながら開発とサポートを続けています。


この記事では、この大規模プロジェクトの技術開発における当社の長年の経験について説明します。まずは、現状のプロジェクトのスナップショットをご紹介します。


  • 数十万人のDAU(デイリーアクティブユーザー)
  • 数億のインストール
  • 12人による同時対戦が数万回
  • 4つの主要プラットフォーム(iOS、Android、Steam、Amazon)で利用可能
  • AndroidやPCを含む数万のデバイスに対応
  • 数百台のサーバー
  • クライアント開発者約20名、サーバー開発者9名、クロスプロジェクト開発チーム8名、DevOps 3名
  • クライアント側コード約150万行
  • 2014 年にバージョン 4 から Unity を使用し始め、現在は 2024 年にバージョン 2022 LTS を使用しています。


この種のプロジェクトの機能性を維持し、さらに高品質な開発を確実に行うには、当面の製品タスクに取り組むだけでは不十分です。技術的な条件を改善し、開発を簡素化し、新しいコンテンツの作成に関連するものも含めプロセスを自動化することも重要です。さらに、利用可能なユーザーデバイスの市場の変化に常に適応する必要があります。


このテキストは、Pixonic (MY.GAMES) の開発部門責任者 Pavel Zinov 氏と、War Robots の主任開発者 Dmitry Chetverikov 氏へのインタビューに基づいています。


始まり

2014 年に戻りましょう。War Robots プロジェクトは当初、小規模なチームによって作成され、すべての技術的ソリューションは、迅速な開発と新機能の市場への提供というパラダイムに適合していました。当時、同社には専用サーバーをホストするための大規模なリソースがなかったため、War Robots は P2P ロジックに基づくネットワーク マルチプレイヤーで市場に参入しました。


Photon Cloud はクライアント間のデータ転送に使用されました。移動、射撃、その他のコマンドなど、各プレイヤーのコマンドは個別の RPC を使用して Photon Cloud サーバーに送信されました。専用サーバーがなかったため、ゲームにはマスター クライアントがあり、すべてのプレイヤーの試合状態の信頼性に責任を負っていました。同時に、残りのプレイヤーはローカル クライアントでゲーム全体の状態を完全に処理しました。


たとえば、動きの検証はありませんでした。ローカル クライアントがロボットを適切と判断して動かすと、その状態がマスター クライアントに送信され、マスター クライアントはこの状態を無条件に信じて、マッチ内の他のクライアントに転送するだけです。各クライアントは独立して戦闘のログを保持し、マッチ終了時にサーバーに送信し、サーバーはすべてのプレイヤーのログを処理して報酬を授与し、マッチの結果をすべてのプレイヤーに送信しました。


プレイヤー プロファイルに関する情報を保存するために、特別なプロファイル サーバーを使用しました。これは、Cassandra データベースを備えた多数のサーバーで構成されていました。各サーバーは Tomcat 上のシンプルなアプリケーション サーバーであり、クライアントは HTTP 経由でサーバーと対話しました。


当初のアプローチの欠点

ゲームプレイで使用されたアプローチには、いくつかの欠点がありました。もちろん、チームはこれらの欠点を認識していましたが、開発のスピードと最終製品の市場投入のスピードを考えると、いくつかの妥協が必要でした。


これらの欠点の第一は、マスター クライアントの接続品質でした。クライアントのネットワークが悪ければ、試合に参加しているすべてのプレイヤーが遅延を経験しました。また、マスター クライアントがあまり高性能なスマートフォンで実行されていない場合、その負荷が高いため、ゲームでもデータ転送の遅延が発生しました。そのため、この場合、マスター クライアントだけでなく、他のプレイヤーも影響を受けました。


2 つ目の欠点は、このアーキテクチャでは不正行為者による問題が発生しやすいことです。最終状態はマスター クライアントから転送されるため、このクライアントは、試合中に獲得したゾーンの数をカウントするなど、多くの試合パラメータを自由に変更することができます。


3 つ目は、Photon Cloud のマッチメイキング機能に問題があります。Photon Cloud マッチメイキング ルームの最年長プレイヤーがマスター クライアントになり、マッチメイキング中に何かが起きた場合 (たとえば、切断)、グループの作成に悪影響が及びます。関連する興味深い事実: グループをマッチに送った後に Photon Cloud のマッチメイキングが終了しないようにするため、しばらくの間、オフィスにシンプルな PC を設置していましたが、これが常にマッチメイキングをサポートしていたため、Photon Cloud とのマッチメイキングが失敗することはありませんでした。


ある時点で、問題とサポート要求の数が臨界量に達したため、私たちはゲームの技術アーキテクチャを進化させることを真剣に考え始めました。この新しいアーキテクチャは、Infrastructure 2.0 と呼ばれていました。


インフラストラクチャ 2.0 への移行

このアーキテクチャの背後にある主なアイデアは、専用のゲーム サーバーを作成することでした。当時、クライアントのチームには、サーバー開発の豊富な経験を持つプログラマーが不足していました。しかし、その会社は同時に、AppMetr と呼ばれるサーバーベースの高負荷分析プロジェクトに取り組んでいました。チームは、1 日に数十億のメッセージを処理する製品を開発しており、サーバー ソリューションの開発、構成、正しいアーキテクチャに関する豊富な専門知識を持っていました。そこで、そのチームのメンバーの一部が Infrastructure 2.0 の作業に参加しました。


2015 年、かなり短期間で、Windows Server 上で実行される Photon Server SDK フレームワークでラップされた .NET サーバーが作成されました。私たちは Photon Cloud を放棄し、クライアント プロジェクトに Photon Server SDK ネットワーク フレームワークのみを残し、マッチメイキングのためにクライアントと対応するサーバーを接続するマスター サーバーを作成することを決定しました。一部のロジックは、クライアントから専用のゲーム サーバーに移動されました。特に、基本的なダメージ検証が導入され、マッチ結果の計算がサーバー上に置かれました。



マイクロサービスの出現

Infrastructure 2.0 の作成に成功した後、私たちはサービスの役割を分離する方向に進み続ける必要があることに気付きました。その結果、マイクロサービス アーキテクチャが作成されました。このアーキテクチャで作成された最初のマイクロサービスは clans です。


そこから、別の通信サービスが登場し、これがマイクロサービス間のデータ転送を担当しました。クライアントは、ゲームサーバーのメタメカニクスを担当する「ハンガー」との接続を確立し、Photon Cloud 経由で UDP を使用して API リクエスト (サービスと対話するための単一のエントリ ポイント) を行うように教えられました。徐々にサービスの数が増え、その結果、マッチメイキング マイクロサービスをリファクタリングしました。これにより、ニュース機能である Inbox が作成されました。


クランを作成したとき、プレイヤーがゲーム内で互いにコミュニケーションを取りたいと考えていることは明らかでした。何らかのチャットが必要でした。これはもともと Photon Chat に基づいて作成されましたが、最後のクライアントが切断されるとすぐにチャット履歴全体が消去されました。そのため、このソリューションを Cassandra データベースに基づく別のマイクロサービスに変換しました。


インフラストラクチャ 4.0 とサーバーの場所

新しいマイクロサービス アーキテクチャにより、互いに独立した多数のサービスを簡単に管理できるようになり、システム全体を水平方向にスケーリングしてダウンタイムを回避できるようになりました。


私たちのゲームでは、サーバーを一時停止することなく更新が行われました。サーバー プロファイルは複数のバージョンのクライアントと互換性があり、ゲーム サーバーに関しては、常にクライアントの古いバージョンと新しいバージョンのサーバーのプールがあり、このプールはアプリケーション ストアで新しいバージョンがリリースされた後に徐々にシフトし、ゲーム サーバーは古いバージョンから時間の経過とともに消えていきました。現在のインフラストラクチャの概要はインフラストラクチャ 4.0 と呼ばれ、次のようになっています。



アーキテクチャの変更に加えて、世界中のプレイヤーをカバーする必要があったため、サーバーをどこに配置すべきかというジレンマにも直面しました。当初、多くのマイクロサービスはさまざまな理由から Amazon AWS に配置されていましたが、特に、このシステムはスケーリングの面で柔軟性があるため、ゲーム トラフィックが急増する瞬間 (ストアで特集されたときや UA を高めるときなど) に非常に重要でした。さらに、当時は、優れたネットワーク品質と外部との接続を提供する優れたホスティング プロバイダーをアジアで見つけることは困難でした。


Amazon AWS の唯一の欠点は、コストが高いことでした。そのため、時間の経過とともに、多くのサーバーが自社のハードウェア (世界中のデータセンターでレンタルしているサーバー) に移行しました。とはいえ、Amazon AWS はアーキテクチャの重要な部分であり続けました。これは、常に変化するコード (特に、リーグ、クラン、チャット、ニュース サービスのコード) の開発を可能にし、安定性テストで十分にカバーされていなかったためです。しかし、マイクロサービスが安定していることがわかった時点で、それを自社の施設に移行しました。現在、すべてのマイクロサービスはハードウェア サーバーで実行されています。


デバイスの品質管理とその他の指標

2016 年には、ゲームのレンダリングに重要な変更が加えられました。戦闘中のすべてのメカに単一のテクスチャ アトラスを使用する Ubershaders の概念が登場し、描画呼び出しの数が大幅に削減され、ゲームのパフォーマンスが向上しました。


私たちのゲームが何万もの異なるデバイスでプレイされていることが明らかになり、各プレイヤーに可能な限り最高のゲーム環境を提供したいと考えました。そこで、Quality Manager を作成しました。これは基本的に、プレイヤーのデバイスを分析し、特定のゲーム機能やレンダリング機能を有効 (または無効) にするファイルです。さらに、この機能により、特定のデバイス モデルに至るまでこれらの機能を管理できるため、プレイヤーが経験している問題を迅速に解決できます。


また、Quality Manager の設定をサーバーからダウンロードし、現在のパフォーマンスに応じてデバイスの品質を動的に選択することもできます。ロジックは非常に単純です。Quality Manager の本体全体がブロックに分割され、各ブロックがパフォーマンスの特定の側面を担当します。(たとえば、シャドウの品質やアンチエイリアシングなど) ユーザーのパフォーマンスが低下すると、システムはブロック内の値を変更し、パフォーマンスの向上につながるオプションを選択しようとします。Quality Manager の進化については後で少し説明しますが、この段階では、実装は非常に高速で、必要なレベルの制御が提供されていました。


グラフィックスの開発が進むにつれて、Quality Manager の作業も必要になりました。ゲームには現在、カスケード ダイナミック シャドウが搭載されており、すべて当社のグラフィックス プログラマーによって実装されています。


徐々に、プロジェクトのコードにかなり多くのエンティティが登場したため、それらのライフタイムを管理し、さまざまな機能へのアクセスを制限するのが良いと判断しました。これは、ゲーム コンテキストが変更されたときに多くのリソースがクリアされていなかったため、格納庫と戦闘コードを分離する上で特に重要でした。さまざまな IoC 依存関係管理コンテナーの調査を開始しました。特に、StrangeIoC ソリューションを検討しました。当時、このソリューションは私たちにとってかなり面倒に思えたため、プロジェクトに独自のシンプルな DI を実装しました。また、格納庫と戦闘のコンテキストも導入しました。


さらに、プロジェクトの品質管理にも取り組み始めました。FirebaseCrashlytics をゲームに統合し、本番環境でのクラッシュ、ANR、例外を特定しました。


AppMetr と呼ばれる社内分析ソリューションを使用して、顧客のステータスを定期的に監視し、リリース中に行われた変更を比較するために必要なダッシュボードを作成しました。さらに、プロジェクトの品質を向上させ、コードに加えられた変更に対する信頼性を高めるために、自動テストの研究を始めました。


コンテンツ内のアセット数の増加と固有のバグにより、アセットの整理と統合について考えるようになりました。これは特にメカに当てはまりました。メカはそれぞれ独自の構造を持っていたからです。このため、Unity でツールを作成し、これを使用して、主要な必要なコンポーネントを備えたメカ ダミーを作成しました。これにより、ゲーム デザイン部門が簡単に編集できるようになりました。これが、メカに関する作業の統合を開始したきっかけです。


その他のプラットフォーム

プロジェクトは成長を続け、チームは他のプラットフォームでのリリースを検討し始めました。また、当時の一部のモバイル プラットフォームでは、ゲームをフィーチャーするために、プラットフォームのネイティブ機能をできるだけ多くサポートすることが重要でした。そこで、Apple TV 用の War Robots の実験バージョンと、Apple Watch 用のコンパニオン アプリの開発を始めました。


さらに、2016 年には、私たちにとって新しいプラットフォームである Amazon AppStore でゲームをリリースしました。技術的な特徴の点では、このプラットフォームは Apple のように統一されたデバイス ラインを備えているという点でユニークですが、このラインのパワーはローエンドの Android レベルです。これを念頭に置いて、このプラットフォームでリリースする際には、メモリの使用とパフォーマンスを最適化するために、アトラスやテクスチャ圧縮などの重要な作業が行われました。ログインと実績のための Game Center の類似物である Amazon の支払いシステムがクライアントに統合されたため、プレイヤーのログインを操作するフローが作り直され、最初の実績がリリースされました。


また、同時に、クライアント チームが初めて Unity エディター用のツール セットを開発し、エンジン内でゲーム内ビデオを撮影できるようになったことも注目に値します。これにより、マーケティング部門はアセットの操作、戦闘の制御、カメラの活用が容易になり、視聴者に大変好評だったビデオを作成できるようになりました。


不正行為者との戦い

Unity が存在せず、特にサーバー上に物理エンジンがなかったため、ほとんどの試合は引き続きプレイヤーのデバイス上でエミュレートされていました。このため、不正行為者による問題は解決されませんでした。定期的に、サポート チームは不正行為者のビデオをユーザーからフィードバックとして受け取りました。不正行為者は都合の良いときにスピードを上げたり、マップを飛び回ったり、角を曲がったところから他のプレイヤーを殺したり、不死身になったりしていました。


理想的には、すべてのメカニズムをサーバーに転送します。ただし、ゲームが継続的に開発され、すでにかなりの量のレガシー コードが蓄積されているという事実に加えて、権威サーバーを使用するアプローチには他の欠点もあります。たとえば、インフラストラクチャの負荷が増加し、より優れたインターネット接続が必要になります。ほとんどのユーザーが 3G/4G ネットワークでプレイしていることを考えると、このアプローチは明らかではありますが、問題の効果的な解決策ではありませんでした。チーム内の不正行為者に対抗する代替アプローチとして、私たちは「クォーラム」を作成するという新しいアイデアを思いつきました。


クォーラムは、ダメージを確認する際に、異なるプレイヤーの複数のシミュレーションを比較できるメカニズムです。ダメージを受けることはゲームの主要な機能の 1 つであり、ゲームの残りの状態は事実上これに依存します。たとえば、対戦相手を破壊した場合、対戦相手はビーコンをキャプチャできなくなります。


この決定の考え方は次の通りです。各プレイヤーは引き続き世界全体をシミュレートし (他のプレイヤーの射撃を含む)、その結果をサーバーに送信します。サーバーはすべてのプレイヤーの結果を分析し、プレイヤーが最終的にダメージを受けたかどうか、またどの程度ダメージを受けたかを決定します。私たちの試合には 12 人が参加しているので、サーバーがダメージを受けたと判断するには、この事実が 7 人のプレイヤーのローカル シミュレーション内に記録されるだけで十分です。これらの結果は、さらに検証するためにサーバーに送信されます。図式的に、このアルゴリズムは次のように表すことができます。



この仕組みにより、戦闘中に自分自身を不死身にする不正行為者の数を大幅に減らすことができました。次のグラフは、これらのユーザーに対する苦情の数と、サーバー上でダメージ計算機能を有効にし、ダメージクォーラムを有効にする段階を示しています。



このダメージを与えるメカニズムは、長い間、不正行為の問題を解決してきました。サーバーに物理学が欠けているにもかかわらず (したがって、表面の地形や空間内のロボットの実際の位置などを考慮できない)、すべてのクライアントのシミュレーション結果とそのコンセンサスにより、誰が誰にどのような条件下でダメージを与えたかが明確に理解できたためです。


プロジェクトのさらなる発展

時間の経過とともに、ダイナミック シャドウに加えて、Unity ポスト プロセッシング スタックとバッチ レンダリングを使用してゲームにポスト エフェクトを追加しました。ポスト プロセス エフェクトを適用した結果、グラフィックが改善された例を次の画像で確認できます。



デバッグ ビルドで何が起こっているかをよりよく理解するために、ログ システムを作成し、内部インフラストラクチャにローカル サービスを展開しました。これにより、内部テスターからログを収集して、バグの原因を見つけやすくなりました。このツールは現在でも QA によるプレイテストに使用されており、その作業結果は Jira のチケットに添付されています。


また、プロジェクトには独自に作成したパッケージ マネージャーも追加しました。当初は、さまざまなパッケージや外部プラグイン (プロジェクトにはすでに十分な数が蓄積されていました) の操作性を向上させたいと考えていました。しかし、当時の Unity の機能は十分ではなかったため、社内のプラットフォーム チームが、パッケージのバージョン管理、NPM を使用したストレージ、GitHub へのリンクを追加するだけでパッケージをプロジェクトに接続できる機能を備えた独自のソリューションを開発しました。それでもネイティブ エンジン ソリューションを使用したかったため、Unity の同僚に相談し、2018 年に Unity がパッケージ マネージャーをリリースしたときに、私たちのアイデアの多くが Unity の最終ソリューションに取り入れられました。


私たちは、ゲームが利用できるプラットフォームの数を拡大し続けました。最終的に、キーボードとマウスをサポートするプラットフォームである Facebook Gameroom が登場しました。これは Facebook (Meta) のソリューションで、ユーザーが PC でアプリケーションを実行できるようにします。基本的には、Steam ストアのアナログです。もちろん、Facebook のユーザーは非常に多様であり、Facebook Gameroom は、主にゲーム以外のデバイスを中心に、多数のデバイスでリリースされました。そのため、メイン ユーザーの PC に負担をかけないように、モバイル グラフィックスをゲームに残すことにしました。技術的な観点から、ゲームに必要な唯一の大きな変更は、SDK、支払いシステムの統合、ネイティブ Unity 入力システムを使用したキーボードとマウスのサポートでした。


技術的には、Steam 向けのゲームのビルドとほとんど違いはありませんでしたが、デバイスの品質は大幅に低下しました。これは、このプラットフォームが、ブラウザーしか実行できない非常にシンプルなデバイスを持つカジュアル プレイヤー向けの場所として位置付けられていたためです。Facebook はこれを念頭に、かなり大きな市場に参入したいと考えていました。これらのデバイスのリソースは限られており、特にプラットフォームでは、メモリとパフォーマンスの問題が継続的に発生していました。


その後、プラットフォームが閉鎖され、プレイヤーを Steam に移行させることが可能になりました。そのために、プラットフォーム間でアカウントを移行するためのコードを備えた特別なシステムを開発しました。


VRでWar Robotsを試してみる

2017 年の注目すべきもう 1 つの出来事は、ノッチ付きの初のスマートフォンである iPhone X のリリースです。当時、Unity はノッチ付きのデバイスをサポートしていなかったため、UnityEngine.Screen.safeArea パラメーターに基づいてカスタム ソリューションを作成する必要がありました。これにより、UI が強制的にスケーリングされ、電話画面上のさまざまなセーフ ゾーンが回避されます。


さらに、2017 年には、別のことに挑戦することにしました。ゲームの VR バージョンを Steam でリリースするというものです。開発には約 6 か月かかり、当時入手可能なすべてのヘルメット (Oculus、HTC Vive、Windows Mixed Reality) でのテストも行われました。この作業は、Oculus API と Steam API を使用して実行されました。さらに、PS VR ヘッドセットのデモ バージョンと MacOS のサポートも準備されました。


技術的な観点からは、安定した FPS (PS VR の場合は 60 FPS、HTC Vive の場合は 90 FPS) を維持する必要がありました。これを実現するために、標準的なフラスタムとオクルージョン、および再投影 (一部のフレームが以前のフレームに基づいて生成される場合) に加えて、自己スクリプト化されたゾーン カリングが使用されました。


乗り物酔いの問題を解決するために、興味深い創造的かつ技術的な解決策が採用されました。プレイヤーはロボットのパイロットになり、コックピットに座ります。キャビンは静的な要素であるため、脳はそれを世界におけるある種の定数として認識し、そのため空間内での動きが非常にうまく機能しました。


また、このゲームには、Cinemachine が Unity のそのバージョンではまだ利用できなかったため、いくつかの個別のトリガー、スクリプト、および自作のタイムラインの開発を必要とするシナリオもありました。


各武器について、ターゲティング、ロック、追跡、自動照準のロジックがゼロから作成されました。


このバージョンは Steam でリリースされ、プレイヤーから好評を博しました。しかし、Kickstarter キャンペーンの後、VR 向けの本格的な PvP シューティング ゲームの開発には技術的なリスクが伴い、市場もそのようなプロジェクトに対応できていないことから、プロジェクトの開発を継続しないことに決定しました。


最初の深刻なバグへの対処

ゲームの技術的要素の改善、および新しいメカニズムやプラットフォームの開発と開発に取り組んでいる間、新しいプロモーションを開始したときに収益に悪影響を与える、ゲームで最初の重大なバグに遭遇しました。問題は、「価格」ボタンが誤って「賞品」としてローカライズされていたことです。ほとんどのプレイヤーはこれに混乱し、実際の通貨で購入してから払い戻しを求めました。


技術的な問題は、当時、すべてのローカリゼーションがゲーム クライアントに組み込まれていたことです。この問題が発生したとき、ローカリゼーションを更新できるソリューションの作業をこれ以上先延ばしにできないことがわかりました。こうして、CDN と、CDN へのローカリゼーション ファイルのアップロードを自動化する TeamCity のプロジェクトなどの付随ツールに基づくソリューションが作成されました。


これにより、使用したサービス (POEditor) からローカリゼーションをダウンロードし、生データを CDN にアップロードできるようになりました。

その後、サーバー プロファイルは、ローカリゼーション データに対応するクライアントの各バージョンのリンクの設定を開始しました。アプリケーションが起動されると、プロファイル サーバーはこのリンクをクライアントに送信し始め、このデータがダウンロードされてキャッシュされました。


データを使った作業の最適化

時は流れ、2018 年。プロジェクトが拡大するにつれ、サーバーからクライアントに転送されるデータの量も増加しました。サーバーに接続する際には、残高や現在の設定など、かなりの量のデータをダウンロードする必要がありました。


現在のデータは XML 形式で提示され、標準の Unity シリアライザーによってシリアル化されました。

クライアントの起動時やプロファイル サーバーおよびゲーム サーバーとの通信時に、かなり大量のデータを転送するだけでなく、プレイヤー デバイスは現在の残高を保存し、それをシリアル化/デシリアル化するために大量のメモリを消費しました。


アプリケーションのパフォーマンスと起動時間を改善するには、代替プロトコルを見つけるための研究開発を行う必要があることが明らかになりました。


テスト データに関する調査の結果は次の表に示されています。


プロトコル

サイズ

割り当て

時間

テキスト

2.2MB

18.4MB

518.4ミリ秒

MessagePack(契約なし)

1.7MB

2MB

32.35ミリ秒

MessagePack (文字列キー)

1.2MB

1.9MB

25.8ミリ秒

メッセージパック (int キー)

0.53MB

1.9

16.5

フラットバッファ

0.5MB

216B

0 ミリ秒 / 12 ミリ秒 / 450 KB


結果として、特に整数キーで MessagePack を使用する場合、同様の出力結果を持つ FlatBuffers に切り替えるよりも移行の方が安価であったため、MessagePack 形式を選択しました。


FlatBuffers (およびプロトコル バッファ) の場合、メッセージ形式を別の言語で記述し、C# および Java コードを生成し、生成されたコードをアプリケーションで使用する必要があります。クライアントとサーバーのリファクタリングという追加コストを負担したくなかったため、MessagePack に切り替えました。


移行はほぼシームレスで、最初のリリースでは、新しいシステムに問題がないと確信できるまで XML にロールバックする機能をサポートしました。新しいソリューションはすべてのタスクをカバーし、クライアントの読み込み時間を大幅に短縮し、サーバーへのリクエストを行う際のパフォーマンスも向上しました。


私たちのプロジェクトの各機能や新しい技術的ソリューションは、「フラグ」の下でリリースされます。このフラグはプレーヤーのプロファイルに保存され、ゲームの開始時にバランスとともにクライアントに表示されます。原則として、新しい機能、特に技術的な機能がリリースされると、いくつかのクライアント リリースに古い機能と新しい機能の両方が含まれます。新しい機能のアクティブ化は、上記のフラグの状態に従って厳密に行われるため、特定のソリューションの技術的な成功をリアルタイムで監視および調整できます。


徐々に、プロジェクトの依存性注入機能を更新する時期が来ました。現在の機能は、多数の依存性に対処できなくなり、場合によっては、解除やリファクタリングが非常に困難な、わかりにくい接続が導入されました。(これは、何らかの形で UI に関連するイノベーションに特に当てはまりました。)


新しいソリューションを選ぶとき、選択肢は簡単でした。他のプロジェクトで実績のある、よく知られている Zenject です。このプロジェクトは長い間開発されており、積極的にサポートされ、新しい機能が追加されており、チーム内の多くの開発者が何らかの形でこのプロジェクトに精通していました。


私たちは少しずつ、Zenject を使用して War Robots を書き直し始めました。新しいモジュールはすべて Zenject で開発され、古いモジュールは徐々にリファクタリングされました。Zenject を使用することで、先ほど説明したコンテキスト (戦闘と格納庫) 内でのサービスの読み込みシーケンスがより明確になり、開発者はプロジェクトの開発に簡単に取り組めるようになり、これらのコンテキスト内で新しい機能をより自信を持って開発できるようになりました。


Unity の比較的新しいバージョンでは、async/await を介して非同期コードを操作できるようになりました。私たちのコードではすでに非同期コードが使用されていましたが、コードベース全体で単一の標準がありませんでした。Unity スクリプティング バックエンドが async/await をサポートするようになったため、R&D を実施して非同期コードへのアプローチを標準化することにしました。


もう 1 つの動機は、コードからコールバック地獄を取り除くことでした。これは、非同期呼び出しの連続チェーンがあり、各呼び出しが次の呼び出しの結果を待機する場合です。


当時は、RSG や UniRx など、いくつかの一般的なソリューションがありましたが、それらをすべて比較して 1 つの表にまとめました。



RSG.Promise

TPLLについて

TPL 待機中

ユニタスク

非同期のUniTask

終了までの時間、s

0.15843

0.1305305

0.1165172

0.1330536

0,1208553

最初のフレーム 時間/自分、ミリ秒

105.25/82.63

13.51/11.86

21.89/18.40

28.80/24.89

19.27/15.94

最初のフレームの割り当て

40.8MB

2.1MB

5.0MB

8.5MB

5.4MB

2 番目のフレームの時間/自分、ミリ秒

55.39/23.48

0.38/0.04

0.28/0.02

0.32/0.03

0.69/0.01

2番目のフレームの割り当て

3.1MB

10.2KB

10.3KB

10.3KB

10.4KB


最終的に、ほとんどの開発者が使い慣れている非同期 C# コードを操作する標準として、ネイティブの async/await を使用することに決めました。プラグインの利点がサードパーティ ソリューションに依存する必要性をカバーしなかったため、UniRx.Async を使用しないことにしました。


私たちは、必要最小限の機能という道を進むことを選択しました。RSG.Promise やホルダーの使用を断念したのは、まず第一に、新しい開発者にこれらの、通常は馴染みのないツールを扱えるようにトレーニングする必要があり、第二に、RSG.Promise やホルダーで非同期タスクを使用するサードパーティ コードのラッパーを作成する必要があったためです。async/await の選択は、会社のプロジェクト間で開発アプローチを標準化するのにも役立ちました。この移行により、私たちの問題は解決しました。非同期コードを扱うための明確なプロセスが確立され、サポートが難しいコールバック地獄がプロジェクトから排除されました。


UI は徐々に改善されました。私たちのチームでは、新機能の機能はクライアントのプログラマーによって開発され、レイアウトとインターフェースの開発は UI/UX 部門によって行われるため、同じ機能の作業を並行して行うことができるソリューションが必要でした。つまり、レイアウト デザイナーがインターフェースを作成してテストし、プログラマーがロジックを記述できるようにすることでした。


この問題の解決策は、インターフェースを操作する MVVM モデルへの移行にありました。このモデルにより、インターフェース デザイナーはプログラマーを介さずにインターフェースを設計できるだけでなく、実際のデータがまだ接続されていないときに、インターフェースが特定のデータにどのように反応するかを確認することもできます。既成のソリューションを調査し、Pixonic ReactiveBindings と呼ばれる独自のソリューションを迅速にプロトタイプ化した後、次の結果を含む比較表を作成しました。



CPU時間

メモリ割り当て

メモリ使用状況

ペパーミントデータバインディング

367 ミリ秒

73KB

17.5MB

ディスプレイファブ

223 ミリ秒

147KB

8.5MB

ユニティウェルド

267 ミリ秒

90KB

15.5MB

Pixonic リアクティブバインディング

152ミリ秒

23KB

3MB


新しいシステムが、主に新しいインターフェースの作成を簡素化するという点でその有効性が実証されるとすぐに、私たちはすべての新しいプロジェクトと、プロジェクトに登場するすべての新機能にそのシステムを使い始めました。


新世代のモバイルデバイス向けにゲームをリマスター

2019 年までに、Apple と Samsung からグラフィックの面で非常に強力なデバイスがいくつかリリースされたため、当社は War Robots を大幅にアップグレードするというアイデアを思いつきました。私たちは、これらすべての新しいデバイスのパワーを活用し、ゲームのビジュアル イメージを更新したいと考えました。


更新されたイメージに加えて、更新された製品にはいくつかの要件もありました。60 FPS のゲーム モードをサポートし、デバイスごとに異なる品質のリソースをサポートする必要がありました。


現在の品質マネージャーも、ブロック内の品質の数が増え、その場で切り替えられるため生産性が低下し、膨大な数の組み合わせが作成され、それぞれをテストする必要があり、リリースごとに QA チームに追加コストがかかるため、作業のやり直しが必要でした。


クライアントの作り直しで最初に取り組んだのは、シューティングのリファクタリングでした。元の実装では、ゲーム エンティティとクライアントでのその視覚的表現が 1 つの同じオブジェクトであったため、フレームのレンダリング速度に依存していました。私たちは、ショットのゲーム エンティティがその視覚的表現に依存しないようにこれらのエンティティを分離することに決め、これにより、異なるフレーム レートのデバイス間でより公平なプレイが実現しました。


ゲームでは多数のショットを扱いますが、これらのデータを処理するアルゴリズムは非常に単純です (移動、敵にヒットしたかどうかの判断など)。エンティティ コンポーネント システムのコンセプトは、ゲーム内の発射物の移動のロジックを整理するのに最適であったため、これを採用することにしました。


さらに、すべての新しいプロジェクトで、ロジックを扱うために ECS をすでに使用していたため、このパラダイムをメイン プロジェクトに適用して統合する時期が来ていました。作業の結果、重要な要件である、60 FPS で画像を実行できるようにするという要件が実現しました。ただし、戦闘コードがすべて ECS に転送されたわけではないため、このアプローチの可能性を十分に実現することはできませんでした。最終的には、期待したほどパフォーマンスは向上しませんでしたが、低下することもありませんでした。これは、このような強力なパラダイムとアーキテクチャのシフトにおいて、依然として重要な指標です。


同時に、新しいグラフィック スタックでどのようなレベルのグラフィックを実現できるかを確認するために、PC 版の開発を開始しました。当時はまだプレビュー版で、絶えず変化していた Unity SRP を活用し始めました。Steam 版で公開された画像は非常に印象的でした。



さらに、上の画像に示されているグラフィック機能の一部は、強力なモバイル デバイスに転送できます。これは特に、歴史的に優れたパフォーマンス特性、優れたドライバー、ハードウェアとソフトウェアの緊密な組み合わせを備えた Apple デバイスの場合に当てはまります。これにより、私たち側で一時的な解決策を講じなくても、非常に高品質の画像を作成できます。


グラフィック スタックを変更するだけではイメージは変わらないことがすぐにわかりました。また、高性能なデバイスだけでなく、低性能なデバイス向けのコンテンツも必要であることも明らかになりました。そこで、さまざまな品質レベル向けのコンテンツを開発する計画を立て始めました。


つまり、メカ、銃、マップ、エフェクト、およびそれらのテクスチャは品質ごとに分離する必要があり、品質ごとに異なるエンティティが必要になります。つまり、HD 品質で動作する物理モデル、テクスチャ、およびメカ テクスチャ セットは、他の品質で動作するメカとは異なります。


さらに、ゲームはマップに大量のリソースを費やしており、新しい品質に準拠するにはマップも作り直す必要があります。また、現在の品質マネージャーはアセットの品質を管理していないため、私たちのニーズを満たしていないことも明らかになりました。


そこで、まず、ゲームで利用できる品質を決定する必要がありました。現在の品質マネージャーの経験を考慮して、新しいバージョンでは、特定のデバイスで利用できる最高の品質に応じて、ユーザーが設定で個別に切り替えることができるいくつかの固定品質が必要であることがわかりました。


新しい品質システムは、ユーザーが所有するデバイスを判別し、デバイス モデル (iOS の場合) と GPU モデル (Android の場合) に基づいて、特定のプレーヤーに利用可能な最高品質を設定できます。この場合、この品質だけでなく、以前のすべての品質も利用できます。


また、各品質ごとに最大 FPS を 30 と 60 の間で切り替える設定があります。当初は 5 つの品質 (ULD、LD、MD、HD、UHD) 程度を予定していましたが、開発の過程で、これだけの品質数では開発に非常に長い時間がかかり、QA の負荷を軽減できないことが明らかになりました。これを考慮して、最終的にゲームでは HD、LD、ULD の品質になりました。(参考までに、これらの品質でプレイしている現在の視聴者の分布は次のとおりです。HD - 7%、LD - 72%、ULD - 21%)。


より多くの品質を実装する必要があることがわかってすぐに、それらの品質に応じてアセットを分類する方法を検討し始めました。この作業を簡素化するために、アーティストが最高品質 (HD) のアセットを作成し、スクリプトやその他の自動化ツールを使用してこれらのアセットの一部を簡素化し、他の品質のアセットとして使用するというアルゴリズムを採用しました。


この自動化システムの開発過程で、私たちは以下のソリューションを開発しました。

  • アセットインポーター – テクスチャに必要な設定を行うことができます
  • Mech Creator – Unity プレハブ バリアントに基づいて複数のメカ バージョンを作成し、品質とテクスチャの設定を対応するプロジェクト フォルダーに配布できるツールです。
  • テクスチャ配列パッカー – テクスチャをテクスチャ配列にパックできるツール
  • 品質マップクリエーター – ソースUHD品質マップから複数の品質マップを作成するツール


既存のメカとマップのリソースをリファクタリングするために多くの作業が行われました。元のメカはさまざまな品質を考慮して設計されていなかったため、単一のプレハブに保存されていました。リファクタリング後、主にロジックを含む基本パーツがそこから抽出され、プレハブバリアントを使用して、特定の品質のテクスチャを持つバリアントが作成されました。さらに、品質に応じてテクスチャストレージフォルダーの階層を考慮して、メカをさまざまな品質に自動的に分割できるツールを追加しました。


特定のデバイスに特定のアセットを配信するためには、ゲーム内のすべてのコンテンツをバンドルとパックに分割する必要がありました。メイン パックには、ゲームの実行に必要なアセット、すべての機能で使用されるアセット、および各プラットフォーム用の品質パック (Android_LD、Android_HD、Android_ULD、iOS_LD、iOS_HD、iOS_ULD など) が含まれています。


アセットをパックに分割できるのは、プラットフォーム チームが作成した ResourceSystem ツールのおかげです。このシステムにより、アセットを個別のパッケージに収集し、クライアントに埋め込んだり、個別に取り出して CDN などの外部リソースにアップロードしたりできるようになりました。


コンテンツを配信するために、プラットフォーム チームによって作成された新しいシステム、いわゆる DeliverySystem を使用しました。このシステムを使用すると、ResourceSystem によって作成されたマニフェストを受信し、指定されたソースからリソースをダウンロードできます。このソースは、モノリシック ビルド、個別の APK ファイル、またはリモート CDN のいずれかになります。


当初、リソース パックの保存には Google Play (Play Asset Delivery) と AppStore (On-Demand Resources) の機能を使用する予定でしたが、Android プラットフォームでは、自動クライアント更新に関連する問題や、保存できるリソースの数に制限がありました。


さらに、社内テストの結果、CDN を使用したコンテンツ配信システムが最も効果的かつ安定していることが判明したため、ストアでのリソースの保存を中止し、クラウドに保存するようになりました。


リマスター版のリリース

リマスター版の主な作業が終わり、いよいよリリースの時が来ました。しかし、市場に出回っている多くの人気ゲームでは、5~10 GB のデータのダウンロードが必要なのに、当初計画していた 3 GB というサイズではダウンロード体験が不十分であることがすぐに分かりました。リマスター版ゲームを市場にリリースする頃には、ユーザーはこの新しい現実に慣れているだろうと予想していましたが、残念ながらそうはなりませんでした。


つまり、プレイヤーはモバイル ゲーム用のこのような大容量ファイルに慣れていなかったのです。この問題の解決策を早急に見つける必要がありました。この後、数回のイテレーションを経て HD 品質のないバージョンをリリースすることにしましたが、その後もユーザーに提供しました。


左 – リマスター前、右 – リマスター後


リマスターの開発と並行して、プロジェクト テストの自動化にも積極的に取り組みました。QA チームは、プロジェクトのステータスを自動的に追跡できるように素晴らしい仕事をしてくれました。現在、ゲームが実行される仮想マシンを備えたサーバーがあります。独自に作成したテスト フレームワークを使用して、スクリプトでプロジェクト内の任意のボタンを押すことができます。また、デバイス上で直接テストするときに、同じスクリプトを使用してさまざまなシナリオを実行します。


当社はこのシステムの開発を続けています。安定性、パフォーマンス、ロジックの正しい実行を確認するために、数百の常時実行テストがすでに作成されています。結果は特別なダッシュボードに表示され、当社の QA スペシャリストが開発者と協力して、最も問題のある領域を詳細に調べることができます (テスト実行の実際のスクリーンショットを含む)。


現在のシステムを運用する前に、回帰テストに多くの時間がかかりました (プロジェクトの古いバージョンでは約 1 週間)。また、ボリュームとコンテンツの量の点でも、現在のバージョンよりもはるかに短いものでした。しかし、自動テストのおかげで、ゲームの現在のバージョンは 2 晩だけテストされています。これはさらに改善できますが、現時点では、システムに接続されているデバイスの数によって制限されています。


リマスターの完成に向けて、Apple チームから連絡があり、新しいグラフィックスを使用して新しい Apple A14 Bionic チップ (2020 年秋に新しい iPad とともにリリース) の機能をデモンストレーションするための新製品プレゼンテーションに参加する機会が与えられました。このミニ プロジェクトの作業中に、Apple チップで 120 FPS で実行できる、完全に機能する HD バージョンが作成されました。さらに、新しいチップのパワーをデモンストレーションするために、いくつかのグラフィックの改善が追加されました。


競争が激しく、かなり厳しい選考の結果、私たちのゲームは Apple イベントの秋のプレゼンテーションに選ばれました。チーム全員が集まってこのイベントを観賞し、祝いました。本当に最高でした!



Photon を放棄し、WorldState アーキテクチャに移行します。

2021 年にゲームのリマスター版がリリースされる前から、新たな課題が浮上していました。多くのユーザーからネットワークの問題について苦情が寄せられていましたが、その根本原因は、当時の当社の現在のソリューションである Photon Server SDK で動作するために使用されていた Photon トランスポート層でした。もう 1 つの問題は、ランダムな順序でサーバーに送信される、標準化されていない大量の RPC が存在することでした。


さらに、ワールドの同期や試合開始時のメッセージ キューのオーバーフローにも問題があり、大きな遅延が発生する可能性がありました。


この状況を改善するために、ネットワーク マッチ スタックを、RPC 呼び出しではなくパケットを介してサーバーとの通信が行われ、ゲームの状態が受信される、より従来的なモデルに移行することにしました。


新しいオンライン マッチ アーキテクチャは WorldState と呼ばれ、ゲームプレイから Photon を排除することを目的としていました。

この新しいアーキテクチャでは、LightNetLib ライブラリに基づいてトランスポート プロトコルを Photon から UDP に置き換えるだけでなく、クライアント サーバー通信システムの合理化も行われました。


この機能に取り組んだ結果、サーバー側のコストが削減され(Windows から Linux に切り替え、Photon Server SDK ライセンスを放棄)、ユーザーのエンドデバイスに対する要求が大幅に軽減されたプロトコルが実現し、サーバーとクライアント間の状態の非同期化の問題が減り、新しい PvE コンテンツを開発する機会が生まれました。


ゲームコード全体を一晩で変更することは不可能であるため、WorldState の作業はいくつかの段階に分割されました。


最初の段階では、クライアントとサーバー間の通信プロトコルを完全に再設計し、メカの動きを新しいレールに移行しました。これにより、ゲームの新しいモードである PvE を作成できました。徐々に、特に最新のメカ (メカへのダメージとクリティカル ダメージ) がサーバーに移行し始めました。古いコードを WorldState メカニズムに段階的に移行するための作業は継続しており、今年もいくつかのアップデートが予定されています。


2022 年に、私たちは Facebook Cloud という新しいプラットフォームを立ち上げました。このプラットフォームの背後にあるコンセプトは興味深いものでした。クラウド内のエミュレーターでゲームを実行し、スマートフォンや PC のブラウザーにストリーミングするというものです。エンド プレイヤーがゲームを実行するために強力な PC やスマートフォンを所有する必要はなく、安定したインターネット接続のみが必要です。


開発者側では、プラットフォームが主に使用するビルドとして、Android ビルドと Windows ビルドの 2 種類のビルドを配布できます。私たちはこのプラットフォームでの経験が豊富なため、最初の方法を選択しました。


Facebook Cloud でゲームを起動するには、ゲーム内の認証をやり直したり、カーソル コントロールを追加したりするなど、いくつかの変更を加える必要がありました。また、プラットフォームが CDN をサポートしていなかったため、組み込みリソースをすべて備えたビルドを準備する必要があり、エミュレーターで必ずしも正しく実行できるとは限らない統合を構成する必要がありました。


Facebook エミュレーターは実際の Android デバイスではなく、ドライバーの実装やリソース管理に関して独自の特性を持っていたため、グラフィック スタックの機能を確保するためにグラフィック側でも多くの作業が行われました。


しかし、このプラットフォームのユーザーは、接続が不安定だったり、エミュレーターの動作が不安定だったりと、多くの問題に遭遇したため、Facebook は 2024 年の初めにプラットフォームを閉鎖することを決定しました。




プログラマー側では常に行われていることですが、このような短い記事では詳しく説明できませんが、プロジェクトの技術的リスクに関する定期的な作業、技術メトリックの定期的な監視、メモリとリソースの最適化に関する継続的な作業、パートナー SDK のサードパーティ ソリューションの問題の検索、広告の統合などがあります。


さらに、重大なクラッシュや ANR を修正するための研究と実践的な作業も継続しています。プロジェクトが多数のまったく異なるデバイスで実行される場合、これは避けられません。


また、問題の原因を突き止めるために働く人々の専門性にも注目したいと思います。こうした技術的な問題は複雑な性質を持つことが多く、原因を突き止めるまでに、複数の分析システムから得たデータを重ね合わせたり、重要な実験を行ったりする必要があります。複雑な問題の多くは、一貫して再現可能なテスト可能なケースがないため、経験的データと私たちの専門的な経験が問題の解決によく利用されます。


プロジェクトの問題を見つけるために使用するツールとリソースについて少し説明しておきます。


  • AppMetr – デバイスから匿名データを収集してプレーヤーの問題を調査できる内部分析ソリューション。読者によく知られている類似のツールとしては、Firebase Analytics、Google Analytics、Flurry、GameAnalytics、devtodev、AppsFlyer などがあります。
  • Google Firebase クラッシュリティクス
  • Google Play コンソール – Android Vitals
  • ログ – デバッグビルドのログシステム。スタジオ内のプレイテストで問題を探す手間を最小限に抑えることができます。
  • パブリックテストレルム – 私たちのゲームには、新しい変更をテストしたり、さまざまな技術的な実験を実施したりできるパブリックテストサーバーがあります。
  • Unity プロファイラー
  • XCodeインストゥルメント


これは、プロジェクトが存続する間に行われた技術的改善のほんの一部です。プロジェクトは絶えず発展しており、技術マネージャーは、エンドユーザーと、開発者自身や他の部門を含むスタジオ内で製品を使用する人々の両方のために製品のパフォーマンスを向上させる計画の立案と実装に絶えず取り組んでいるため、達成されたすべてのことをリストすることは困難です。


今後 10 年間で製品にはまだ多くの改善が予定されており、次の記事でそれらを共有できることを願っています。


War Robots、お誕生日おめでとうございます。そして、このすべてを可能にした大規模な技術専門家チームに感謝します!