開始する前に
C++ ベースの Unreal Engine プロジェクトがあることを確認します。
このページは、「一人称視点のカメラ、メッシュ、アニメーションを追加する」の続きですが、データ駆動型のゲームプレイについてのみ学習する場合は、「一人称視点のアドベンチャー ゲームをコーディングする」チュートリアル シリーズの残りの部分とは別にこの手順を進めてもかまいません。
ゲームのデータの整理
データをどのように整理して表すのかは、ゲーム デザインの重要な部分です。 インタラクト可能なアイテムの品質は実にさまざまであり、こうしたアイテムはゲーム内に存在することもあれば、1 つのデータとして存在することもあります。 このようなデータは、各アイテム タイプ用の個別のクラスとブループリントを作成し、さまざまなアクタに分散して伝達することで表すことができます。 ただし、ゲームと保存されているデータの量が増えると、このような処理は非効率的になります。
より優れているアプローチは、データ駆動型のゲームプレイです。 値をハードコーディングするのではなく、ゲームのシステムによって一元管理されている場所でデータを整理します。 データ駆動型のゲームプレイでは、必要なときに必要なものをロードできます。 たとえば、多くのゲームでは、それぞれのキャラクターに場合によっては数百にもなる行を保存するのではなく、システムでダイアログの特定の行を抽出する方が簡単なため、スプレッドシート ドキュメントを使用してダイアログを整理します。
このセクションでは、この手法でカスタム アイテムの作成を開始する方法を学びます。
データ駆動型ゲームプレイの要素
基本的なアイテムのビルドを開始する前に、何によって「アイテム」が定義されるのかを考えることが重要です。 アイテムはプレイヤーがインタラクトするあらゆるものになる可能性があるため、あらゆるタイプのアイテムに対して有効な最小限のプロパティが必要であり、 アイテム データ構造体でこれを設定します。 また、このようなアイテム データを整理して表示するための一元化された場所も必要ですが、 それに関してはデータ テーブル アセットを使用します。
アイテム データ構造体は、アイテムのデータの型を定義するテンプレートとしての役割を果たし、データ テーブルとデータ アセットは、構造体に基づく実際のデータ エントリを保存します。
以下の図に、チュートリアルのこの部分で作成する 4 つのデータ駆動型ゲームプレイの要素を示します。 4 つすべての要素の設定が完了したら、この図を詳しく見直して何をビルドしたのかを要約します。
まず、アイテム データを定義する次の 2 つのファイルを作成します。
ItemData.h:アイテム データ構造体 (FItemData) の宣言のコンテナ。ItemDefinition.h:Unreal Editor でアイテム データを使用できるようにUDataAssetから継承するクラス。
アイテム データ構造体は UObject から継承せず、レベルでインスタンス化できないため、エディタで使用したり参照したりするデータ アセット クラスも必要です。
そのため Unreal Editor で、ItemDefinition に基づくデータ テーブルとデータ アセット インスタンスを作成します。
アイテム データを定義する
アイテム データ構造体は、データ テーブルの各アイテムに必要なデータやプロパティを定義し、テーブルの縦列のような役割を果たします。
アイテム データ構造体には、次のプロパティがあります。
ID:後でテーブル横列を参照するときに役立つ、アイテムの一意の名前。
アイテム タイプ:このアイテムのタイプ (このケースでは、ツールおよび消費アイテム タイプを定義します)。
アイテム テキスト:名前と説明を含む、アイテムに関するテキスト データ。
アイテム ベース:このアイテムに関連する ItemDefinition データ アセット。
独自のテーブル フィールド (縦列) を作成する場合は、データ テーブル フィールドが UPROPERTY() と互換性のあるあらゆる型になる可能性があるということを覚えておいてください。
構造体のヘッダ ファイル コンテナを作成する
アイテム データ構造体の定義を保存するための新しいフォルダと新しいヘッダ (.h) ファイルを設定します。
ItemDefinition.h 内に FItemData 構造体を作成することはできますが、構造体を別のファイルに入れるとデータ要素を整理しやすくなり、再利用が可能になります。
アイテム データ構造体のコンテナとしてヘッダ ファイルを設定するには、次の手順を実行します。
Unreal Editor で、[Tools] > [New C++ Class] の順に移動します。
[Choose Parent Class] ウィンドウで、親クラスとして [None (なし)] を選択してから [Next] をクリックします。
[Path] の横にあるフォルダ アイコンをクリックします。
「Source/[ProjectName]」フォルダで、このクラスを保存する「Data」という新しいフォルダを作成します。クラスに
ItemDataという名前を付けて [Create Class] をクリックします。Unreal Engine で新しいクラス ファイルが自動的に開かれない場合は、Visual Studio でプロジェクトと
ItemData.hを開きます。ItemData.cppのすべてのテキストを削除してから、ファイルを保存して閉じます。 これを使用することはありません。ItemData.hで、#include “CoreMinimal.h”行の下のすべての項目を 削除します。CoreMinimal.hヘッダには、FNameやFStringのような基本的な型と、データを定義するのに必要なその他の型が含まれています。ItemData.hの上部で、#pragma onceと次の include 文を追加します。#include “Engine/DataTable.h”:構造体にFTableRowBaseを継承させるために必要です。#include “ItemData.generated.h”:Unreal ヘッダ ツールで必要です。 コードが適切にコンパイルされるように、この include 文は必ず最後に来るようにします。
C++#pragma once #include "CoreMinimal.h" #include "Engine/DataTable.h" #include "ItemData.generated.h"UItemDefinitionというクラスの前方宣言を追加します。 これはエディタでの作業に使用できるデータ アセットになります。C++class UItemDefinition;
アイテム プロパティを定義する
アイテム タイプとテキスト データの既存の変数型はないため、定義する必要があります。
アイテム タイプの列挙型を定義するには、次の手順を実行します。
使用可能なすべてのアイテム タイプをリストする新しい
enum classを作成します。 このチュートリアルでは、ツールおよび消費アイテム タイプのアイテムを作成します。列挙型クラスに
EItemTypeという名前を付け、型uint8を指定します。UENUM()マクロを上に追加して、この列挙型を Unreal Header Tool に宣言します。C++// Defines the type of the item. UENUM() enum class EItemType : uint8 { };この列挙型に 2 つのカスタム値を追加します。
Toolは、UMETA()マクロをDisplayName= “ツール”で追加します。Consumableは、UMETA()マクロをDisplayName= “消費アイテム”で追加します。
C++// Defines the type of the item. UENUM() enum class EItemType : uint8 { Tool UMETA(DisplayName = "Tool"), Consumable UMETA(DisplayName = "Consumable") };
これらのアイテム タイプはカスタムであり、Unreal Engine に組み込まれていません。そのため、基本を習得すれば、好きなものを何でも作成できます。 (QuestItem、Currency、Disguise など)
アイテム テキスト構造体を定義するには、次の手順を実行します。
EItemTypeのあとに、USTRUCT()マクロで「FItemText」という名前の新しい構造体を作成します。 この構造体は、アイテムに関するテキスト データを保持します。C++// Contains textual data about the item. USTRUCT() struct FItemText { };FItemText内に、GENERATED_BODY()マクロを追加します。次に、このアイテムの名前と説明を格納するために「
Name」と「Description」という名前の 2 つのFTextプロパティを追加します。UPROPERTY()マクロをEditAnywhereを引数としてそれぞれに追加します。C++// Contains textual data about the item. USTRUCT() struct FItemText { GENERATED_BODY() // The text name of the item. UPROPERTY(EditAnywhere) FText Name;
アイテム データ構造体を作成する
これらの前提条件の宣言を追加できたので、次はアイテムのプロパティを含むアイテム データ構造体を作成します。 これらのプロパティは、データ テーブルではフィールドになります。
FTableRowBase から継承する、「FItemData」という名前の構造体を定義します。 public 指定子を追加し、任意の場所で表示できるようにし、Unreal Header Tool の GENERATED_BODY() を追加します。
// Defines a basic item that can be used in a data table.
USTRUCT()
struct FItemData : public FTableRowBase
{
GENERATED_BODY()
};FTableRowBase は、Unreal Engine が提供するベース構造体で、データ テーブル アセットでカスタム USTRUCT を使用できるようにします。 Unreal では、行構造体をシリアル化する方法を把握したり、CSV/JSON ファイルからのデータのインポートとエクスポートをサポートしたり、テーブルからデータを取り出す際の型安全性を確保したりするために使用します。
FItemData 構造体で、次の宣言を追加します。
「
ID」という名前のFName。 データ テーブルの各行には、参照するための関連付けられたFNameが必要です。「
ItemType」という名前のEItemType 列挙型。 これは、先ほど宣言したアイテム タイプの列挙型です。「
ItemText」という名前のFItemText構造体。 これは、先ほど宣言したテキスト データの構造体です。
UPROPERTY() マクロを EditAnywhere と Category = “アイテム データ” 引数とともに各宣言に追加します。
// The ID name of this item for referencing in a table row.
UPROPERTY(EditAnywhere, Category = "Item Data")
FName ID;
// The type of the item.
UPROPERTY(EditAnywhere, Category = "Item Data")
EItemType ItemType;
// Text struct including the item name and description.
UPROPERTY(EditAnywhere, Category = "Item Data")
さらにもう 1 つ、「ItemBase」という名前の UItemDefinition に TObjectPtr を追加します。 これに、構造体の他のプロパティと同じ UPROPERTY マクロを指定します。
// The Data Asset item definition associated with this item.
UPROPERTY(EditAnywhere, Category = "Item Data")
TObjectPtr<UItemDefinition> ItemBase;TObjectPtr は、Unreal Engine のスマート ポインタの型で、UObject の派生型を安全に参照する方法です。 これは、エディタで認識される、UObject raw ポインタのガベージ コレクションセーフな置き換えです。 これはハード参照であるため、ランタイム時にオブジェクトをロードしたままにします。
次のステップでは、「ItemDefinition」という名前の UDataAsset クラスを作成します。 データ テーブルでは、[ItemBase] フィールドを使用して ItemDefinition データ アセット インスタンスを参照します。
FItemData 構造体は、次のようになります。
// Defines a basic item that can be used in a data table.
USTRUCT()
struct FItemData : public FTableRowBase
{
GENERATED_BODY()
// The ID name of this item for referencing in a table row.
UPROPERTY(EditAnywhere, Category = "Item Data")
FName ID;
コードを保存します。
DataAsset アイテム定義をビルドする
ここまでで、アイテム データ、つまりデータ テーブルに表示されるデータの型を定義しました。 次に、前方宣言した UItemDefinition クラスを ItemData.h に実装します。
このクラスは UDataAsset を継承するため、UObject です。つまり、コードを経由することなくエディタで直接そのインスタンスを作成し、使用することができます。 データ テーブルに UItemDefinition クラスのインスタンスを追加します。
ItemDefinition DataAsset クラス (ItemDefinition.h) を作成するには、次の手順を実行します。
Unreal Editor で、[Tools] > [New C++ Class] の順に移動します。
[Choose Parent Class (親クラスを選択)] ウィンドウで [All Classes (すべてのクラス)] をクリックします。
親クラスとして「DataAsset 」を検索して選択し、[Next (次へ)] をクリックします。
クラス名を「
ItemDefinition」(ItemData.h内に作成した前方宣言に一致) とし、[Create Class (クラスを作成)] をクリックします。
VS では自動的に新しいクラスの .hと .cpp ファイルが開きます。 開かない場合は、VS をリフレッシュし、ファイルを手動で開きます。 作業は .h ファイルのみで行うため、必要な場合は .cpp ファイルを閉じることもできます。
ItemDefinition.h に、ItemData.h のインクルードを追加します。そのファイルで宣言した ItemType プロパティと ItemText プロパティを再利用するためです。
#include "CoreMinimal.h"
#include "Data/ItemData.h"
#include "ItemDefinition.generated.h"ItemDefinition.h で、クラス定義の上にある UCLASS() マクロで BlueprintType と Blueprintable 指定子を追加し、ブループリントを作成するための基本クラスとして公開します。
// Defines a basic item with a static mesh that can be built from the editor.
UCLASS(BlueprintType, Blueprintable)
class FIRSTPERSON_API UItemDefinition : public UDataAsset
{
GENERATED_BODY()
public:
// Default constructor for the class.
UItemDefinition();
};Public セクションで、ItemData.h から FName ID、EItemType ItemType、FItemText ItemText 宣言をコピーします。
アイテムの定義は、FItemData 構造体と同じデータを取得するため、アイテムに関する情報を取得する際に元のテーブルを参照する必要はありません。
public:
// The ID name of this item for referencing in a table row.
UPROPERTY(EditAnywhere, Category = "Item Data")
FName ID;
// The type of this item.
UPROPERTY(EditAnywhere, Category = "Item Data")
EItemType ItemType;
ItemText の後に、「WorldMesh」という名前の UStaticMesh 型の TSoftObjectPtr を宣言します。 このスタティックメッシュを使用して、このアイテムをワールドに表示します。
TSoftObjectPtr は、必要なときにのみロードされるアセットのパスの文字列表現として機能する特別な型のウイーク ポインタです。 通常、アセットを参照する UObject ポインタ プロパティを宣言すると、そのプロパティを含むオブジェクトがロードされるときに、そのアセットもロードされます。 これにより、ゲームの開始時にすべてのアセットがロードされ、多大なオーバーヘッドと速度低下が発生する可能性があります。 TSoftObjectPtr は、オンデマンドでのみロードする必要のあるメッシュなどの大きなアセットに役立ちます。 詳細については、「アセットの非同期ロード」を参照してください。
同じ UPROPERTY(EditAnywhere, Category = “アイテム データ”) マクロをこのプロパティに追加します。
// Text struct including the item name and description.
UPROPERTY(EditAnywhere, Category = "Item Data")
FItemText ItemText;
// The Static Mesh used to display this item in the world.
UPROPERTY(EditAnywhere, Category = "Item Data")
TSoftObjectPtr<UStaticMesh> WorldMesh;
データ テーブルの行は、CSV の行と似ており、完全なアセットを格納するのではなく、テキスト データを保持するためのものです。 データ管理を最適化するには、アイテムのメッシュ、マテリアル、アニメーションなどの情報を DataAsset にまとめることをお勧めします。これは、特定のアイテムに関するすべてのデータが置かれている一元管理の場所であるためです。 そのため、アイテムのスタティックメッシュのプロパティは、FItemData 構造体ではなく、UItemDefinition にあります。
完成した UItemDefinition クラスは次のようになります。
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Data/ItemData.h"
#include "ItemDefinition.generated.h"
/**
* Defines a basic item with a static mesh that can be built from the editor.
コードを保存して Visual Studio からコンパイルします。
データ アセット インスタンスを作成する
アイテム データ (ItemData.h からの FItemData 構造体) とアイテム定義 (UItemDefinition クラス) が定義されたことで、アイテム インスタンスとデータ テーブルをビルドするために必要なすべての要素が揃いました。
まず、新しい投射物ピックアップ アイテムのためのデータ アセットを作成し、次にデータ テーブルを作成して、データ アセットの情報をデータに取り込みます。
ItemDefinition クラスからデータ アセット アイテムを作成するには、次の手順を実行します。
コンテンツ ブラウザで、[Content (コンテンツ)] > 「FirstPerson 」フォルダに移動し、[Add (追加)] をクリックするか、アセット ビュー の空白の領域を右クリックして、[New Folder (新規フォルダ)] を選択し、「
Data」という名前を付けます。ここにゲーム内のデータ アセットを格納して整理します。
「
Data」フォルダで、[Add] をクリックするか、アセット ビューの空白の領域を右クリックして、[Miscellaneous (その他)] > [Data Asset (データアセット)] を選択します。円グラフのアイコンの付いたデータ アセット オプションを選択してください。
[Pick Class For Data Asset Instance (データアセットインスタンスのクラスの選択)] ウィンドウで、[Item Definition (アイテム定義)] (先ほど定義した C++ クラス) を選択し、[Select (選択)] をクリックします。 新しいデータ アセットに「
DA_Pickup_001」という名前を付けます。「
DA_Pickup_001」をダブルクリックして開きます。 その [Details (詳細)] パネルに、ItemDefinition.hで定義したすべてのプロパティが表示されます。[ID] に「
pickup_001」と入力します。[Consumable (消費アイテム)] を [Item Type (アイテムタイプ)] に設定します。
[Item Text (アイテムテキスト)] を展開して、[Name (名前)] と [Description (説明)] を入力します。
[World Mesh (ワールドメッシュ)] を
[SM_FoamBullet]に設定します。ウィンドウの左上隅近くにある [Save (保存)] をクリックし、データ アセットを保存します。
データ テーブルを定義する
データ テーブルにデータを取り込むためのデータ アセットを少なくとも 1 つ用意できたので、テーブルを作成することができます。
データ テーブルの各行は、ItemData 構造体の、埋め込まれた 1 つのインスタンスです。
データ テーブルを作成するには、次の手順を実行します。
コンテンツ ブラウザの「
Data」フォルダで空白の領域を右クリックして [Miscellaneous] > [Data Table (データテーブル)] を選択します。[Pick Row Structure (行構造を選択)] ウィンドウで、[ItemData] (
ItemData.hで定義したFItemData構造体) を選択し、[OK] をクリックします。新しいテーブルに「
DT_PickupData」という名前を付け、ダブルクリックして開きます。
最初は、データ テーブルは空です。 ただし、ヘディングとして FItemData で定義したプロパティはテーブルの上部に表示され、「Row Name」という名前の追加の縦列も表示されます。
ピックアップ アイテム データ アセットをテーブルの行として追加するには、次の手順を実行します。
[Add] をクリックし、テーブルに新しい行を追加します。 DataTable エディタでは、[Data Table] タブの左上のパネルに行のエントリがリストされます。
行名「
NewRow」をダブルクリックし、「pickup_001」 (データアセットの ID) に変更します。任意の
FNameを行名として使用できますが、コードで行を参照しやすくするために、行名はデータ アセットの ID と同じにします。[Row Editor (行エディタ)] パネルで、
DA_Pickup_001データ アセットに設定したものと同じ値を [ID]、[Item Type (アイテムタイプ)]、[Item Text (アイテムテキスト)] のフィールドに入力します。[Item Base (アイテムベース)] を
DA_Pickup_001データ アセットに設定します。データ テーブルを保存します。
完成です。 このステップで作成したデータ駆動型ゲームプレイ要素の図をもう一度見て、すべてがどのように接続されているかを確認します。
FItemData 構造体から列を取得するデータ テーブルが作成できました。 作成した消費アイテム型の ItemDefinition データ アセット インスタンスからのデータを含む行をテーブルに入力し、ItemBase ポインタを使用してデータ アセット自体を参照しました。 最後に、データ アセット インスタンスは、作成した親 UItemDefinition データ アセット クラスからプロパティを取得しました。
次の内容
次のセクションでは、このアイテム定義を拡張してカスタム ピックアップ クラスを作成し、レベルでインスタンス化する方法を学びます。
完全なコード
#pragma once
#include "CoreMinimal.h"
#include "Engine/DataTable.h"
#include "ItemData.generated.h"
class UItemDefinition;
/**
* Defines the type of the item.
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Data/ItemData.h"
#include "ItemDefinition.generated.h"
/**
* Defines a basic item with a static mesh that can be built from the editor.