Action RPG のゲームプレイを C++ で構築する

Action RPG のゲームプレイ システムがどのように構築されているかを説明します。

Windows
MacOS
Linux

本ドキュメントの目的は、Action RPG (ARPG) のゲームプレイ システムがどのように構築されているかを説明し、ユーザーが同様のシステムを構築する際に利用できる例として示すことにあります。本ドキュメントでは、ユーザーが既に UE4 の C++ プログラミング入門 に目を通した上で、 FPS チュートリアル に記載されている既存のテンプレートの 1 つを使用して、基本的なプロトタイプを構築した経験があることを想定しています。アビリティ システムに固有の機能については、 ゲームプレイ アビリティ システム ドキュメントを参照してください。

コードの概要

Unreal Engine 4 (UE4) プロジェクトを始める際は、既存のテンプレートの 1 つを利用するか、既存のサンプル プロジェクトのクローンを使用することがほとんどです。ARPG の場合は、Top Down テンプレートに似たブループリントのみのゲームとして開始して、後にハイブリッドの C++/ブループリント プロジェクトに変換しました。このような経緯があるため、基本的なゲームプレイ ロジックの大部分は C++ ではなくブループリントで実装されています。ブループリントと C++ のバランスを調整する ドキュメントでは、この決定に関連するいくつかの理由について説明しています。最初にプロジェクトを作成して変換した後に、ゲームプレイで使用するネイティブ クラス階層を構築しました。また、C++ コードとコンテンツに対する命名規則およびディレクトリ編成スキームについても作業を進めました。

次は、ARPG で使用されるソース ファイルの概要です。

ファイル名

説明

ActionRPG.h

プロジェクト内のすべての CPP ファイルにより最初に含まれるモジュール ヘッダです。ここに、ほとんどのクラスで必要な共有エンジン ヘッダとすべてのグローバル定義を含めています。

RPGTypes.h

他のクラスで使用されるゲーム特有の構造体および列挙型を定義する共有ヘッダです。一般的には、循環ヘッダ インクルードの問題を回避するために、このヘッダを 1 つ以上作成することが推奨されます。

RPGPlayerControllerBase.h

PlayerController のゲーム特有のサブクラスで、ほぼすべてのゲームで必要です。ARPG では、ほとんどの場合これでインベントリが処理されます。

RPGCharacterBase.h

Character のゲーム特有のサブクラスです。ARPG ではすべての Blueprint Characters がこの 1 つのクラスから継承しますが、多くのゲームでは複数のキャラクター タイプを含む階層が必要となります。

RPGGameInstanceBase.h

GameInstance のゲーム特有のサブクラスで、ほぼすべてのゲームで必要です。ゲーム全体に対して 1 つの Game Instance が宣言されるため、グローバル ゲームプレイ データを保存するのに適した場所です。

RPGGameModeBase.h および RPGGameStateBase.h

Game Mode およびステート サブクラスです。ARPG では、ほとんどのマップ特有のゲームプレイ ロジックはブループリントで作成されているため、これらは単なるスタブとして使用されますが、多くのゲームには C++ コードで作成された複数のモードおよびステートが含まれます。

RPGBlueprintLibrary.h

特定のアクタに結び付けられていない、ゲーム特有のブループリント関数を公開します。ほとんどすべてのゲームでこれが 1 つ以上必要になります。

RPGSaveGame.h

inventory/experienceinformation をディスクに保存する際に使用されるクラスです。詳細は後のセクションに記載されています。

RPGAssetManager.h

後述のインベントリ システムで使用される AssetManager のサブクラスです。

RPGInventoryInterface.h

RPGCharacterBase を有効にして、手動キャストなしでインベントリに関する RPGPlayerControllerBase へのクエリを実行するネイティブ インターフェースです。

Items/RPGItem.h およびサブクラス

異なるインベントリ アイテムのタイプです。

Abilities/RPGAbilitySystemComponent およびその他

