アンリアルでのオブジェクト処理

UObject システムの機能の概要

Windows
MacOS
Linux

クラス、プロパティ、関数を適切なマクロでマーク付けすると、それぞれ UClassesUPropertiesUFunctions になります。その結果、アンリアル エンジンがこれらにアクセスできるようになり、たくさんの内部処理機能を実装することができます。

プロパティの自動初期化

コンストラクタが呼び出される前に、UObjects は初期化時に自動的にゼロになります。これはクラス全体、UProperties、ネイティブ メンバでも同様に起こります。続いて、クラス コンストラクタのカスタム値でメンバが初期化されます。

参照の自動更新

AActor または UActorComponent が破棄されるか、プレイから取り除かれると、それに対するすべての参照でリフレクション システムで可視のものは (UProperty ポインタおよび TArray など Unreal Engine コンテナ クラスに保存されているポインタ) 自動的に null になります。これは、ダングリング ポインタが残らないようにし、今後トラブルが生じないようにするという点でメリットがありますが、コードの他の部分がそれらを破棄すると、AActor ポインタと UActorComponent ポインタが null になるということも意味します。一番のメリットは、null チェックの方が信頼性が高いということです。標準ケースの null ポインタと non-null ポインタが破棄されたメモリをポイントしている場合の両方を検出するからです。

この機能は、UPROPERTY とマーク付けされているかアンリアル エンジンのコンテナ クラスに格納されている UActorComponent または AActor 参照にのみ適用されることを理解することが重要です。Raw ポインタに格納されているオブジェクト参照は、アンリアル側では未知のものであり、自動的に null にはならず、ガーベジ コレクションも妨げません。UObject* 変数は必ずしも UProperties でなくてもよい、という点に注意してください。UProperty 以外のオブジェクト ポインタが必要な場合は、TWeakObjectPtr の使用を検討してください。これは、弱いポインタであるため、ガーベジ コレクションを防ぎませんが、アクセスされる前に、妥当性についてクエリ可能であり、ポイントしているオブジェクトが破棄されると null になるように設定されます。

参照された UObject UProperty が自動的に null になる別のケースは、エディタでアセットに対して 'Force Delete' を使用する場合です。結果として、アセットである UObjects を操作するすべてのコードは、こうしたポインタが null になるように処理しなければなりません。

シリアル化

UObject がシリアル化されると、"transient" と明示的にマーク付けされていない限り、すべての UProperty 値が自動的に書き込みまたは読み出されます。または、ポスト コンストラクタのデフォルト値から変更されません。例えば、AEnemy インスタンスをレベルに配置し、ヘルスを 500 に設定して保存して UClass 定義以外に一行もコードを記述することなく、リロードすることができます。

UProperties が追加または取り除かれると、事前に存在していたコンテンツのロードがシームレスに処理されます。新規プロパティは、新規 CDO からコピーされたデフォルト値を取得します。取り除かれたプロパティは、警告なしに無視されます。

カスタムのビヘイビアが必要な場合、UObject::Serialize をオーバーライドすることができます。これはデータ エラーの検出、バージョン番号のチェック、データ フォーマットが変わったときに自動変換を実行または更新する場合に便利です。

プロパティ値を更新する

UClassClass Default Object (CDO) を変更すると、アンリアル エンジンではこうした変更をロード時にクラスのすべてのインスタンスに適用しようとします。任意のオブジェクト インスタンスに対して、更新された変数の値が古い CDO の値と一致する場合、新しい CDO で保持されている値に更新されます。変数に他の値がある場合、その値は意図的に設定されたものであるとみなされ、こうした変更は保たれます。

例えば、いくつかの AEnemy オブジェクトを配置したレベルを保存し、ヘルスのデフォルト値を AEnemy コンストラクタで 100 に設定したとします。非常にタフであるため、Enemy_3 のヘルスを 500 に設定したとします。その後、気が変わって、ヘルスのデフォルト値を 150 に増やしたと想定します。次回、レベルをロードすると、アンリアル エンジンは、CDO が変更されたことを認識し、古いヘルスのデフォルト値 (100) を持つ AEnemy のすべてのインスタンスを 150 のヘルス値を持つように更新します。Enemy_3 のヘルスは 500 のままです。古いデフォルト値を使用していなかったからです。

