【UE5】アクターのアタッチの基本的な使い方

今回は Unreal Engineにおけるアクターのアタッチについて基本的な知識と使い方を説明したいと思います。

アタッチ (Attach) とは?

アタッチ (Attach) とは、アクターやコンポーネントの親子関係を作り、子のTransformを親の座標系で解釈する仕組みのことです。
ブループリントクラスでは、あらかじめコンポーネント階層を作ることができます。

これに対してゲーム実行中に階層を変更したい場合には、アタッチを使います。

アタッチのよくある例としては、キャラクター(親)に武器メッシュ(子)をくっつける(装備する)といった使い方です。

ワールド / 相対 / ローカル Transform

World Transform (ワールド Transform)

ワールド原点 (0, 0, 0) を基準とした Transformで、そのオブジェクトがゲーム世界のどこに存在するのかを示す値。

親子関係があるアクター・コンポーネントであっても、この値は常に「世界から見た座標」となります。

Relative Transform (相対 Transform)

親 (Parent) から見た Transform。親アクター・親コンポーネントの座標系を基準にした相対値。

ワールドではないので、この値だけではゲーム世界のどこにあるのかはわからない。親が動いても、基本的に相対 Transformは維持されたままで子も動きます。

親 (Parent) がない場合は「ワールド=相対」となります。

Local Transform (ローカル Transform)

UEでは、ローカル Transform はやや曖昧な扱いですが、実質的には「Local Transform は、親に対する 相対 Transformとほぼ同義」と考えて良いです。

ただ Relativeという用語は「"親" からの相対値」、Localは「そのコンポーネント "自身" の内部のローカル空間」といったように、基準とする概念が異なることにより使い分けを行っている印象です。

アタッチルールとAttachmentの考え方

「アタッチ」をする場合には、"ワールド Transform を維持する" か、"相対 Transformを維持する" か、はたまた "親の情報に従属する" のかといった「3つのアタッチルール」が指定可能です。

  1. Keep Relative Transform: 相対 Transformを維持する
  2. Keep World Transform: ワールド Transformを維持する
  3. Snap To Target Including Scale / Snap To Target Not Including Scale: 親にスナップする

「1と2」については、アタッチ前の Transformが維持されます。それに対して「3」の "Snap To ~" に関しては、アタッチ先の親の位置にワープしてスナップする (子の位置は無視) という特徴があります。

Keep Relative Transform (相対 Transformを維持)

"Keep Relative" はその名の通り、相対 (Relative) Transformを維持したままアタッチします。例えばアクター生成時に子となるパーツを取り付けるといった目的で使います。扉に装飾を取り付けるなどの場合は通常 "Keep Relative" を使用します。理由としては、Relative の値を変更することで、親からの相対位置を調整するのがやりやすいためです。

ただしワールドTransformは親アクターの影響を受けるため、親の状態によってアタッチ時にワールドTransformが若干ズレることがあります。

Keep World Transform (ワールド Transformを維持)

"Keep World" はワールド Transform を維持したままアタッチします。こちらは "Keep Relative" よりも特殊な用途で使います。

先程説明した通り "Keep Relative" は相対 Transform を維持するためにワールドにズレが発生することがあり、アタッチ時にガタガタする場合があります。

その点、"Keep World" ではワールドを維持するためアタッチ時のズレを回避することができます。

Snap To Target Including Scale / Snap To Target Not Including Scale

"Snap To Target" は、親に依存するアタッチで、例えば剣を持つ(アタッチする)場合などに使います。「Snap To Target Including Scale」はスケール値を含め完全にスナップします。それに対して「Snap To Target Not Including Scale」はスケール値の影響を受けないようにするため、エフェクトやUIなどのアタッチに向いています。

アタッチ関連の各関数

アタッチルールが理解できたので、各アタッチ関数を見ていきます。

関数設計目的使うタイミング親になる対象子になる対象特徴
SetupAttachment()初期構造の宣言コンストラクタ内のみComponentComponentデフォルトのアタッチ構造を定義するだけ(実行時には使わない)
AttachActorToActor()アクター同士をアタッチランタイムActorActorRootComponent を介してアタッチされる
AttachActorToComponent()Actor → ComponentランタイムComponentActorActor がメッシュやシーンコンポーネントにぶら下がる
AttachComponentToComponent()コンポーネント同士ランタイムComponentComponentSceneComponent の中心的な attach 関数

分類としては、SetupAttachment()は BeginPlay前 (コンストラクタ) で行うアタッチ処理で、対象はコンポーネントのみです。

それ以外は、自身や対象がアクター or コンポーネントであるかによって使い分けるものです。

AttachActorToActor() でソケットにアタッチする際の注意点

AttachActorToActor() でソケット指定でアタッチする場合、アタッチ先アクター (ParentActor) の RootComponent に存在するソケットが対象となります。そのため RootComponentに該当のソケットが存在しないと、ルートにアタッチされます。

もし RootComponent 以外のソケットにアタッチしたい場合は AttachActorToComponent() を使用する必要があります

ローカルオフセット(相対Transformの調整)

相対Transform で親からの位置・回転を調整する場合、ローカルオフセット関数を使うと便利です。

  • AddLocalOffset(): 指定した位置だけオフセットでずらす
  • AddLocalRotation(): 指定した回転値だけオフセットで回転する

デタッチ

アタッチを解除したい場合にはデタッチ関数である DetachFromActor() を使用します。

注意点として「デタッチルール」の指定があります。

  • FDetachmentTransformRules::KeepRelativeTransform: 相対Transformを維持してデタッチ
  • FDetachmentTransformRules::KeepWorldTransform: ワールドTrransformを維持してデタッチ

アタッチルールと同様、KeepRelativeTransformを行うとワールドTransformのズレが発生することがあります。そのため基本的にはKeepWorldTransformを使ってデタッチするのがおすすめです。

Destroy時の破棄順番

アタッチしたオブジェクトをDestroyしたときの挙動のルールは以下のとおりです。

親をDestroyすると子もDestroyされる

Unreal Engineでは、親アクター(コンポーネント)が破棄されると、子アクター(コンポーネント) もすべて破棄されます。

そのため子アクターを親以外が保持する場合には破棄タイミングに注意する必要があります。

AttachToActor() のActorは1フレーム遅延が発生することがある

Unreal Engine の Destroy は即時破棄ではなく「安全なタイミングまで破棄を遅らせる」仕組みで設計されています。

この「1フレームの破棄遅延」が問題となるケースは以下のとおりです。

  • 親と子を同一フレームで破棄したい(ができない)
  • 親がDestroyしたのに子のTickが動いてしまう
  • 親だけが消えて子アクターが一瞬画面に表示されてしまう

この解決策としては「親のDestroy前に、子をデタッチして別途Destroyする」です。

// 子を親からデタッチ.
ChildActor->DetachFromActor(FDetachmentTransformRules::KeepWorldTransform);
// 子をDestroy.
ChildActor->Destroy();
// 親をDestroy.
ParentActor->Destroy();

これにより同一フレームでの破棄が可能となります。

おしまい

以上、アクターのアタッチの基本的な使い方でした。

アタッチ周りの理解に役立てれば幸いです。

\ 最新情報をチェック /