画像提供:Joy Way

STRIDE のデベロッパー、Joy Way が明かす VR のクロスプラットフォーム マルチプレイヤーの手法

Artem Tarasov、Joy Way のマルチプレイヤー担当リーダー |
2022年11月16日
こんにちは、Artem Tarasov です。Joy Way でマルチプレイヤー担当のリーダーをしています。

Joy Way は、キプロスの VR ゲーム開発および配信会社です。6 年ほど前から、SteamVR、Meta Quest、PlayStation VR、Pico などの PC およびスタンドアローン VR 向けのプロジェクトにいくつも取り組んでいます。

アクション パルクール VR ゲームである STRIDE の開発はチームにとって挑戦でした。特にクロスプラットフォーム プレイを特徴とするマルチプレイヤー モードが課題となりました。いくつものプラットフォーム、さまざまな入力デバイス、物理ベースの移動、正確な攻撃登録、その他のタスクに対応する必要があったのです。

このブログでは、STRIDE のマルチプレイヤー ゲーム モードの開発中に直面した課題のいくつかに対する解決策について説明します。
 

このブログは、Unreal Engine を活用してクロスプラットフォーム ゲームを開発し、カスタム仕様のバックエンド サービスに接続するためのガイドとして利用することができます。また、C++ブループリント の両方を使用して作業する Unreal のプログラマーにとって役立ちます。

プラットフォーム固有のコードを記述する

クロスプラットフォーム ゲームの開発において、すべてのデベロッパーが最初に直面する課題は、プラットフォーム固有のコードを記述することの必要性です。

最初に挙げられる最も一般的な例としては、プラットフォーム固有のプラグインとモジュールの使用です。Unreal では、個別のモジュールごとにプラットフォームをホワイトリストとブラックリストに登録することができます。
プラグインについては、BlacklistPlatformsSupportedTargetPlatforms、および WhitelistPlatforms を使用して (1 つまたは複数のパラメータを選択して) 同じことを行えます。
C++ の依存関係としてモジュールを使用するためにプラットフォームをホワイトリストまたはブラックリストに登録した後、モジュール名を PublicDependencyModuleNamesPrivateDependencyModuleNames に含める必要があります。その後は、それほど複雑ではなくなります。

最初に、いくつかのプラットフォームでサポートされていないモジュールを除外する必要があります。最も簡単にこれを実行する方法は、モジュールの .Build.cs ファイルで if/else 文を使用することです。

次に例を示します。
次に、プラットフォーム固有のコンパイル フラグを使用する必要があります。次に例を示します。
C++ プリプロセッサ ディレクティブについての詳細は、こちら を参照してください。
STRIDE のマルチプレイヤー マップ

1 つの OS 上で実行されている複数のプラットフォームを処理する

STRIDE の開発時に、ターゲットとする VR プラットフォームのいくつか (Pico および Meta Quest) が Android 上で実行されているという問題に直面しました。それにより、いくつかの問題が起きたのです。それから、Unreal プラットフォームの設定を使用して Pico および Quest の交差する設定値を分離することができなくなりました。デフォルトでは、コードで使用しているプラットフォームを判別することができません。その解決策をお教えします。

設定値の問題は、Unreal Build Tool への -ini 引数の挿入を使用して解決することができます。これを CI/CD ビルド スクリプトに実装し、-ini コンフィギュレーションを Unreal Automation Tool に渡して設定をオーバーライドすることができます。次の形式で渡します。
設定の挿入についての詳細は、こちら を参照してください。また、Unreal Automation Tool を変更して、挿入された設定値をパックされたゲームに適用する方法もあります。詳細は、こちら を参照してください。

これで、設定値を UAT に渡して使用中のプラットフォームを判別することができるようになりました。

次のステップは、Pico および Quest のデバイス向けにプラットフォームの定義を追加することです。ターゲット ルールの GlobalDefinitions とモジュール ルールの PublicDefinitions との違いに注意してください。デフォルトでは、UAT では 2 つのビルドが生成されます。1 つはエディタ用 (ビルド中にコマンドレットを実行するため) で、もう 1 つはターゲット プラットフォーム用です。GlobalDefinitions は、ターゲット全体の定義です。これは、Pico または Quest のプラットフォーム定義を GlobalDefinitions に含めると、コマンドレットの実行に必要なエディタ ビルドにも、不要なプラットフォーム定義が含まれることを意味します。このことを考慮して、モジュール ルールの PublicDefinitions にプラットフォーム定義を配置する必要があります。その方法は次のとおりです。
これで、使い慣れたプリプロセッサ ディレクティブを使用して、C++ コードで使用中のプラットフォームを判別し、BlueprintFunctionLibrary を使用してプラットフォームの確認をブループリントに公開できるようになりました。

ゲームをカスタム仕様のバックエンド サービスに接続する

ここからは、バックエンド サービスの統合へのアプローチについて説明します。バックエンドは複数の HTTP API と WebSocket API で構成されています。HTTP リクエストと WebSocket イベントの実装は非常にシンプルなため、非同期呼び出しをチェーン化するためのアプローチを中心に説明します。
STRIDE のクロスプラットフォーム ハブの様子
私たちは最初に、レスポンスに対してラムダ関数コールバックを使用する API 呼び出しを実装することから始めました。しかし、開始して間もなく、ネスティングされた呼び出しが大量に発生し、コードを保持することが非常に難しくなったのです。そのため、それぞれのリクエストを個別の UBlueprintAsyncActionBase にすることにしました。

