敵に攻撃を当てて、ダメージも入っている。でも、敵の頭上にHPバーを出したいのに、画面の隅に貼り付いたまま敵についていってくれません。被弾のたびに「25」と数字を飛ばしたいのに、出し方が分かりません。
これらは、UMGで作るHUD とは別の仕組みが要ります。HUDは画面に貼るUIですが、頭上HPバーやダメージ数字は ワールドの中のActorに追従するUI だからです。この記事では、その主役になる Widget Component の使い方と、ダメージ数字を軽く出す方法を、敵ラッシュで数字が飛ぶ画面を作りながら解説します。
この記事でわかること
- 画面に貼るUI(Add to Viewport)と Actorに付くUI(Widget Component)の違い
- Widget Componentの Space:Screen と World の使い分け
- 頭上HPバーを Get User Widget Object で更新する
- ダメージ数字は 画面投影方式 で軽く出す(被弾ごとの生成を避ける)
- 大量に出しても重くしない 注意点
- 実践: 敵の頭上にHPバー、被弾でダメージ数字が飛ぶ
画面に貼るUIと、Actorに付くUI
UMGのWidgetを表示するには、大きく2つの道があります。この違いが、頭上バーを作る出発点です。

- Add to Viewport(画面に貼る): Widgetを画面の最前面に平らに貼ります。スコアやミニマップのようなHUD向け。ワールドのどこを見ていても、画面の同じ位置に居続けます
- Widget Component(Actorに付ける): WidgetをActorのコンポーネントとして持たせます。親のActorが動けば、Widgetも一緒に動きます。 頭上HPバーやネームプレートはこちら です
「敵についていくバー」が欲しいのに Add to Viewport で作ってしまうと、画面に貼りついて敵を追えません。まず「そのUIはActorに付いて動くのか、画面に貼るのか」を決めるのが最初の分岐です。
Widget Componentを追加する
頭上バーは、敵のBlueprintに Widget Component を1つ足すところから始まります。

- 敵Blueprintの Components パネルで Add → Widget を選び、Meshの子として追加する
- 追加したWidget Componentを選び、Detailsの Widget Class に、表示したいUMG(例:
WBP_EnemyHealthBar)を割り当てる - Transform の位置Zを上げて、バーを頭の上あたりへ移す
これだけで、敵の頭上にWidgetが表示され、敵が歩けばバーもついてきます。あとは中身のProgress Barを、敵のHPに合わせて更新するだけです。
SpaceのScreenとWorld
Widget Componentを選ぶと、Detailsに Space という設定があります。ここがHPバーの見え方を左右します。

- Screen: Widgetが常にカメラの方を向きます(画面に対して正対)。どの角度から見ても読めるので、 頭上HPバーやネームプレート向け 。遠近で傾かず、他の物体に隠れにく いです
- World: Widgetが3D空間に 板ポリゴンとして 置かれます。遠近で小さくなり、角度がつき、手前の物に遮られます。壁の操作パネルや設置端末のような、 世界に溶け込ませたいUI向け です
頭上バーは、まず Screen で始めれば間違いありません。「世界の中の板」として見せたくなったときにWorldへ切り替えます。
頭上HPバーを更新する
Widget Componentを付けても、それは「Widgetの入れ物」でしかありません。中身のProgress Barを更新するには、 入れ物から実際のWidgetを取り出す 必要があります。

そのためのノードが Get User Widget Object です。Widget Componentからこのノードで中身のWidgetを取り出し、自分のUMGクラス(WBP_EnemyHealthBar )へ Cast すれば、中のProgress Barや関数へアクセスできます。
(敵Blueprint)HPが変わったとき
Get(HealthBar Widget Component)
→ Get User Widget Object
→ Cast To WBP_EnemyHealthBar
→ Set Percent(= CurrentHealth / MaxHealth)
ここで Binding(バインディング)を使わない のが大事です。Progress BarのPercentをBindingで毎フレーム関数から引くと、敵の数だけ毎フレーム計算が走ります。HPが変わった瞬間だけ Set Percent を呼ぶ方が、ずっと軽く済みます(詳しくは UIのパフォーマンス最適化 )。
ダメージ数字は画面投影で軽く出す
被弾のたびに飛び出す「25」のようなダメージ数字。これも頭上バーと同じくWidget Componentで作れそうに見えますが、 被弾ごとにWidget Componentを生成・破棄するのはやや重い です。敵ラッシュで数字が雨のように出る場面では、これが効いてきます。

軽い定番は 画面投影方式 です。
- 被弾したら
WBP_DamageNumberを Create Widget → Add to Viewport(画面に置く) - Project World Location to Widget Position で、被弾した3D地点の座標を 画面上の2D座標へ変換 し、その位置へ数字を移す
- UMGアニメーションで 上へ流しながらフェードアウト し、終わったら Remove from Parent で自壊する
Project World Location to Widget Position は、ワールドの座標を「今その地点は画面のどこに映っているか」に変換するノードです。これを使えば、重いWidget Componentを毎回作らずに、画面の正しい位置へ数字を出せます。
実践:頭上バーとダメージ数字を組む
ARPGの雑魚戦、タワーディフェンスの敵ラッシュ、ハクスラの数字の雨。 「頭上のバーが減り、被弾で数字が飛ぶ」 はジャンルを問わない定番表現です。ここではその1本を、頭上バー(Widget Component)とダメージ数字(画面投影)で組みます。
作るのは、 攻撃するたびに敵の頭上バーが減り、被弾地点に「25」の数字がふわっと浮かんで消える 画面です。
動かすとこうなります。敵に斬りかかると、頭の上のHPバーがスッと減る。同時に、当たった位置に「25」が現れ、0.6秒かけて上へ流れながら薄くなって消える。連続で当てれば、数字がぽんぽんと重なって飛びます。

