HPを減らす処理はできた。次は、画面の左上に体力バーを出して、残りの体力をひと目で分かるようにしたい。そこで使うのが、UEのUI作成機能 UMG(Unreal Motion Graphics) です。
UMGでは、文字やバーを並べた設計図を作り、ゲーム中にその実体を画面へ載せます。この記事では 左上にHPバーを表示する → Hキーで25ずつ減らす → HPが変わったときに表示を更新する ところまで、同じ例で組み立てます。
この記事でわかること
- Widgetを「作る」と「画面に載せる」の違い
- DesignerとGraph、アンカーとコンテナの役割
- HPを0〜1の割合へ変えて、バーへ渡す方法
- HPの変更通知と、表示開始時の初期値の反映
Widgetは「作る」と「載せる」の2段階
Widget(ウィジェット) は、文字、ボタン、HPバーなど、UIを構成する部品です。それらをまとめて一つの画面として作れるのが Widget Blueprint。HPや残弾数のように、プレイ中の情報を画面に重ねて見せるUIを HUD と呼びます。
他のエンジンでいうと: Unity の uGUI / UI Toolkit、Godot の Control ノード に当たります。画面を1つのアセットとして作り、あとから開いて重ねるところも同じです。
Widget Blueprintは設計図なので、アセットを保存しただけではゲーム画面に現れません。表示するには、次の2段階が必要です。

- Create Widget で、 設計図から実体を作る。
- その実体を Add to Viewport で、ゲームの表示領域へ載せる。
Create WidgetのReturn Valueが、今作った実体です。これを変数へ保存しておくと、後で同じHUDを指定して、値を更新したり画面から外したりできます。この「後から同じ相手を指定するための値」が 参照 です。
親Widgetの中に並べた文字やバーは、親と一緒に表示されます。部品ごとにAdd to Viewportを呼ぶ必要はありません。
Designerで、見せる部品と並べる部品を組む
Widget Blueprintには、見た目を組む Designer と、処理を組む Graph があります。

| タブ | 何を決めるか | 今回の例 |
|---|---|---|
| Designer | 部品の並び、大きさ、色 | 左上に「HP」とバーを並べる |
| Graph | いつ、何を更新するか | 新しいHPを受け取り、バーの長さを変える |
DesignerのPaletteは部品置き場、Hierarchyは部品の親子関係です。部品には、TextやProgress Barのように 情報を見せるもの と、Canvas PanelやHorizontal Boxのように 子の配置を決めるもの があります。
Canvas Panelでは、子の位置や 大きさを指定できます。Horizontal Boxは子を横へ、Vertical Boxは縦へ並べます。今回なら、CanvasにHP表示のまとまりを置き、その中で「HP」とバーを横に並べる形です。
このように 大枠の位置を決めることと、まとまりの中を並べることを分ける と、部品を足したときにも調整しやすくなります。
アンカー:画面のどこを基準にするか
HPバーを左上に置いたら、画面が横長になっても左上に残ってほしい。その基準になるのが アンカー(Anchors) です。親のCanvas Panelのどこから位置を測るかを決めます。
| 置きたい場所 | アンカー | 例 |
|---|---|---|
| 左上の隅 | 左上 | HP、スコア |
| 右上・右下の隅 | それぞれの隅 | ミニマップ、残弾数 |
| いつも中央 | 中央 | 照準、確認ダイアログ |
| 親いっぱいに広げる | 上下左右へストレッチ | 暗幕、背景 |
判断の基準は、「画面が広くなったとき、この部品はどこにいてほしいか」 です。
Anchorsは、Canvas Panelの 直接の子 にあるSlotで設定します。Slot は、その部品を親の中へどう収めるかの設定です。Horizontal Boxの中のバーを選んでも、Canvas用のAnchorsは出ません。今回は、Canvasへ直接置くHorizontal Boxに設定します。
Alignment は、部品自身のどこを位置の基準へ合わせるかを決めます。(0, 0)なら部品の左上、(0.5, 0.5)なら中央です。中央アンカーへダイアログの中心を合わせたい場合は、Alignmentも(0.5, 0.5)にします。

