74.

UE5でコンポーネントから所有アクターの変数にアクセスする方法|Get Owner・Cast

編集

Unreal Engine 5 (UE5) のコンポーネント(Actor Component)のイベントグラフから、それを所有しているアクター(オーナー Actor)の変数にアクセスするには、「Get Owner」で所有アクターの参照を取得し、対象のアクタークラスへ「Cast To」してから、そのクラスの変数を読み書きするのが基本的な方法だ。ここで言う「親クラス」は、継承関係の親(スーパークラス)ではなく、コンポーネントを保持している側のアクター(所有者)を指すことが多い。本記事ではこの「所有アクターの変数へアクセスする」ケースを中心に、代表的な3つの手法と、それぞれの長所・短所、具体的な手順、つまずきやすい落とし穴までを整理する。

この記事の要点
  • コンポーネント自身は変数を持てるが、それを所有するアクターの変数へ直接はアクセスできないため、まず所有者の参照を得る必要がある。
  • もっとも基本的なのは「Get Owner」→「Cast To 所有アクターのクラス」の流れ。Cast 成功ピンの先で、そのクラスの変数の Get / Set が使えるようになる。
  • 毎回キャストするのを避けたい場合は、コンポーネントに所有アクターへの参照変数を持たせ、BeginPlay でキャスト結果を一度だけ保存する方法が有効。
  • 特定のクラスに依存させたくない(汎用コンポーネントにしたい)場合は、ブループリントインターフェイスを介して疎結合にする。
  • Cast は失敗すると参照が無効(None)になるため、Cast Failed ピンや Is Valid のチェックを前提に組むことが安定動作の鍵となる。

状況の整理:何にアクセスしたいのか

UE5 のコンポーネントは、それ単体でレベルに配置されるのではなく、アクターやポーン、キャラクターといった「所有アクター(Owning Actor)」にアタッチされてはじめて機能する。たとえば体力管理を担う Actor Component を作り、その内部処理から、所有アクター側に定義された「現在の体力」「最大体力」といった変数を読み書きしたい、というのが典型的な状況だ。

ここで重要なのは、コンポーネントのイベントグラフのスコープからは、所有アクターのメンバ変数が直接は見えないという点である。コンポーネントとアクターは別のオブジェクトなので、まず「自分は誰に所有されているのか」を取得し、その参照を経由してアクセスする必要がある。逆に、所有アクター側からコンポーネントを操作するのは、コンポーネント変数の Get で参照が取れるため比較的容易だ。本記事は前者、コンポーネントから所有アクターへ向かう方向を扱う。

方法①:Get Owner → Cast To でアクセスする(基本)

もっとも基本的で、まず最初に押さえておきたいのがこの方法だ。コンポーネントの Get Owner ノードは、自分を所有しているアクターを Actor 型の参照として返す。ただし戻り値はあくまで基底の Actor 型であり、この段階では所有アクター固有の変数は見えない。そこで Cast To で具体的なアクタークラスへ変換する。

たとえば所有アクターのクラスを BP_MyActor、そこに MyHealth という変数があるとする。手順は次のとおり。

  1. 所有アクター BP_MyActor 側に、アクセスしたい変数(例:MyHealth)を用意しておく。
  2. コンポーネントのイベントグラフで Get Owner ノードを配置する。
  3. その出力を Cast To BP_MyActor ノードに接続する。
  4. Cast の成功側出力(As BP My Actor)ピンをドラッグし、Get MyHealthSet MyHealth ノードを作成して値を読み書きする。

変数だけでなく、所有アクター側で定義した関数(例:ダメージ処理のカスタム関数)も、同じく Cast 後の参照ピンから呼び出せる。なお、変数を「外部から触れるようにしたい」場合は、所有アクター側で対象変数の「インスタンス編集可能(Instance Editable)」や「Blueprint Read/Write」といった可視性の設定を確認しておくとよい。

下記は、この流れをノードのつながりとしてメモした疑似コードのイメージだ。

// コンポーネントのイベントグラフ(疑似表記)
Event BeginPlay
  Owner = Get Owner()    // 戻り値は Actor 型
  Cast To BP_MyActor (Owner)
    Success -> Set As_BP_MyActor.MyHealth = 100
    Cast Failed -> (所有者が BP_MyActor ではない/処理しない)