エディタの統合

UObjectsUProperties はエディタによって認識されます。特殊なコードを記述する必要なくエディタはこうした値を編集のために自動的に公開します。これにはオプションでブループリント ビジュアル スクリプティング システムへの統合が含まれます。変数と関数のアクセシビリティと公開を制御するためのオプションが数多くあります。

ランタイムの型情報とキャスティング

UObjects は、アンリアル エンジンのリフレクション システムの一部であり、どの UClass であるかを常に認識しており、ランタイム時に型関連の決定とキャストが行われます。

ネイティブ コードでは、すべての UObject クラスは、その親クラスに設定されたカスタムの "Super" typedef を持ちます。これを使うとオーバーライドする挙動を簡単に制御することができます。例えば、以下のようになります。

class AEnemy : public ACharacter
{
    virtual void Speak()
    {
        Say("Time to fight!");
    }
};

class AMegaBoss : public AEnemy
{
    virtual void Speak()
    {
        Say("Powering up! ");
        Super::Speak();
    }
};

ご覧になってわかるように、 Speak を呼び出すと、 MegaBoss が "Powering up! Time to fight!" といいます。

さらに、テンプレート化された Cast 関数を使用して、基本クラスからのオブジェクトを派生クラスに安全にキャストできます。または、 IsA を使用してオブジェクトが特定のクラスであるかをクエリすることができます。以下に簡単な例を示します。

class ALegendaryWeapon : public AWeapon
{
    void SlayMegaBoss()
    {
        TArray<AEnemy> EnemyList = GetEnemyListFromSomewhere();

        // The legendary weapon is only effective against the MegaBoss
        for (AEnemy Enemy :EnemyList)
        {
            AMegaBoss* MegaBoss = Cast<AMegaBoss>(Enemy);
            if (MegaBoss)
            {
                Incinerate(MegaBoss);
            }
        }
    }
};

ここでは、Cast を使用して AEnemyAMegaBoss にキャストしようとしています。問題となっているオブジェクトが実際には AMegaBoss (またはその子クラス) ではない場合、キャストは nulll ポインタを戻し、適切に反応することができます。上のコードでは、 Incinerate 関数は MegaBoss に対してのみ呼び出されます。

ガーベジ コレクション

アンリアル エンジンは、参照されなくなった、または破棄と明示的にフラグ付けされた UObjects を定期的にクリーンアップするガーベジ コレクション スキームを実装しています。どの UObjects がまだ使用中であるか、どのオブジェクトがオーファンになっているかを判断するための参照グラフをビルドします。このグラフの元は、"root set" と指定されている一連の UObjects です。どの UObject でもルートセットに追加することができます。ガーベジ コレクションが実施されると、既知の UObject 参照のツリーを "root set" から開始して検索することで、参照されているすべての UObjects を追跡することができます。参照されていない UObjects、つまりツリー検索で見つからなかったものは、不要とみなされ、取り除かれます。

通常はガーベジ コレクションの対象から外したいオブジェクトに対する UPROPERTY 参照を保持しておく必要があります。または、それに対するポインタを TArray またはアンリアルエンジンの他のコンテナ クラスに格納します。多くの場合、アクタはこの例外です。アクタは通常、ルートセットにリンクバックするオブジェクトによって参照されるからです。例えば、それらが属するレベルなどで、アクタのコンポーネントはアクタ自体によって参照されます。アクタは、Destroy 関数を呼び出すことで明示的に破棄とマーク付けされます。これは進行中のゲームからアクタを取り除く標準的な方法です。コンポーネントは、DestroyComponent 関数を使って明示的に破棄できますが、通常は所有しているアクタがゲームから取り除かれると破棄されます。

UE4 のガーベジ コレクションは高速かつ効率的です。Orphaned (孤立) オブジェクトを特定するためのマルチスレッドの到達可能性分析や、コンテナからアクタをできるだけ早く取り除くために最適化されたコードの unhash など、オーバーヘッドを最小限に抑えるように設計された数多くのビルトイン機能があります。いつどのようにガーベジ コレクションを行うかを一段と正確に調整する機能もあります。そのほとんどは、[Project Settings][Engine - Garbage Collection] にあります。以下の設定はプロジェクトのガーベジ コレクタのパフォーマンスを調整するために一般的に使用されるものです。