アンカーは位置の基準で、あらゆる画面サイズへの対応を一つで済ませる設定ではありません。文字や余白の大きさには、解像度に応じてUI全体を拡大・縮小するDPIスケーリングも関係します。まずは左上の配置を作り、DesignerのScreen Sizeで画面比率を変えて確かめましょう。
準備:HPを持つキャラクターを用意する
今回は、プレイヤー1人のThird Person Blueprintプロジェクト を使います。新しく作る場合は、Variantsがある版ではNoneを選びます。WASDで歩き、Spaceでジャンプできる状態から始めてください。
- BP_ThirdPersonCharacterを複製し、
BP_HUDPracticeと名付ける。 - レベルのWorld Settingsから使用中のGameModeを開き、Default Pawn ClassをBP_HUDPracticeへ変更する。
- レベルへキャラクターを手置きせず、PlayerStartから生成する。Playして、複製したキャラクターが動くことを確認する。
Default Pawn Classは、プレイヤー用に生成するキャラクターの種類です。PlayerStartは、その出現位置の目印です。
この練習では、キャラクターが自分のHUDを一つ作ります。自分自身の参照をHUDへ渡すので、HUD側で「操作中のキャラクターを探す」手順を挟ま ずに、表示する相手を決められます。複数人プレイや復活をまたぐHUDの管理は、最後に分けて考えます。
BP_HUDPracticeに次の変数を作り、コンパイルして既定値を設定します。Float は、小数を扱える数値の型です。
| 変数 | 型 | 既定値 | 役割 |
|---|---|---|---|
| MaxHealth | Float | 100 | 最大HP |
| CurrentHealth | Float | 100 | 今のHP |
この練習ではMaxHealthを100のまま使います。後でHPの割合を割り算で求めるため、最大HPは0より大きい値にします。変数をPrivateにせず、HUDから現在値を読めるようにしておきます。

実践1:左上にHPバーを表示する
1. Widget Blueprintを作る
コンテンツブラウザで「User Interface → Widget Blueprint」を作り、親Classを選ぶ画面が出たらUser Widgetを選びます。名前は WBP_PracticeHUD にします。
DesignerでCanvas Panelをルートに置き、その子にHorizontal Boxを追加します。さらにHorizontal Boxの子として、TextとProgress Barをこの順で並べます。
Canvas Panel
└─ Horizontal Box(HP表示のまとまり)
├─ Text(HPという文字)
└─ Progress Bar(HealthBar)
Horizontal Boxを選び、Slot (Canvas Panel Slot)を次の値へ設定します。Size To Contentはオフにします。
| 設定 | 値 |
|---|---|
| Anchors | 左上。Minimum / Maximumともに(0, 0) |
| Position X / Y | 24 / 24 |
| Size X / Y | 320 / 32 |
| Alignment X / Y | 0 / 0 |
これで、HP表示の左上を、画面左上の基準から右へ24、下へ24ずらして配置します。数値はUIの座標単位で、最終表示のピクセル数はDPIスケーリングによって変わります。
Textは表示内容を「HP」、フォントサイズを20にします。Horizontal Box SlotのSizeをAuto、Vertical AlignmentをCenter、PaddingのRightを12にします。Autoは文字に必要な幅を使う指定、Paddingは隣との余白です。
Progress Barは HealthBar へ名前を変え、Is Variableをオン にします。これでGraphからこの部品を指定できます。Horizontal Box SlotはSize=Fill、値=1、Horizontal / Vertical Alignment=Fillにします。文字と余白の残りを、バーが使う配置です。
HealthBarのPercentを 1.0、Bar Fill TypeをLeft to Right、Fill Color and Opacityを青系にします。PercentのBindは設定しません。Designerで「HP」と満タンのバーが左上に見えれば、見た目の準備はできています。