Action RPG のゲームプレイ アビリティ に記載されているようにアビリティ システムで使用されます。

ActionRPGLoadingScreen Module

ゲームの初期ロード時またはマップの転送時に、Texture の表示に使用されるシンプルな C++ ロード画面です。これは、主な ARPG ゲーム モジュールの前にロードされる必要があるため、別のモジュールとなります。

ARPG にはありませんが、その他多くの Unreal Engine 4 (UE4) ゲームには、UE4 Editor で使用される追加の UI またはツールを追加する Editor Module も含まれています。

ネイティブ クラスを作成したら、適切な Game ModeGame Instance および アセット管理 クラスをスポーンするよう Project Settings (プロジェクト設定) を変更する必要があります。また、新しい変更をプロジェクトに反映させるために、マップ設定を変更しなければならない場合もあります。

インベントリおよび Asset Manager

ARPG ではインベントリ アイテムのロードとアクセスに アセット管理 システムを使用します。Asset Manager は、本来は複数の異なる状況およびゲーム全体において使用可能なアセットの管理を目的として設計されており、通常はすべてのインベントリ アイテムに対しても同様に使用することができます。ARPG には、次の 4 つのタイプのインベントリ アイテムがあります。

  • 武器 :プレイヤーによって装備可能な、メレー ダメージを起こすブループリントです。

  • スキル :直接的なエフェクト ダメージおよびその領域に対処するために、プレイヤーによる装備と使用が可能な、ファイアボールなどの特別攻撃です。

  • ポーション : 治癒とマナの増加に使用される、一度限りの消耗アイテムです。

  • トークン :獲得ソウル数や経験値などのデータを追跡するシンプルなカウンタです。

これらの各アイテム タイプには、 URPGItem から継承する独自のネイティブ C++ クラスが含まれており、 「 DefaultGame.ini 」AssetManagerSettings セクションのラインを使用して定義されます。ARPG では、アイテムは独自のロジックまたは継承構造を持たないため、アイテムをブループリントで作成していませんが、これはゲームによって異なります。それぞれのアイテム ベース クラスでは、使用するアイコンなどの UI 情報や、特定のアイテムを装備した場合に与えられるアビリティなどのゲームプレイ情報が提供されます。

プレイヤーが所有するアイテムの情報は、次の 2 つのマップ プロパティに含まれる URPGPlayerControllerBase インスタンスに保存されます。

  • 最初のマップは URPGItem から FRPGItemData へのもので、カウントおよびレベルを保存します。 

  • 2 番目のマップは FRPGItemSlot から URPGItem へのもので、特定のアイテムが「 weapon slot 1 」に保存されていることを示します。

有効なアイテム スロットのリストおよびデフォルトのインベントリは BP_GameInstance に保存されます。Player Controller ネイティブ クラスでは、インベントリ アイテムの追加、削除およびクエリを実行する API が提供され、さらにアビリティ システムとのインタラクションも行います。ARPG に含まれる各アイテム タイプはプライマリ アセット タイプであるため、 FPrimaryAssetType 構造の目的を変更して、フィルタ関数に渡される独自の「アイテム タイプ」としました。 ARPG ではゲーム内での保存が行われるため、スタートアップ時にはゲーム内のすべてのアイテムを事前にロードする必要があります。これは、 BP_GameInstance から次のロジックを使用して行われます。

クリックしてフルサイズで表示

AsyncLoadPrimaryAssetList ノードは最終的に URPGAssetManager の LoadPrimaryAssets 関数を呼び出し、これによって特定のタイプのすべてのアイテムの非同期ロードが開始されます。ロードが完了すると、ゲーム インスタンスに保存されている、ストア UI によって使用されるマップにこれらが追加されます。ここで重要なのは、これらのアセットを参照するものがない場合であっても、 LoadPrimaryAssets を呼び出すことで、 Unload が呼び出されるまでこれらのアセットがメモリ内に維持されることです。 RPGAssetManager は、各アイテム タイプのいくつかの静的なタイプと、インベントリのディスクからのロード時に使用される ForceLoadItem 関数を宣言するだけであるため、比較的シンプルなサブクラスです。