この方法は手軽だが、所有アクターのクラスを固定で名指しするため、別のクラスのアクターにそのコンポーネントを付けると Cast が失敗する。汎用的に使い回したいコンポーネントには向かない点に注意したい。

方法②:所有アクターへの参照変数を持たせ、BeginPlay で一度だけ設定する

方法①では、変数にアクセスするたびに Get OwnerCast To を繰り返すことになり、グラフが冗長になりやすい。そこで、コンポーネント側に「所有アクター型の参照変数」を1つ用意し、ゲーム開始時に一度だけキャスト結果を保存しておく方法がよく使われる。

  1. コンポーネントに、型を BP_MyActor(対象クラス)にした変数、たとえば CachedOwner を作成する。
  2. コンポーネントの Event BeginPlayGet OwnerCast To BP_MyActor を実行する。
  3. Cast 成功ピンの出力を、先ほどの CachedOwnerSet で保存する。
  4. 以降は CachedOwnerGet するだけで、毎回キャストせずに所有アクターの変数・関数へアクセスできる。

コンポーネントの BeginPlay は、所有アクターがプレイ開始したタイミング(あるいはプレイ開始後にコンポーネントが生成された場合はその生成時)に呼ばれる。つまり、この時点では所有アクターはすでに初期化が進んでおり、参照を取得して保存するには適したタイミングといえる。ただし、キャッシュした参照を使う処理が BeginPlay より前に走る可能性がある場合(コンストラクション中など)は、参照がまだ未設定(None)になり得るため注意が必要だ。

方法③:ブループリントインターフェイスで疎結合にする

「このコンポーネントを、特定のアクタークラスに縛られず、さまざまなアクターに付けたい」という場合は、ブループリントインターフェイスを使って具体的なクラスへの依存を避ける方法が有効だ。直接そのクラスの変数を読むのではなく、「値を返す(または値を渡す)関数」をインターフェイスとして定義し、所有アクター側でその関数を実装するという考え方になる。

  1. インターフェイス(例:BPI_Damageable)を作成し、GetCurrentHealthApplyDamage のような関数を宣言する。
  2. 変数を公開したい所有アクター側で、そのインターフェイスを実装し、自身の変数を返す/更新する処理を書く。
  3. コンポーネント側では Get Owner で取得した参照に対し、Does Implement Interface で確認したうえで、インターフェイス経由のメッセージ(関数)を呼ぶ。

この方式なら、コンポーネントは「相手がそのインターフェイスを実装しているかどうか」だけを気にすればよく、具体的なクラス名を知る必要がない。結果として、同じコンポーネントを複数の異なるアクターで再利用しやすくなる。一方で、インターフェイスの定義・実装という一手間が増えるため、単一のクラスだけで使う小規模なケースでは過剰になることもある。

3つの方法の比較

方法 仕組み 長所 短所 向いている場面
① Get Owner → Cast 毎回キャストして変数へアクセス 仕組みが単純で理解しやすい クラスを名指しするため再利用性が低い・毎回キャスト 所有アクターのクラスが固定で、まず動かしたいとき
② 参照変数にキャッシュ BeginPlay で一度キャストし参照を保存 以降はキャスト不要でグラフが簡潔 初期化タイミング前は参照が無効になり得る 同じ所有アクターへ何度もアクセスするとき
③ インターフェイス 関数をインターフェイス経由で呼ぶ 具体クラスに依存せず再利用しやすい 定義・実装の手間が増える 複数の異なるアクターで使い回す汎用コンポーネント

具体例:体力コンポーネントから所有アクターの体力を減らす

イメージを具体化するため、ダメージ処理を担う Actor Component から、所有アクターの体力変数を減らす例を考える。ここでは方法②(参照のキャッシュ)を使う。

  1. 所有アクター BP_EnemyHealth(Float、初期値 100)を用意する。
  2. 体力コンポーネント側に CachedOwner(型:BP_Enemy)を作成する。
  3. Event BeginPlayGet OwnerCast To BP_Enemy → 成功ピンを Set CachedOwner へ。
  4. ダメージを受けるイベント(例:オーバーラップ)で、CachedOwner が有効か Is Valid で確認する。
  5. 有効なら Get Health から受けたダメージ量を引き、Set Health で書き戻す。