2. キャラクターから作って、画面へ載せる
BP_HUDPracticeのイベントグラフで、BeginPlayから Create Widget を呼びます。既存のBeginPlay処理がある場合は、その実行線の末尾へ続けます。
| Create Widgetの入力 | 指定 |
|---|---|
| Class | WBP_PracticeHUD |
| Owning Player | Get Player Controller(Player Index=0)のReturn Value |
Owning Player は、このUIを使うプレイヤーのPlayer Controllerです。ここでのSelfはキャラクターなので、Owning PlayerにはGet Player Controllerの結果を渡します。Player Index=0は、今回の単独プレイのプレイヤーを指定しています。
Create WidgetのReturn Valueを右クリックしてPromote to Variableを選び、HUDRef と名付けます。型はWBP_PracticeHUDのObject Referenceになります。
白い実行線を、Create Widget → Set HUDRef → Add to Viewportの順につなぎます。Add to ViewportのTargetには、保存したHUDRefをつなぎます。

コンパイル・保存してPlayします。左上に満タンのHPバーが表示され、WASDでも動ければ、この段階は完成です。表示を見るだけのHUDなので、Input Modeやマウスカーソルの設定は追加しません。
3. 画面比率を変えて確かめる
WBP_PracticeHUDのDesignerへ戻り、Screen Sizeで16:9と4:3などを切り替えます。HP表示が左上に残り、文字とバーが重ならないか確認してください。
バーの横幅まで画面に合わせて伸ばしたい場合は、左上への固定とは別に、Horizontal Boxの左右アンカーを広げる設計へ変えます。今回は、左上にまとまって残る固定幅のHP表示を使います。
実践2:HPが変わったらバーを更新する
ここまでは見た目だけのバーです。次は、キャラクターが「HPが変わった」と知らせ、HUDが受け取って長さを変えるようにします。
この通知に使うのが Event Dispatcher です。受け取りたい処理を Bind で登録し、通知する側が Call すると、登録した処理が呼ばれます。基本の接続方法はEvent Dispatcher入門でも扱っています。

1. 25ずつHPを減らして通知する
BP_HUDPracticeのMy BlueprintでEvent Dispatcherを追加し、OnPracticeHealthChanged と名付けます。InputsへFloatの Current と Maximum を追加します。この2つで「今はいくつで、満タンはいくつか」を渡します。
次に関数 ReducePracticeHealth を作ります。今回はテスト用に25ずつ減らすので、関数の入力は不要です。
- CurrentHealthから25をSubtractで引く。
- Clamp (Float)へつなぎ、Min=0、Max=MaxHealthにする。
- Clampの結果をSet CurrentHealthへ入れる。
- Set CurrentHealthの実行出力から、OnPracticeHealthChangedのCallを呼ぶ。
- CallのCurrentへ更新後のCurrentHealth、MaximumへMaxHealthを渡す。

Clamp は、値を指定した範囲内へ収める処理です。HPが10のときに25を引いても、0で止まります。通知は、HPを書き換えた後に呼びます。

Input Actionの IA_HUDDamage をDigital (Bool)、Modifiers / Triggersなしで作ります。テンプレートの移動に使われているInput Mapping Context(IMC_Defaultなど)へ追加し、Hキーを割り当 てます。既存の移動・視点操作は残してください。
BP_HUDPracticeのイベントグラフへIA_HUDDamageを置き、StartedからReducePracticeHealthを呼びます。入力アセットの操作に迷う場合は、Enhanced Input入門を参照してください。

まだHUDへの接続はできていないので、この時点ではバーは動きません。先にCallの後ろへPrint Stringを置き、CurrentHealthを表示します。Hキーの1回目で75、続いて50 → 25 → 0と出れば、HPを減らす処理はできています。確認したPrint Stringは外して構いません。
2. HUDに、割合を表示する関数を作る
WBP_PracticeHUDのGraphへ移り、関数 RefreshPracticeHealth を作ります。入力はFloatのCurrentとMaximum、出力はなしにします。
バーに渡す Percent は、0が空、1が満タンの割合です。HPが75、最大HPが100なら、75 ÷ 100 = 0.75 を渡します。75をそのまま渡す値ではありません。
Current ÷ MaximumをDivideで求め、その結果をClamp (Float)の0〜1へ通します。HealthBarをGetで置き、そこからSet Percentを作ります。TargetはHealthBar、In PercentはClampの結果です。関数入口の白い実行出力をSet Percentへつなぎます。

この割り算の結果を、バーへ渡します。