ARPG では、インベントリ アイテムを使用するためのロジックのほとんどは、プレイヤーと敵のブループリントの両方で共有される BP_Character ブループリントに含まれていますが、多くのゲームではアイテムの使用はネイティブ C++ で実装されます。また、インベントリはアビリティ システムと非常に頻繁に相互作用します。この詳細については、 ゲームプレイ アビリティ システム ドキュメントを参照してください。

ゲーム保存

ARPG ではネイティブ構造を使用して、 URPGSaveGame クラスでプレイヤーのインベントリ (souls/experience を含む) をディスクに保存します。ネイティブのバージョン体系および修正コードを利用できるめ、重要な情報はネイティブ構造を使用して保存することが一般的です。URPGSaveGame は、 ERPGSaveGameVersion 列挙型関数と、Serialize 関数の修正コードを使用して実装されます。これは、ユーザー定義の構造体であると、誤って変更されてしまう危険性が常にあるためです。デベロッパーがフィールドの名前を変更または削除しようとした場合、プレイヤーのゲーム保存データが失われて、プレイヤーの保存済みデータが完全に破損する危険性があります。一般的には、重要なデータはバージョン体系を含むネイティブ構造を使用して実装することをお勧めします。

ARPG のゲーム保存では、 PrimaryAssetIds を使用してインベントリを保存します。これは、文字列として ItemType:ItemName のフォーラム タイプと共に保存されています。この方法は、アセットが移動された後でもその参照は壊れないため、アイテム参照の保存において 「 /Game/Items/ItemName.ItemName 」 などのアセット パスよりも安定した方法と言えます。アセットの名前が変更された場合は、 PrimaryAssetIdRedirects またはネイティブ コードを使用してこれらの修正を処理することができます。ForceLoadItem は、URPGItem がメモリにない場合 (ARPG では前述の Store の事前ロードの理由で、通常はこの状況) に、同時ロードによる PrimaryAssetId から URPGItem への変換に使用されます。

URPGGameInstanceBase では、 BP_GameInstance で設定されている変数を使用して、インベントリの実際の保存およびロードを処理します。 Player Controller では、インベントリにアイテムが追加または削除された際にインベントリを保存するよう強制するため、ネイティブ コードからアクセス可能な Save 関数を含めることが重要です。必要に応じてブループリントから手動で呼び出すことも可能です。ARPG では、保存は SaveGameToSlot ブループリント関数を使用してディスクに書き込まれますが、これをネイティブに実装することで、後にサーバーサイドのソリューションに変更することも可能になります。[Options] メニューでは、データが失われた場合でもあまり重要ではないため、ネイティブのゲーム保存の実装は使用されません。また、この情報は常にローカル デバイスに保存することを推奨します。 

ゲーム保存の管理については、ゲーム開発の早期段階から十分に考慮して計画を立てる必要があります。

リリース向けのパッケージング

ゲームプレイ インフラの構築が完了し、チームによるコンテンツ制作が開始されたら、最後の重要なプログラミング タスクとして、ゲームのパッケージングに向けて準備し、デフォルトで UE4 パッケージとしてリリースする作業があります。UE4 パッケージにはリリースするビルドで必要なものよりも多くのコンテンツを含めることができますが、モバイルなどのプラットフォームではこれが問題となる場合があります。ARPG では、最初に ARPG が必要なコンテンツのみを含んでいることを確認しました。このタスクには アセット管理 を使用しました。 

