C++ ときどき ごはん、わりとてぃーぶれいく☆

USAGI.NETWORKのなかのひとのブログ。主にC++。

UE4: C++er 視点での実行中の AActor への USceneComponent の動的なオブジェクトの実行中の生成、レジスター、アタッチ、デタッチ、アンレジスター、破棄の方法

状況 (½) おさらい編: AActor::AActor (アクターのコンストラクター) で生成する場合

// .h
  UHogeComponent* HogeComponent;
// .cpp
AActor::AActor()
{
  RootComponent = CreateDefaultSubobject< USceneComponent >( TEXT( "RootComponent" ) );
  HogeComponent = CreateDefaultSubobject< UHogeComponent >( TEXT( "Hoge" ) );
  HogeComponent->SetupAttachment( RootComponent );
}

以上のように ctor で"デフォルト"のサブオブジェクトとして生成する場合には CreateDefaultSubobject を使う。

Note: コンポーネント間のアタッチメントは SetupAttachment を使うのがナウい方式。やや古い参考文献を見ると [[deprecated]]API を使っている事があるのでコンパイラーの warning を見てモダン化する。

状況 (2/2) 本編: 実行中の任意のタイミングで生成する場合

// .h
  UHogeComponent* HogeComponent;
  void Fuga();
  void Piyo();
// .cpp
AActor::AActor()
{
  // 比較用: ctor では CreateDefaultSubobject を使った。
  RootComponent = CreateDefaultSubobject< USceneComponent >( TEXT( "RootComponent" ) );
}

// 実行中の任意のタイミングでコンポーネントを生成
AActor::Fuga()
{
  // 実行中の任意のタイミングで生成する場合は NewObject を使う。
  // (ここでは AActor のデフォルトではないオブジェクト生成なので CreateDefaultSubobject は使えない事に注意)
  HogeComponent = NewObject< UHogeComponent >( this );
  // NewObject で生成したオブジェクトは RegisterComponent が必要。
  HogeComponent->RegisterComponent();
  // ctor 以外でのコンポーネントのアタッチメント(取り付け)も SetupAttachemnt ではなく AttachToComponent を使う
  // ( SetupAttachment を使っても 4.16 時点では大量の警告とエラーを垂れ流しつつ一応は動作するのでうっかり使わないよう注意)
  HogeComponent->AttachToComponent( RootComponent, { EAttachmentRule::SnapToTarget, true } );
}

// 実行中の任意のタイミングでコンポーネントを破棄
AActor::Piyo()
{
  // RootComponent への Attachement (取り付け)を Detach (解除)する
  HogeComponent->DetachFromComponent( { EDetachmentRule::KeepRelative, true } );
  // RegisterComponent によるコンポーネントの登録を UnregisterComponent で解除する
  HogeComponent->UnregisterComponent();
  // コンポーネントオブジェクトの破棄をGCへ明示する
  // (ここで突然 DestroyComponent を呼び出すコードを書くとアクセス違反で死ぬことになるので注意)
  HogeComponent->ConditionalBeginDestroy();
  // "立つ鳥跡を濁さず"
  HogeComponent = nullptr;
}

実行中の AActor へ任意のタイミングで USceneComponent (というか実際にはその派生コンポーネントなど)を生成したり、付け足したり、消したり。公式の C++er 向けチュートリアルでも軽く触れるような ctor での生成とは違うポイントがいくつもあるので少し手間取った@w@

参考

  1. Unreal Engine | UObject インスタンスの作成
  2. What is the correct way to create and add components at runtime ?
  3. Explicitely Delete a UObject - UE4 AnswerHub
  4. その他としてコンパイラーの deprecated 警告、 Debug/Development ビルドの実行中の Warning, Error レベルのログなど。

事後修正

  1. 2017-06-19T22:20+09:00: 記事中のソース例で AttachToComponent をモダンなAPIとしてコードすべきところが AttachTo になっていて [[deprecated]] 警告を受ける実装を示していたので修正しました。
  2. 2017-06-21T15:17+09:00: 記事中のソース例で NewObject の引数が誤って TEXT( "Hoge" ) となっていたところを this に変更。