最大HPは準備で決めた正の100を使います。最大HPを変更できるゲームへ広げる場合も、0で割らないように、値を設定する側で正の値を保ちます。
3. 作ったHUDへ、表示する相手を渡す
WBP_PracticeHUDに関数 InitializePracticeHUD を作り、入力 Source の型を BP_HUDPracticeのObject Reference にします。Sourceは、このHUDがHPを表示するキャラクターの実体です。
ここまでをコンパイルし、Sourceから引き出して Bind Event to OnPracticeHealthChanged を作ります。TargetはSourceです。赤いEventピンからCreate Eventを作り、Object=self、Select FunctionでRefreshPracticeHealthを選びます。
ここでのCreate Eventは、Widgetを作るCreate Widgetとは別物です。「このHUDのRefreshPracticeHealthを、通知の受け取り先にする」 という指定を作っています。関数の入力型・数がDispatcherと一致していると、候補に出ます。

InitializePracticeHUDの白い出力をBind Eventへつなぎ、その後ろにRefreshPracticeHealthの呼び出しを置きます。この呼び出しのTargetはself、CurrentとMaximumにはSourceから読んだCurrentHealthとMaxHealthを渡します。

Sourceの青いピンから引き出し、Get CurrentHealthとGet MaxHealthをそれぞれ検索して置くと、そのキャラクターの値を読めます。緑の出力を、RefreshPracticeHealthのCurrentとMaximumへつなぎます。

Bindは、これからの通知を受け取るための登録です。登録前にあったHPの変化までは、後から教えてくれません。 そこで登録直後に現在値を読み、一度だけ表示を合わせます。これが初期値の反映です。
4. 表示する前に初期化を呼ぶ
BP_HUDPracticeへ戻ります。先ほどのSet HUDRefとAdd to Viewportの間へ、HUDRefをTargetにしたInitializePracticeHUDを挟みます。Sourceには Self を渡します。
最終的な順番は、Create Widget → HUDRefへ保存 → InitializePracticeHUD → Add to Viewportです。同じHUDを続けて使うので、Create WidgetやAdd to Viewportをもう一組作る必要はありません。

この順なら、HPを表示する相手を明示して、通知を登録し、現在値を反映してから画面へ載せられます。WBP_PracticeHUDのEvent Constructからプレイヤーを探す処理は追加しません。
5. 減る瞬間と、表示開始時の値を比べる
Playして画面をクリックし、Hキーを1回ずつ押します。1回で75%、2回で50%、3回で25%、4回で空になれば、HPの変化がバーまで届いています。押し続けてもStartedは押し始めに1回なので、次は離して押します。

図では割合を比べやすいように、バーを4つの区画で示しています。実際に作るHealthBarは連続した1本のバーで、キャラクターにはThird Personテンプレートのものを使います。
初期値の反映も試してみま しょう。DesignerのHealthBarのPercentだけを0.25にし、キャラクターのCurrentHealthは100のままPlayします。ゲームでは満タンになる はずです。Designerの見本の値を、ゲーム側の現在HPで更新したためです。
次に、InitializePracticeHUDの最後のRefreshPracticeHealth呼び出しだけを一時的に実行線から外します。Bindは残します。Play直後は25%のままですが、Hを押すとHP75の通知が届き、75%になります。「最初から正しく見せる処理」と「変わったときに更新する処理」が別だと分かります。確認後は実行線とDesignerのPercent=1.0を戻してください。

図のパーセントは、画面に見えるバーの満ち具合です。初期反映を外しても、キャラクター側のHPが25へ減ったわけではありません。
Bindingと、変更時に更新する方法
UMGには、Percentなどの値を関数や変数へ結び付ける Binding もあります。表示側が繰り返し値を読み取るため、短い試作では手早くつなげます。
一方、今回の方法は、HPを変更した処 理から通知を出し、HUDがSet Percentを呼びます。何も変わらない間に、HUDがHPを問い合わせ続ける必要がありません。HPやスコアのように「どこで値が変わるか」が分かる表示では、この形を基本にすると更新のきっかけも追いやすくなります。