// ダメージ適用(疑似表記)
Event OnDamage (Damage)
  Is Valid (CachedOwner)?
    Yes -> CachedOwner.Health = CachedOwner.Health - Damage
    No  -> (参照が無効なので何もしない)

このように参照をキャッシュしておくと、ダメージ処理のたびにキャストする必要がなくなり、グラフがすっきりする。なお値の上限・下限のクランプ(0未満や最大値超えの防止)など、ゲームロジック上の補正は別途必要になる点は留意したい。

つまずきやすい落とし穴

落とし穴 内容と対策
Cast 失敗で参照が None になる 所有アクターが指定クラスでない場合、Cast は失敗し出力は無効(None)になる。Cast Failed ピンや Is Valid を必ず通す設計にし、None のまま変数へアクセスしないようにする。
Get Owner の戻り値は基底 Actor 型 Get Owner はあくまで Actor 型を返すため、その時点では所有アクター固有の変数は見えない。具体クラスへ Cast するか、インターフェイス経由でアクセスする必要がある。
初期化タイミングのずれ キャッシュした参照を、BeginPlay より前(コンストラクション時など)に使おうとすると未設定のことがある。参照に依存する処理は所有アクターの初期化後に走らせるか、使用前に有効性を確認する。
特定クラスへの密結合 方法①・②はクラス名を直接参照するため、別クラスのアクターに付けると機能しない。汎用化したいならインターフェイスで疎結合にする方針を検討する。

よくある質問(FAQ)

Q. この記事の「親クラス」は継承の親クラスのことですか?

ここで扱っているのは、継承上の親(スーパークラス)ではなく、コンポーネントを保持している「所有アクター」のことを指している。コンポーネントから見て自分を持っている相手、という意味合いだ。継承の親クラスのメンバへは、通常は同一クラス階層内であれば直接アクセスでき、本記事のような Get Owner + Cast の流れは不要となる。

Q. 毎回 Cast するのと、参照をキャッシュするのはどちらがよいですか?

同じ所有アクターへ繰り返しアクセスするなら、BeginPlay で一度キャストして参照変数に保存する方法(方法②)のほうがグラフが簡潔になり扱いやすい。アクセスが1回限りであれば、方法①のその場キャストでも十分だ。いずれの場合も、参照が無効になり得る前提で Is Valid 等の確認を入れておくと安定する。

Q. 1つのコンポーネントを複数の種類のアクターで使い回したい場合は?

特定のクラスへ Cast する方式だと、対象クラス以外では失敗してしまう。複数の異なるアクターで共通利用したいなら、ブループリントインターフェイス(方法③)を使い、具体的なクラス名に依存せず関数経由でやり取りする設計が適している。

まとめ