ブループリントで UBlueprintAsyncActionBase の自動的に生成されるノードを使用するのは非常に簡単です。プログラミング ガイドは こちら を参照してください。
 
Get Stride Net User Data

ただし、解決すべき重要な問題が残っています。これらのノードをどこで呼び出しますか?場合によってはゲーム内のエンティティで呼び出すことができ、これは良い配置となります。しかし、GameInstance のレベルでの呼び出しはどうでしょうか?その解決策は、拡張された UObject を «Worker» エンティティに使用することです。

Worker は、GameInstanceSubsystems を使用するライフサイクルを制御するための UObject の派生クラスです。サブシステムのプログラミングについての詳細は、こちら を参照してください。GameInstanceSubsystems を使用する必要はありません。また、おそらく LocalPlayerSubsystems を使用する方が、より良い解決策となるでしょう。

Worker を使用すると、呼び出しチェーンの保持が非常に簡単になります。
ここからは UObject の拡張についてわかりやすく説明し、いくつかとっておきのヒントもお教えします。

拡張が必要になるのは主に 1 つだけ、WorldContext でグローバル関数を呼び出す GetWorld です。Worker GetWorld オーバーライドのコード例は、次のとおりです。
CDO の最初のチェックに注意してください。これはより一層、理にかなっています。

Worker の作成のコード例は、次のとおりです。
上述の内容をまとめると、UObject から継承して GetWorld をオーバーライドし、次に C++ Worker から継承し、最後に、Worker のライフサイクル コアで正しいオブジェクトをインスタンス化する必要があります。ブループリントからクラスを取得して正しいオブジェクトをインスタンス化する方法は、次のとおりです。
次は CDO です。ご覧のとおり、GameInstanceSubsystem の構築時に TSubclassOf 変数を割り当てています。ここで、CDO をチェックしないと問題が発生する可能性があります。CDO チェックを行わないとエディタ クラッシュや大きなアセット システムの問題が発生しました。みなさんにもその可能性はあります。

各リクエストを分離し、リクエスト チェーンをブループリント グラフに公開することによって「スパゲティ コード」を取り除くことができ、バックエンドに関連するコードの保持が非常に簡単になりました。その結果、イテレーションが高速化し、バグが減少しました。
当社のゲームや VR ゲーム開発の舞台裏などにご興味がある場合は、Joy Way の Twitter をフォローするか、Discord サーバー にご参加ください。

    今すぐ Unreal Engine を入手しましょう!

    Unreal Engine は、世界で最もオープンで高度な制作ツールです。
    あらゆる機能とソース コード アクセスを完備している Unreal Engine を使用すれば、すぐに制作を開始できます。
    Unreal Engine 5.3 がリリースされました!
    ニュース
    9月6日

    Unreal Engine 5.3 がリリースされました!

    このリリースでは、幅広い多数の改善が加えられ、実験的な新機能も導入され、業界全体のゲーム開発者やクリエイター向けに UE5 の機能と可能性を拡大し続けています。新機能についてご覧ください。
    Unreal Engine 5.3 がリリースされました!
    ニュース

    Unreal Engine 5.3 がリリースされました!

    このリリースでは、幅広い多数の改善が加えられ、実験的な新機能も導入され、業界全体のゲーム開発者やクリエイター向けに UE5 の機能と可能性を拡大し続けています。新機能についてご覧ください。
    中世風ゲーム環境のコンテンツが UE5 向けに更新されました
    技術ブログ
    9月26日

    中世風ゲーム環境のコンテンツが UE5 向けに更新されました

    最新の Unreal Engine の機能を利用するために、中世風ゲーム環境がどのように更新されたかを説明します。UE マーケットプレイスから利用できます。
    中世風ゲーム環境のコンテンツが UE5 向けに更新されました
    技術ブログ

    中世風ゲーム環境のコンテンツが UE5 向けに更新されました

    最新の Unreal Engine の機能を利用するために、中世風ゲーム環境がどのように更新されたかを説明します。UE マーケットプレイスから利用できます。
    モバイルとその他のプラットフォームに本格的なレーシング アクションと最高のグラフィックをもたらした <em>Racing Master</em>
    インタビュー
    9月21日

    モバイルとその他のプラットフォームに本格的なレーシング アクションと最高のグラフィックをもたらした Racing Master

    Racing Master のチームが、ハイエンドなスポーツ カーのリアルな感覚の再現やモバイルと PC 上のゲーム シミュレーターでのクロスプラットフォーム ゲームに向けた Unreal Engine の最適化の取り組みについて語ります。
    モバイルとその他のプラットフォームに本格的なレーシング アクションと最高のグラフィックをもたらした <em>Racing Master</em>
    インタビュー

    モバイルとその他のプラットフォームに本格的なレーシング アクションと最高のグラフィックをもたらした Racing Master

    Racing Master のチームが、ハイエンドなスポーツ カーのリアルな感覚の再現やモバイルと PC 上のゲーム シミュレーターでのクロスプラットフォーム ゲームに向けた Unreal Engine の最適化の取り組みについて語ります。