Sparse Class Data システムを使用すると、よく使用される アクタ 型の冗長なデータを取り除くことで、メモリが節約されます。ゲーム開発中に、
ゲーム内に同時に多数のインスタンスを持つ (冗長なコピーによって大量のメモリが消費される) アクタ クラスのメンバーである。
配置済みのアクタ インスタンスで変化しない。つまり、基本値をオーバーライド (変更) するアクタ インスタンスが存在しないため、プロパティに
EditInstanceOnly
またはEditAnywhere
UProperty 指定子が必要ない。C++ コードで変更されない。変数に直接アクセスするコードは、アクセサー関数への呼び出しで置き換える必要がある。
Sparse Class Data 機能を実装するには、ネイティブ (C++) コードが必要です。ブループリントで宣言された変数は、このプロセスの対象とするために、C++ コードに移行する必要があります。
Unreal Engine 4.24 では本機能は ブループリントのネイティブ化 と互換性がありません。つまり、それが参照する Blueprint クラスをや、Sparse Class Data を実施するクラスの子である Blueprint クラスのネイティブ化はできません。不当なブループリントを使ってプロジェクトをクックしようとすると、この効果に対して警告メッセージが生成されます。
実装例
クラスの 1 つに Sparse Class Data を使用すると決めたら、候補となるプロパティを特定する必要があります。EditAnywhere
、EditInstanceOnly
、または BlueprintReadWrite
でタグ付けされたプロパティは、Sparse Class Data の候補にはなりません。同様に、ネイティブ C++ コードで変更されるプロパティも、Sparse Class Data システムで処理する対象とはなりません。これは、そのようなプロパティはアクタ インスタンスごとに異なる可能性があるからです。レベル エディタでインスタンスごとに編集されたり、ブループリント スクリプティングや、ネイティブ コードによってゲーム セッション中に 1 つのアクタ インスタンスの値が変更されたりするからです。次のサンプル クラスにはいくつかのプロパティが含まれており、一部は Sparse Class Data の候補です。
// The properties in this class can all be changed in the Editor, but on a per-class basis, not a per-instance basis. (このクラスのプロパティはすべてエディタで変更できるが、クラスごとの変更であり、インスタンスごとの変更はできない。)
UCLASS(BlueprintType)
class AMyActor : public AActor
{
GENERATED_UCLASS_BODY()
public:
// This property can be changed in the Editor, but only on a per-class basis. (このプロパティはエディタで変更できるが、クラスごとの変更しかできない。)
// Blueprint graphs cannot access or change it. (ブループリント グラフではアクセスや変更ができない。)
// It is a potential candidate for Sparse Class Data. (Sparse Class Data の有力な候補である。)
UPROPERTY(EditDefaultsOnly)
float MyFloatProperty;
// This property cannot be changed in the Editor. (このプロパティはエディタで変更できない。)
// Blueprint graphs can access it, but cannot change it. (ブループリント グラフでアクセスできるが、変更はできない。)
// It is a potential candidate for Sparse Class Data. (Sparse Class Data の有力な候補である。)
UPROPERTY(BlueprintReadOnly)
int32 MyIntProperty;
// This property can be edited on a per-class basis in the Editor. (このプロパティはエディタでクラスごとに編集できる。)
// Blueprint graphs can access it, but cannot change it. (ブループリント グラフでアクセスできるが、変更はできない。)
// It is a potential candidate for Sparse Class Data. (Sparse Class Data の有力な候補である。)
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FName MyNameProperty;
// This property can be edited on placed MyActor instances. (このプロパティは配置済みの MyActor インスタンスで編集できる。)
// It is not a potential candidate for Sparse Class Data. (Sparse Class Data の有力な候補ではない。)
UPROPERTY(EditAnywhere)
FVector MyVectorProperty;
// This property can be changed in Blueprint graphs. (このプロパティはブループリント グラフで変更できる。)
// It is not a potential candidate for Sparse Class Data. (Sparse Class Data の有力な候補ではない。)
UPROPERTY(BlueprintReadWrite)
FVector2D MyVector2DProperty;
};
候補となる変数を特定したら、それらの変数を含めた構造体を作成し、BlueprintType
EditDefaultsOnly
指定子を含んでいる必要があります。
USTRUCT(BlueprintType)
struct FMySparseClassData
{
GENERATED_BODY()
FMySparseClassData()
:MyFloatProperty(0.f)
, MyIntProperty(0)
, MyNameProperty(NAME_None)
{ }
// You can set this property's default value in the Editor. (エディタでこのプロパティのデフォルト値を設定できる。)
// Blueprint graphs cannot access it. (ブループリント グラフではアクセスできない。)
UPROPERTY(EditDefaultsOnly)
float MyFloatProperty;
// This property's value will be set in C++ code. (このプロパティの値は C++ コードで設定される。)
// You can access it (but not change it) in Blueprint graphs. (ブループリント グラフでアクセスできる (が、変更できない)。)
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int32 MyIntProperty;
// You can set this property's default value in the Editor. (エディタでこのプロパティのデフォルト値を設定できる。)
// You can access it (but not change it) in Blueprint graphs. (ブループリント グラフでアクセスできる (が、変更できない)。)
// "GetByRef" means that Blueprint graphs access a const ref instead of a copy. (「GetByRef」は、ブループリント グラフがコピーではなく定数の参照にアクセスすることを意味する。)
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, meta=(GetByRef))
FName MyNameProperty;
};
FMySparseClassData
この構造体を使用するには、元のクラスに何らかの変更が必要です。プロセスに必要な変更は、具体的には次の 3 つです。
この構造体を Sparse Class Data 型として使用するようにクラスに指示する。
新しい構造体に移動するプロパティに
#if WITH_EDITORONLY_DATA
プリコンパイラ ディレクティブ ブロックを追加し、元のクラスでは_DEPRECATED
サフィックスでマークする。さらに、UProperty 指定子をすべて削除し、プロパティをprivate
アクセスに設定します。_DEPRECATED
の名前を使用するうえでコードの他の部分は変更しないようにします。これらの行は、Sparse Class Data 構造体へのアクセサー呼び出しで置き換えられます。エディタ ビルドで (
#if WITH_EDITOR
)、MoveDataToSparseClassDataStruct
関数をオーバーライドします。この関数は、元のクラスから Sparse Class Data 構造体へのワンタイム コピーを実行することで既存のデータ値を保持します。
これらの変更を加えると、クラスは次のようになります。
UCLASS(BlueprintType, SparseClassDataTypes = MySparseClassData)
class AMyActor : public AActor
{
GENERATED_BODY()
#if WITH_EDITOR
public:
// ~ This function transfers existing data into FMySparseClassData.
virtual void MoveDataToSparseClassDataStruct() const override;
#endif // WITH_EDITOR
#if WITH_EDITORONLY_DATA
//~ These properties are moving out to the FMySparseClassData struct:
private:
// This property can be changed in the editor, but only on a per-class basis.
// Blueprint graphs cannot access or change it.
// It is a potential candidate for Sparse Class Data.
UPROPERTY()
float MyFloatProperty_DEPRECATED;
// This property cannot be changed in the editor.
// Blueprint graphs can access it, but cannot change it.
// It is a potential candidate for Sparse Class Data.
UPROPERTY()
int32 MyIntProperty_DEPRECATED;
// This property can be edited on a per-class basis in the editor.
// Blueprint graphs can access it, but cannot change it.
// It is a potential candidate for Sparse Class Data.
UPROPERTY()
FName MyNameProperty_DEPRECATED;
#endif // WITH_EDITORONLY_DATA
//~ The remaining properties can change on a per-instance basis and
//~ are therefore not involved in the Sparse Class Data implementation.
public:
// This property can be edited on placed MyActor instances.
// It is not a potential candidate for Sparse Class Data.
UPROPERTY(EditAnywhere)
FVector MyVectorProperty;
// This property can be changed in Blueprint graphs.
// It is not a potential candidate for Sparse Class Data.
UPROPERTY(BlueprintReadWrite)
FVector2D MyVector2DProperty;
};
次の関数は、共有プロパティすべての既存の値をコピーします。
#if WITH_EDITOR
void AMyActor::MoveDataToSparseClassDataStruct() const
{
// make sure we don't overwrite the sparse data if it has been saved already
UBlueprintGeneratedClass* BPClass = Cast<UBlueprintGeneratedClass>(GetClass());
if (BPClass == nullptr || BPClass->bIsSparseClassDataSerializable == true)
{
return;
}
Super::MoveDataToSparseClassDataStruct();
#if WITH_EDITORONLY_DATA
// Unreal Header Tool (UHT) will create GetMySparseClassData automatically.
FMySparseClassData* SparseClassData = GetMySparseClassData();
// Modify these lines to include all Sparse Class Data properties.
SparseClassData->MyFloatProperty = MyFloatProperty_DEPRECATED;
SparseClassData->MyIntProperty = MyIntProperty_DEPRECATED;
SparseClassData->MyNameProperty = MyNameProperty_DEPRECATED;
#endif // WITH_EDITORONLY_DATA
}
#endif // WITH_EDITOR
Engine/BlueprintGeneratedClass.h
この時点で、Sparse Class Data が実装できました。影響を受けるプロパティをユーザーがエディタで編集、アクセスしても、気がつくような動作の違いはありませんが、出荷ビルドのメモリ使用量は削減されます。プロパティを C++ コードで参照する場合は、その変数にアクセスする試行を getter 関数の呼び出しに置き換えます。例えば、MyFloatProperty
変数へのアクセスに使用していたコードでは、代わりに GetMyFloatProperty
を呼び出すようにします。この関数は、UHT によって自動的に生成されます。重要な getter 関数があり、その動作を維持する必要がある場合は、UHT によって getter 関数が生成されないよう NoGetter
UProperty メタデータ指定子で指示します。値ではなく定数の参照によってアクセスする必要のある変数には、GetByRef
UProperty メタデータ指定子を使用します。