同じPercentをBindingとSet Percentの両方で管理しないようにします。直接Setする操作はBindingを切るため、「Bindingが常にSetの結果を上書きする」と考えると挙動を取り違えます。既存のBindingから切り替えるときは、DesignerのPercentのBindメニューで割り当てを外し、更新方法をそろえてください。
Event Dispatcherが必須というわけではありません。親Widgetが自分の子バーを更新するだけなら、Set Percentを直接呼んでも十分です。通知を使う意味は、キャラクターがバーの配置や部品名を知らず、「HPが変わった」という情報を渡せることにあります。
動かないときの確認
一度に全部を追わず、表示する処理 → HPを減らす処理 → 通知 → バーの更新 の順に分けます。
| 症状 | 確認するところ |
|---|---|
| HP表示が出ない | Default Pawn Class、BeginPlayの実行線、Create WidgetのClass、Add to ViewportのTarget |
| バーだけ見えない | Horizontal Boxの幅・高さ、HealthBarのFill、Percent、色の透明度 |
| Hを押してもHPが減らない | 有効なIMCにHを登録したか、Startedから関数を呼んでいるか |
| HPは減るがバーが動かない | InitializePracticeHUDの呼び出し、Source=Self、BindのTargetとEvent |
| RefreshPracticeHealthが候補に出ない | 入力がFloatの2個で、出力がないか。コンパイル済みか |
| いつも満タンに見える | Set Percentへ75などを直接入れず、現在HP÷最大HPを渡しているか |
| 初めの表示だけ違う | Bind直後に現在値を渡す呼び出しがあるか |
通知まで届くか迷ったら、RefreshPracticeHealthの入口へPrint Stringを一時的に置きます。Hを押したときに呼ばれていれば、次に調べるのはHealthBarのTargetと割合です。
おまけ:HUDを片付ける・次のUIへ広げる
キャラクターと一緒に使い終わるHUD
今回のHUDは、キャラクター1体のために作りました。BP_HUDPracticeのEvent EndPlayから、白い実行ピンを持つ Is Valid へつなぎ、Input ObjectへHUDRefを入れます。有効な側から Remove from Parent を呼び、TargetもHUDRefにすると、そのキャラクターを使い終わるときに画面から外せます。

Remove from Parentは、表示階層から取り外す操作です。必ずその瞬間にWidget自体が破棄される、という意味ではありません。生きているキャラクターからHUDだけを外したり、同じHUDを再利用したりする構成では、通知のBindを外すタイミングも決めます。Bindと同じ相手・同じ受け取り先をUnbindで解除する手順は、Event Dispatcher入門を参照してください。
また、Event Constructは表示階層の作り直しで再び呼ばれる場合があります。今回の初期化は、作成した側から明示的に1回呼びます。表示のたびに何度も通知を登録する処理と混ぜないようにします。
復活後も残すHUDと、操作するメニュー
復活してもHUDを残したい場合は、Player ControllerなどでHUDを管理し、新しいキャラクターへ表示対象を切り替える構成を考えます。HUDを残すことと、新しいHPの持ち主へつなぎ直すことは別の作業 です。
ゲームの状態をどこへ置くかはGame Framework入門、頭上へ付けるHPバーはWidget Componentの記事へつながります。
ボタンを押せるポーズ画面へ進むなら、ポーズメニューの記事で、ゲームを止める処理とUIへ入力を渡す処理を組み合わせます。まずは今回のHUDで、表示とデータの更新を別々に確かめられるようにしておきましょう。
まとめ
Widget Blueprintで見た目を作り、Create Widgetで実体を作り、Add to Viewportで画面へ載せる。HPバーでは、この表示の流れへ「現在HPを割合に変えて渡す」処理を足します。
最初に現在値を反映し、その後はHPが変わった通知で更新する形ができれば、スコアや残弾数の表示にも応用できます。まずはHキーでバーが減るところを完成させ、次に体力とダメージの記事の攻撃処理へ置き換えてみてください。
参考:Create Widget、UMGのアンカー、Property Binding、イベントによるUI更新、UMGの最適化指針。
画面の文字を翻訳して切り替えるなら Localization Dashboard、別カメラの映像をUIへ映すなら Render Targetでミニマップを作る が入口です。