Sparse Class Data

Sparse Class Data システムを使用すると、冗長なプロパティによるメモリの無駄が取り除かれます。

Choose your operating system:

Windows

macOS

Linux

コンテンツ

Sparse Class Data システムを使用すると、よく使用される アクタ 型の冗長なデータを取り除くことで、メモリが節約されます。ゲーム開発中に、 ブループリントに公開されたプロパティ を使用すると、デザイナーが非常に容易にアクタのビヘイビアをイテレーションできるようになります。しかし、ゲームの出荷時に、そのようなプロパティの値がアクタ インスタンスによって変化しない、またはゲームプレイ中に変化しない場合、そのプロパティの多くは実質的に定数であるといえます。Sparse Class Data を使用すると、そのようなプロパティを 1 つの共有構造体インスタンスに転送し、メモリ内に保持するプロパティのコピー数を 1 つだけに抑えながらも、引き続きデザイナーがブループリント グラフ内の値にアクセスして [Class Defaults (クラスのデフォルト)] で編集可能にできます。あるプロパティが Sparse Class Data の対象にふさわしいかどうかを判断するには、次の 3 要件基準を使用します。以下に当てはまる場合、そのプロパティは対象として妥当です。

  1. ゲーム内に同時に多数のインスタンスを持つ (冗長なコピーによって大量のメモリが消費される) アクタ クラスのメンバーである。

  2. 配置済みのアクタ インスタンスで変化しない。つまり、基本値をオーバーライド (変更) するアクタ インスタンスが存在しないため、プロパティに EditInstanceOnly または EditAnywhere UProperty 指定子が必要ない。

  3. 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 UStruct 指定子 でマークします。構造体の各プロパティは 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. (~ この関数は既存のデータを FMySparseClassData に移動する。)
    virtual void MoveDataToSparseClassDataStruct() const override;
#endif // WITH_EDITOR

#if WITH_EDITORONLY_DATA
    //~ These properties are moving out to the FMySparseClassData struct: (~ これらのプロパティは FMySparseClassData 構造体に移動する。)
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. (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. (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. (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. (~ したがって、Sparse Class Data 実装には含まない。)
public:
    // 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;
};

次の関数は、共有プロパティすべての既存の値をコピーします。

#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. (Unreal Header Tool (UHT) によって GetMySparseClassData が自動的に作成される。)
    FMySparseClassData* SparseClassData = GetMySparseClassData();

    // Modify these lines to include all Sparse Class Data properties. (すべての Sparse Class Data プロパティを含めるにはこれらの行を変更する。)
    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 メタデータ指定子を使用します。

Unreal Engine のドキュメントを改善するために協力をお願いします!どのような改善を望んでいるかご意見をお聞かせください。
調査に参加する
閉じる