コンポーネントのイベントグラフから所有アクター(いわゆる「親」側)の変数にアクセスする基本は、「Get Owner」で所有者を取得し、「Cast To」で具体クラスへ変換してから変数を読み書きすることだ。アクセスが頻繁なら参照をキャッシュし、汎用性が必要ならインターフェイスで疎結合にする、と用途に応じて使い分けるとよい。いずれの手法でも、Cast の失敗や参照の無効化を前提に、有効性チェックを挟んで安全に組むことが、安定した動作につながる。具体的なノード名や挙動はバージョンによって細部が異なる場合があるため、最終的には利用中のエンジンバージョンの公式ドキュメントで確認することを推奨する。

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 床の上に乗ったらイベントを発生させる方法
  2. OverlapAllDynamicとOverlapAllの違い
  3. タイトル画面を作る方法
  4. サードパーソンテンプレートでのキャラクター表示の仕組みと非表示にする方法
  5. ボタンに文字を記載する方法
  6. Event ActorBeginOverlapとOn Component Begin Overlapの違い
  7. キャラクターに特定のオブジェクトとの当たり判定を付ける
  8. 特定のオブジェクトに触れたとき、キャラクターが倒れるようにする
  9. 動いているオブジェクトに静止しているキャラクターが当たり判定を持たない原因と解決方法
  10. 「On Component Hit」に「Cast To ~」で複数のクラスを指定する方法
  11. Blenderファイルをインポートする方法
  12. 鏡を作成する方法
  13. レベルブループリントでキャラクターの出現を設定する方法
  14. サードパーソンテンプレートにおけるキャラクター出現の定義
  15. アイテムに近づいたらボタンを押してイベントを発火させる方法
  16. 画面の中央にメッセージを表示する方法
  17. どこからでも呼び出せるカスタムイベントを作成する方法
  18. カスタムイベントに引数を追加する方法
  19. 「Get Overlapping Actors」から特定のクラスの場合のみ処理を実行する方法
  20. オブジェクトに近づいている間だけメッセージを表示する方法
  21. PCの画面を操作するUIを作る方法
  22. コンテンツブラウザに画像を追加する方法
  23. SetInputMode_UIOnlyを取り消す方法
  24. 特定の画像の上にマウスカーソルを置いたら手マークにする方法
  25. オブジェクトがアウトライナーで選択できない原因と解決策
  26. PlayerStartを作成する方法
  27. メニュー画面を作成して開く方法
  28. 「Esc」キーを押してメニュー画面を開く方法
  29. イベントの「On Clicked」と「On Pressed」の違い
  30. 「Set Input Mode」の種類と使い方
  31. 「Set Game Paused」の使い方と詳細解説
  32. Motion Matchingとは?
  33. 「GameMode」と「GameModeBase」の違い
  34. マップに配置したTargetPointを取得する方法
  35. TargetPointにタグをつけて取得する方法
  36. Spawnしたインスタンスがイベントを実行する方法
  37. 特定の時間ごとに処理を実行する方法
  38. 数値をランダムで出力する方法
  39. ThirdPersonテンプレートでキャラクターの移動を歩くように変更する方法
  40. MaxWalkSpeedを変更する方法
  41. しゃがむ動作を導入する方法
  42. キャラクターのアニメーションを設定する方法
  43. 導入済みのプラグインを確認する方法
  44. Motion Matchingの導入と必要なプラグイン
  45. プレイヤーを非表示にする方法
  46. カメラを傾ける角度を制限させる方法
  47. 配列からランダムに重ならない要素を特定の数取得する方法
  48. カメラの映す画面に文字やエフェクトを付ける方法
  49. キャラクターやメッシュを非表示にした際にカメラが移動しなくなる問題の解決方法
  50. プライマリーデータアセットを活用する方法
  51. プレイヤーのHPといった変数を定義する最適な場所
  52. カメラに映った画面をスクリーンショットとして保存する方法
  53. ゲーム内のカメラ映像を保存して再表示する方法
  54. HighResShot を使って高解像度の画像を保存する方法(UE5)
  55. HighResShotで保存した画像のファイル名を取得する方法
  56. SceneCapture2DとFrameGrabberの画像保存方法の比較
  57. SceneCapture2Dを使用して画像を保存・取得する方法
  58. HighResShotとTake High Res Screenshotの違い
  59. ゲーム終了ボタンを作成する方法
  60. 「Save Game To Slot」の戻り値がfalseになる問題の解決方法
  61. 画面上にメッセージを指定された時間表示させる方法
  62. シェーダコンパイル時間を短縮する方法
  63. 「Take High Res Screenshot」実行時に「シェーダをコンパイル」に長時間待たされる問題とその解決策
  64. データベースを活用する方法
  65. UE5.5がインストールされた環境にUE5.4を追加で導入する方法
  66. World PartitionとWorld Compositionの違い
  67. オープンワールドテンプレートとは?
  68. ポーンをスポーンさせても視点を切り替えない方法
  69. キャラクター同士がすり抜けてしまう問題の解決方法
  70. キャラクターの外見を動的に変更
  71. World Partitionでインスタンスが「アンロード済み」になる問題
  72. データ アセットとデータ テーブルの違い
  73. コンポーネントイベントグラフ内で親クラスの変数にアクセスする方
  74. エディターのソースコードの自動保存の頻度を高める方法
  75. SpawnActorでSpawn Transform Rotationが反映されない理由
  76. ミニマップを表示しポーンの位置を反映する方法
  77. RInterp ToとVInterp Toの違い
  78. 毎秒実行するイベントの定義方法
  79. Niagara のエフェクトにコリジョンを持たせる方法
  80. 「Overlap」と「Hit」の違い
  81. OverlapはあるがHitがない原因
  82. Overlapした位置の座標を取得する方法
  83. ブループリントでレベル間のパラメータを受け渡す方法

最近更新/作成されたページ