再現条件
| 項目 | 設定 |
|---|---|
敵 BP_Enemy(Character) | 変数 CurrentHealth(Float, 100.0 )、MaxHealth(Float, 100.0 )。Widget Component HealthBar を追加し Space = Screen |
頭上バー WBP_EnemyHealthBar | Progress Bar 1本。関数 Set Percent で更新 |
ダメージ数字 WBP_DamageNumber | Text Block 1つ。上へ40px移動+フェードのUMGアニメーション(0.6秒)を1本作る |
| ダメージの発生 | Event AnyDamage(Apply Damage で敵に届く) |
ステップ1:被弾で頭上バーを更新する
BP_Enemy の Event AnyDamage で、HPを減らしてから頭上バーの Set Percent を呼びます。

BP_Enemy(イベントグラフ)
Event AnyDamage(Damage)
→ Set CurrentHealth = CurrentHealth − Damage
→ Get(HealthBar Widget Component)→ Get User Widget Object
→ Cast To WBP_EnemyHealthBar
→ Set Percent(= CurrentHealth / MaxHealth)
→ (被弾地点で)ShowDamageNumber を呼ぶ(ステップ2)
ステップ2:被弾地点にダメージ数字を出す
数字 は画面投影方式で出します。Create Widget → Add to Viewport → Project World Location to Widget Position の順です。

ShowDamageNumber(被弾地点 HitLocation を受け取る)
→ Create Widget(Class: WBP_DamageNumber)
→ Add to Viewport
→ Project World Location to Widget Position(Player Controller, HitLocation)
→ Set Position in Viewport(= 変換された2D座標)
→ Set Text("25")
→ Play Animation(上へ流れてフェード)
→ (アニメ終了イベント)Remove from Parent
数字が薄くなって消えたら 必ず Remove from Parent します。これを忘れると、透明な数字Widgetが画面に溜まり続け、だんだん重くなります。
確かめる
Playして敵を攻撃してください。うまくいけば、頭上のHPバーが減り、当たった位置に「25」が浮かんで、0.6秒で上へ流れて消えます。
うまくいかないときの切り分けです。
- バーが減らない →
Get User Widget Objectの後のCastが失敗しています。Widget ClassにWBP_EnemyHealthBarを割り当てたか確認 - 数字が変な位置に出る →
Project World Location to Widget Positionに渡す座標が違います。被弾地点(HitLocation)を渡しているか確認 - 数字が消えずに溜まる → アニメ終了後の
Remove from Parentが呼ばれていません
ポイントは2つです。
- 追従するものはWidget Component、飛ぶものは画面投影: 頭上バーはActorに付いて動き続けるのでWidget Component、ダメージ数字は一瞬で消えるので軽い画面投影。この使い分けが、敵が増えても軽いままの分かれ道です
- 出したら必ず片づける: 一瞬のUIほど
Remove from Parentを忘れがちです。数字・エフェクト系のWidgetは「出す」と「消す」を必ずセットで書いてください(詳しくは UIのパフォーマンス最適化 )
おまけ:先に知っておくと良いこと
距離で消す・向きを整える。 頭上バーが遠くの敵にまで出ていると、画面がバーだらけになります。プレイヤーとの距離が一定以上なら Widget Componentを Set Visibility で隠すと、手前の敵だけにバーが出て見やすくなります。Screen spaceなら常にカメラを向くので、向きの調整は不要です。
数字の色や大きさで情報を足す。 ダメージ数字は、ただ数を出すだけでなく、 クリティカルは赤く大きく、通常は白く小さく と変えると、手応えが一気に増します。WBP_DamageNumber にText Blockの色とサイズを引数で渡せるようにしておくと、1つのWidgetで表現の幅が広がります。
プールで使い回すと更に軽い。 数字が毎秒何十個も飛ぶ本格的なハクスラでは、毎回 Create Widget するのも積もれば重くなります。あらかじめ数十個作っておき、使い終わっ たら消さずに隠して再利用する「オブジェクトプール」にすると、生成コストがゼロに近づきます。まずは生成・破棄で作り、重くなってから検討すれば十分です。
まとめ
ワールドに追従するUIは、2つの道具を使い分けて作ります。
| 用途 | 使う道具 | 理由 |
|---|---|---|
| 頭上HPバー・ネームプレート | Widget Component(Space=Screen) | Actorに付いて動き続ける。常にカメラを向く |
| 飛び出すダメージ数字 | 画面投影(Add to Viewport+Project World Location to Widget Position) | 一瞬で消える。被弾ごとの生成を避けて軽く |
| 中身の更新 | Get User Widget Object → Cast | 入れ物から実Widgetを取り出して操作 |
そして共通の心得が、 Bindingを避け、出したら片づける ことです。追従UIは敵の数だけ増えるので、軽さの積み重ねが効いてきます。
これで、当たった手応えを画面に返せるようになりました。あなたのゲームの敵は、何ダメージで倒れるでしょうか。その数字を、頭上に飛ばしてみてください。
さらに学ぶために
- UMGウィジェットブループリント(基礎から応用) — 画面に貼るHUDの基礎
- 体力とダメージ(Apply Damage) — 頭上バーを減らす発生源
- UIのパフォーマンス最適化 — Bindingと再描画の落とし穴
- ゲームフィールとヒットフィードバック — 数字と一緒に重ねる演出