設定

機能の説明

Create Garbage Collector UObject Clusters

プロジェクトの設定でオン、オフすることができます (デフォルトではオン)。オンの場合、関連オブジェクトはガーベジ コレクション クラスタでグループ化されて、個々のオブジェクトをチェックするのではなく、クラスタだけをチェックすればよいようにします。つまり、到達可能性は速くなります。クラスタ全体がひとつのオブジェクトとして扱われるからです。しかし、クラスタ内の個々のアイテムはすべて unhash されて、同じフレームで削除するように準備されます。クラスタが十分に大きいと処理落ちを生じる可能性があります。一般的にクラスタを作成することでガーベジ コレクションのパフォーマンスが向上し、到達可能性分析にかかる時間が短縮します。

Merge GC Clusters

クラスタのマージを有効にして、あるクラスタからのオブジェクトが別のクラスタのオブジェクトを参照する場合にクラスタをマージさせることができます。マージを生じさせた参照をクリアしても、新しくマージされたクラスタが解消されたり、バラバラになることはありません。この機能が動作するためには、[Create Garbage Collector UObject Clusters] を有効にしなければなりません。これはガーベジ コレクターがオブジェクトを unhash し、破棄する頻度を減らすことになりますが、オブジェクト数が多くなると一度に unhash、および破棄します。さらに、マージしたクラスタなしでガーベジ コレクションが起こると、マージしたクラスタでガーベジ コレクションが行われない場合もあります。クラスタ内の任意のオブジェクトに対する参照では、クラスタ全体がガーベジ コレクションの対象になるからです。

Actor Clustering Enabled

[Project Settings (プロジェクト設定)] でこのオプションをオンにして、bCanBeInCluster 変数を true に設定するか、コードの CanBeInCluster 関数をオーバーライドして true を戻すようにすることでアクタをクラスタに入れることができます。デフォルトでアクタとコンポーネントでは、これをオフにしています。ただし、Static Mesh アクタと Reflection Capture コンポーネントは例外です。この機能は、一度に破棄することを想定しているアクタをグループ化するのに便利です。通常はそれらを含むサブレベルをアンロードすること以外では破棄できないレベルに配置しているスタティックメッシュになります。

Blueprint Clustering Enabled

ブループリントの UBlueprintGeneratedClass と共有の UPROPERTY や UFUNCTION などの関連データは、この設定をオンにすることでクラスタ化することができます。このクラスタリングは、Blueprint Generated Class 自体を参照し、ブループリントの個々のインスタンスは参照しないことを覚えておいてください。

Time Between Purging Pending Kill Objects

ガーベジ コレクションのアクティビティの頻度はプロジェクト設定で調整することができます。こうしたハイレベルな制御は、処理落ちを防ぐうえで特に役立ちます。コレクション間の時間を短縮することで、次回の到達可能性分析のパスで見つかるであろう到達不可能になりそうなオブジェクト量を減らして、大量のアクタを同時にクリーンアップする場合に起こる処理落ちを避けることができます。

ProjectSettingsGarbageCollection.png

プロジェクト設定内のガーベジ コレクション設定

ネットワークのレプリケーション

UObject システムには、ネットワーク通信とマルチプレイヤー ゲームを行いやすくする堅牢な機能セットがあります。

UProperties にタグ付けして、アンリアル エンジンに対して ネットワーク プレイ中にデータをレプリケートする ように指示できます。この場合の一般的なモデルでは、変数がサーバー上で変更されると、アンリアル エンジンがその変更を検出し、すべてのクライアントに確実に送信します。レプリケーションによって変数が変更する場合に、クライアントはオプションでコールバック関数を受信します。

UFunctionsリモート マシン上で実行する ようにタグ付けすることも可能です。例えば、「サーバー」の関数は、クライアントのマシン上で呼び出されると、その関数がアクタのサーバー版でサーバー マシンで実行するようにします。一方、「クライアント」の関数はサーバーから呼び出し可能で、そのアクタの所有クライアント版で実行されます。

タグ
Select Skin
Light
Dark

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

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

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

フィードバックを送信