「 Primary Asset Type 」 コンフィギュレーション ファイルの 「 CookRule=AlwaysCook 」 セクションにより、プロジェクトの 「 Content 」 フォルダに含まれるすべてのアイテムが最終ゲームにクックされます。Main Menu および Gameplay マップが確実に ARPG に含まれるよう、両方のマップを Packaging Settings の +MapsToCook ラインに含めました。ARPG にすべての必要なコンテンツが含まれていることを確認した後に、プロジェクトをモバイル プラットフォーム向けに UE4 Editor 内からパッケージ化しました。これで、すべてが期待通りに機能することを検証できました。パッケージ化したゲームが適切に機能することと、プロジェクトのすべてのコンテンツが含まれていることを検証した後に、ダウロードおよびメモリのサイズを削減するための方法をいくつか検討しました。ARPG はモバイル プラットフォームを対象としているため、ダウンロードおよびメモリのサイズを可能な限り小さくなるようにしたいと考えました。このため、次のステップでインストール サイズとメモリ使用量を削減できました。

  1. 使用されていないすべての プラグイン を無効にします。ARPG でこれを行うことで、プロジェクト全体のサイズを 30 MB 削減できました。 ARPG_DisableUnusedPlugins_01.png

    上の図では Augmented Reality プラグインのみが無効になっていますが、最大限削減するには、プロジェクトのすべてのプラグイン セクションでこれを行う必要があります。

  2. [Packaging] 設定にある [Exclude editor content when cooking] フラグをオンにして有効にします。これで、 「 /Engine/EditorMaterials 」 などの UE4 Editor フォルダに含まれるコンテンツがプロジェクトによってシッピングされることを防ぎます。 ARPG_SkipCookingEditorContent_01-1.png

    これを行うことで、これらのマテリアルを使用するゲーム コンテンツが破損することに留意してください。ただし、プロジェクトでは、UE4 Editor フォルダに含まれるアセットは使用されていないはずです。

  3. 「 DefaultEditor.ini 」 ファイル内の +ContentDirectories ラインにより、UE4 ではデフォルトで 「 /Game/UI 」 とその他いくつかのフォルダに含まれるすべてのコンテンツをクックします。ARPG の 「 DefaultEditor.ini 」 ファイルにインクルードを加えることで無効にしたこのフォルダには、ARPG のいくつかのプロトタイプ ユーザー インターフェース アイテムが含まれていました。本ステップと上記のステップを組み合わせることで、ARPG のインストール サイズを 50 MB 削減できました。ARPG_DefaultEditorINI_01.png

  4. [Asset Audit] ウィンドウの [Size Map] ツールを使用することで ( クックとチャンキング ドキュメントを参照)、非常に負荷の高い一連のテクスチャとスタティック メッシュを識別することができました。この情報をコンテンツ チームに伝えて、クリーンアップしてもらいました。これらのアセットを最適化することで、ARPG のインストール サイズをさらに 100 MB 削減できました。ARPG_SizeMapTool_01.png

  5. [Project Settings] > [Packaging] の [For Distribution] チェックマーク ボックスを一時的にオンにして有効にし、 [Build Configuration] を [Development] から [Shipping] に変更して、 ARPG の最終的なサイズがどれくらいになるかを確認します。一般的に、この設定は最終リリース ビルドをクックする段階で行いますが (通常は UAT スクリプトに渡されるコマンドライン オプションを通じて)、開発の段階においては 有効にしないこと を推奨します。Development ビルドから Shipping ビルドに変更することで、ARPG のインストール サイズを約 50 MB 削減できました。 ARPG_ForDistributionSettings_01.png

上記のステップをすべて組み合わせることで、ARPG のインストール サイズを約 230 MB 削減することができ、さまざまなアプリ ストアで ARPG をリリースする準備が整いました。

新しい Unreal Engine 4 ドキュメントサイトへようこそ!

あなたの声を私たちに伝えるフィードバックシステムを含め、様々な新機能について開発をおこなっています。まだ広く使える状態にはなっていないので、準備ができるまでは、ドキュメントフィードバックフォーラムで、このページについて、もしくは遭遇した問題について教えていただけると助かります。

新しいシステムが稼働した際にお知らせします。

フィードバックを送信