【Unreal Engine】頭上HPバーとダメージ数字:ワールドに追従するUIを作る

作成: 2026-07-23

敵の頭上に付くHPバーや、被弾で飛び出すダメージ数字の作り方。画面に貼るUI(Add to Viewport)とActorに付くUI(Widget Component)の違い、SpaceのScreenとWorldの使い分け、Get User Widget Objectでバーを更新する方法、そしてダメージ数字を軽く出す画面投影方式まで。敵ラッシュで数字が雨のように飛ぶ様子を作ります。

敵に攻撃を当てて、ダメージも入っている。でも、敵の頭上にHPバーを出したいのに、画面の隅に貼り付いたまま敵についていってくれません。被弾のたびに「25」と数字を飛ばしたいのに、出し方が分かりません。

これらは、UMGで作るHUD とは別の仕組みが要ります。HUDは画面に貼るUIですが、頭上HPバーやダメージ数字は ワールドの中のActorに追従するUI だからです。この記事では、その主役になる Widget Component の使い方と、ダメージ数字を軽く出す方法を、敵ラッシュで数字が飛ぶ画面を作りながら解説します。

敵の頭上にHPバーが付き、被弾で「25」の数字がふわっと浮かぶ様子とソフトブルーのクレイ人形

この記事でわかること

  • 画面に貼るUI(Add to Viewport)と Actorに付くUI(Widget Component)の違い
  • Widget Componentの Space:Screen と World の使い分け
  • 頭上HPバーを Get User Widget Object で更新する
  • ダメージ数字は 画面投影方式 で軽く出す(被弾ごとの生成を避ける)
  • 大量に出しても重くしない 注意点
  • 実践: 敵の頭上にHPバー、被弾でダメージ数字が飛ぶ

Sponsored

画面に貼るUIと、Actorに付くUI

UMGのWidgetを表示するには、大きく2つの道があります。この違いが、頭上バーを作る出発点です。

Add to Viewportは画面に平らに貼りつき、Widget ComponentはActorに付いて一緒に動くことを対比した図
  • 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にWidgetを追加し、DetailsのWidget ClassにWBP_EnemyHealthBarを割り当てる様子
  1. 敵Blueprintの Components パネルで AddWidget を選び、Meshの子として追加する
  2. 追加したWidget Componentを選び、Detailsの Widget Class に、表示したいUMG(例:WBP_EnemyHealthBar )を割り当てる
  3. Transform の位置Zを上げて、バーを頭の上あたりへ移す

これだけで、敵の頭上にWidgetが表示され、敵が歩けばバーもついてきます。あとは中身のProgress Barを、敵のHPに合わせて更新するだけです。

SpaceのScreenとWorld

Widget Componentを選ぶと、Detailsに Space という設定があります。ここがHPバーの見え方を左右します。

Screen spaceは常にカメラへ正対して読みやすく、World spaceは3D空間に板として置かれ遠近と遮蔽が効くことを対比した図
  • Screen: Widgetが常にカメラの方を向きます(画面に対して正対)。どの角度から見ても読めるので、 頭上HPバーやネームプレート向け 。遠近で傾かず、他の物体に隠れにくいです
  • World: Widgetが3D空間に 板ポリゴンとして 置かれます。遠近で小さくなり、角度がつき、手前の物に遮られます。壁の操作パネルや設置端末のような、 世界に溶け込ませたいUI向け です

頭上バーは、まず Screen で始めれば間違いありません。「世界の中の板」として見せたくなったときにWorldへ切り替えます。

Sponsored

頭上HPバーを更新する

Widget Componentを付けても、それは「Widgetの入れ物」でしかありません。中身のProgress Barを更新するには、 入れ物から実際のWidgetを取り出す 必要があります。

Widget ComponentのGet User Widget ObjectからCast To WBP_EnemyHealthBar、Set Percentへつなぐ流れの図

そのためのノードが 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を生成・破棄するのはやや重い です。敵ラッシュで数字が雨のように出る場面では、これが効いてきます。

被弾ごとにWidget Componentを生成する重い方式と、画面に置いてProject World Location to Widget Positionで座標を移す軽い方式を対比した図

軽い定番は 画面投影方式 です。

  1. 被弾したら WBP_DamageNumberCreate WidgetAdd to Viewport(画面に置く)
  2. Project World Location to Widget Position で、被弾した3D地点の座標を 画面上の2D座標へ変換 し、その位置へ数字を移す
  3. UMGアニメーションで 上へ流しながらフェードアウト し、終わったら Remove from Parent で自壊する

Project World Location to Widget Position は、ワールドの座標を「今その地点は画面のどこに映っているか」に変換するノードです。これを使えば、重いWidget Componentを毎回作らずに、画面の正しい位置へ数字を出せます。

Sponsored

実践:頭上バーとダメージ数字を組む

ARPGの雑魚戦、タワーディフェンスの敵ラッシュ、ハクスラの数字の雨。 「頭上のバーが減り、被弾で数字が飛ぶ」 はジャンルを問わない定番表現です。ここではその1本を、頭上バー(Widget Component)とダメージ数字(画面投影)で組みます。

作るのは、 攻撃するたびに敵の頭上バーが減り、被弾地点に「25」の数字がふわっと浮かんで消える 画面です。

動かすとこうなります。敵に斬りかかると、頭の上のHPバーがスッと減る。同時に、当たった位置に「25」が現れ、0.6秒かけて上へ流れながら薄くなって消える。連続で当てれば、数字がぽんぽんと重なって飛びます。

斬るたびに頭上バーが減り、被弾位置に「25」が浮かんで上へ流れ消える一連の流れを示した実例図

再現条件

項目設定
BP_Enemy(Character)変数 CurrentHealth(Float, 100.0 )、MaxHealth(Float, 100.0 )。Widget Component HealthBar を追加し Space = Screen
頭上バー WBP_EnemyHealthBarProgress Bar 1本。関数 Set Percent で更新
ダメージ数字 WBP_DamageNumberText Block 1つ。上へ40px移動+フェードのUMGアニメーション(0.6秒)を1本作る
ダメージの発生Event AnyDamageApply Damage で敵に届く)

ステップ1:被弾で頭上バーを更新する

BP_EnemyEvent AnyDamage で、HPを減らしてから頭上バーの Set Percent を呼びます。

Event AnyDamageからHP減算、Get HealthBar→Get User Widget Object→Cast→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 WidgetAdd to ViewportProject World Location to Widget Position の順です。

Create Widget WBP_DamageNumberからAdd to Viewport、Project World Location to Widget Position、Set 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は敵の数だけ増えるので、軽さの積み重ねが効いてきます。

これで、当たった手応えを画面に返せるようになりました。あなたのゲームの敵は、何ダメージで倒れるでしょうか。その数字を、頭上に飛ばしてみてください。

さらに学ぶために