Sparse Class Data

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

Windows
MacOS
Linux
On this page

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 を使用すると決めたら、候補となるプロパティを特定する必要があります。EditAnywhereEditInstanceOnly、または 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;
};

Sparse Class Data 構造体でプロパティのカテゴリを指定しないと、デフォルト名が取得されます。FMySparseClassData の場合、エディタには「My Sparse Class Data」として表示されます。

この構造体を使用するには、元のクラスに何らかの変更が必要です。プロセスに必要な変更は、具体的には次の 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 メタデータ指定子を使用します。

Select Skin
Light
Dark

Welcome to the new Unreal Engine 4 Documentation site!

We're working on lots of new features including a feedback system so you can tell us how we are doing. It's not quite ready for use in the wild yet, so head over to the Documentation Feedback forum to tell us about this page or call out any issues you are encountering in the meantime.

We'll be sure to let you know when the new system is up and running.

Post Feedback