UE4:アクターのライフサイクルの補足

アクターが生成から終了までに行われる処理は以下の通り。これはアクタ単体のライフサイクルとなる。 http://api.unrealengine.com/JPN/Programming/UnrealArchitecture/Actors/ActorLifecycle/

ロード時の処理順番

基本的なオブジェクトの階層は次のようにっている

UWorld
  ↓
    複数の ULevel
    ↓
        複数のAActor
      ↓
            複数の AActorComponent

ロード処理は ULevel 単位で行われるので、当然、後から読み込まれるレベルのアクターの生成は後になる。つまり他のアクターを参照する場合に「既にオブジェクトがあるか、初期化が終わって動作しているか」、というのはレベルのロードに依存している。レベルは単体でロードできるので、そもそも依存する作り方は良くない。

パーシスタントレベルは UWorld に必ず1つだけあり、最初となるレベルになるので、パーシスタントレベルのアクターは先に生成されていることを保証してよい(と思われる)。パーシスタントレベルに設定する GameMode(その継承クラス) にゲームプレイで必要なマネージャークラスを生成すれば良い。

レベル単位での処理順番

ULevel::RouteActorInitialize()
    ULevel内の全アクター
        PreInitializeComponents()
    ULevel内の全アクター
        InitializeComponents()
        PostInitializeComponents()
    ULevel内の全アクター
        BeginPlay();

PreInitializeComponents() は全てのアクターの InitializeComponents() の前に呼び出される。面白いのは、InitializeComponents() → PostInitializeComponents() はセットで呼び出される。これは分ける意味があまりない気がする。どの道、レベル単位での処理がされるためレベルを変えると優先が変わってしまうので、他のクラスを参照する様な実装はしない方が良い。マネージャークラスのみパーシスタントレベルで生成して、それを介してアクセスする手段を用意すべき。

スポーン時の処理

UWorld::SpawnActor()

    UWorld::PostSpawnInitialize()

        BeginPlay()

スポーンは SpawnActor() 関数でスポーンさせるが、内部で BeginPlay() まで一気に呼び出される。 つまり、エディタ上で設定するような UPROPATY 値を、SpawnActor() 後に設定するという事は意味がない。コンストラクタで設定した初期値で BeginPlay() まで行われる。

これはエディタ上の様に後から指定が出来ない為、直感的ではない。値を設定した BPクラス をスポーンすべきである。(誰かBPクラスのスポーンの仕方をしっている?)

ロード処理と、スポーンでの処理

1つのプレイ空間生成するには UWord 単位となる。複数のレベルで構成されるので、1レベルのロードが終わった後、他のレベルのロードを待つ必要がある。アクター単位では

1)アクター固有のロードのリクエスト(レベルに関連しないロード)
  ↓
2)アクター固有のロードを関連する初期化(パラメーターテーブルなどを読んで初期化)
  ↓
3)他のロードの全完了待ち
(他のレベルのロード完了、アクター固有のロードの完了)
  ↓
4)他のアクターやレベルに関連する初期化(地形に関連する配置補正等)
  ↓
5)全アクタ初期化終了待ち
  ↓
6)ゲームプレイ開始

多分、ATでは1)→2)→6)となっていると思われる。 で、本来なら、1)の処理は AActor::BeginPlay() で行い、2)~6)までをTick()内で状態推移すべきである。

各アクタの処理内容

基本的に扱うのは

  • コンストラク
  • BeginPlay()
  • Tick()
  • EndPlay()
  • デストラク

コンストラクタ Tick 動作用のフラグを設定

レベルに投入後の開始時 BeginPlay() SetActorTickEnable()

レベルから削除されるときに呼び出される EndPlay()

UWorld::SpawnActor NewObject() LevelToSpawnIn->Actors.Add( Actor ); LevelToSpawnIn->ActorsForGC.Add(Actor); AActor::PostSpawnInitialize AActor::DispatchOnComponentsCreated ActorComponent::OnComponentCreated(); // V:全コンポーネント AActor::RegisterAllComponents() AActor::PreRegisterAllComponents(); // V:AActor AActor::PostActorCreated() // V:AActor AActor::FinishSpawning() AActor::ExecuteConstruction() AActor::PostActorConstruction(); AActor::PreInitializeComponents(); ; // V:AActor AActor::InitializeComponents() // V:AActor ActorComponent::InitializeComponent(); // V:全コンポーネント (flag指定があるなら) AActor::PostInitializeComponents() // V:AActor AActor::DispatchBeginPlay(); AActor::BeginPlay() // V:AActor