
RPGのバトルで一番よく見る場所といえば、仲間のHPとMPが並んだウインドですよね。「あと何回攻撃を受けても大丈夫か」「まほうを使えるMPは残っているか」が、ひと目で分からないと戦えません。今回は右下のウインドに、仲間3人の名前・レベル・HP・MPを、ゲージと数字の両方で見せるステータスのウインドを作ってみたいと思います!
- シリーズの目次:ターン制RPGの作り方
- 前回:#2 キャラクターと敵のデータをScriptableObjectで作ろう
今回作るもの
- HPやMPを、ゲージと「38/38」のような数字で見せる
Gauge - 1人分の名前・Lv・HP・MPを並べた行
StatusRow(プレハブ) - データから3人分の行を作る
StatusWindow
| スクリプト | 役割 | 付ける場所 |
|---|---|---|
| Gauge | ゲージの長さと数字を変える | HpGauge・MpGauge |
| StatusRow | 1人分の行の表示 | StatusRowのプレハブ |
| StatusWindow | データから行を作る | StatusWindow |
| BattleLineup | 並べるついでに、ステータスの行も作る(#2のものを書き換え) | Battle |
使うスタートガイドの記事は次の2つです。
1人分の行を作ろう
まずは、1人分の行の見た目を組み立てます。完成すると、次のような1行になります。

StatusWindowの子に、空のGameObject「StatusRow」を作ります。中身は、横に4つ並べます。
- StatusRowにAdd Component>Horizontal Layout Group
- Spacing:24、Child Alignment:Middle Left
- Control Child Size:Width・Heightにチェック、Child Force Expand:Heightだけチェック
- StatusRowの子に、次の4つを作る
| 名前 | 作り方 | 中身 | 幅(Layout Element の Preferred Width) |
|---|---|---|---|
| NameText | Text – TextMeshPro | 「スライム」、Font Size 34、太字 | 260 |
| LevelText | Text – TextMeshPro | 「Lv1」、Font Size 30 | 120 |
| HpGauge | Image(下で作る) | HPのゲージ | 520 |
| MpGauge | Image(下で作る) | MPのゲージ | 360 |
- 4つともAdd Component>Layout Elementを付けて、Preferred Widthに表の幅を入れる
- Horizontal Layout Groupは、子のLayout Elementを見てそれぞれの幅を決めてくれるので、数字だけで並びを調整できます
Gaugeを作ろう
HPのゲージは、4つの部品でできています。
- HpGauge(UI (Canvas)>Image)
- Source Image:ui_white、Color:#1A1A2E(ゲージの背景の暗い色)
- HpGaugeの子にBack(UI (Canvas)>Image)
- アンカー:stretch-stretch、Left・Top・Right・Bottom:4(背景のふちを少し見せる)
- Source Image:ui_white、Color:#4A4A66(灰色がかった紺。ゲージの最大の長さを見せる帯)
- Raycast Targetのチェックを外す
- HpGaugeの子にFill(UI (Canvas)>Image)。Backの下(Backより手前に描かれる)に置く
- アンカー:stretch-stretch、Left・Top・Right・Bottom:4(Backとぴったり同じ大きさ)
- Source Image:ui_white、Image Type:Filled、Fill Method:Horizontal、Fill Origin:Left
- Color:#3FAE5A(緑)
- HpGaugeの子にLabel(Text – TextMeshPro)
- アンカー:stretch-stretch、Left:16、Top・Right・Bottom:0
- 「HP」、Font Size:24、太字、Alignment:左寄せ・上下中央
- HpGaugeの子にValue(Text – TextMeshPro)
- アンカー:stretch-stretch、Left:0、Top・Bottom:0、Right:16
- 「38/38」、Font Size:28、太字、Alignment:右寄せ・上下中央

ゲージの絵には、角の丸い画像ではなく白い四角(ui_white)を使います。Filledは画像を切り分けずにそのまま縮めるので、角の丸い画像だとゲージの両端が丸くつぶれて、見苦しくなります。色はImageのColorで付けるので、白い四角が1枚あれば、HPにもMPにも使えます。
Backは、Fillと同じ大きさの帯です。HPが減ってFillが縮むと、その後ろのBackが見えて、「全体のうち、どれだけ残っているか」がひと目で分かります。Backが無いと、減ったところが背景と同じ色になって、ゲージの最大の長さが分かりにくくなります。
ゲージの中の数字は、28の太字ぐらいの大きさにしておくと、ゲームの画面を少し離れて見ても読めます。小さい文字はウインドの中で埋もれがちなので、思い切って大きめにしましょう。
HpGaugeが出来たら、Ctrl+Dで複製して「MpGauge」にし、FillのColorを#3C7BD9(青)、Labelを「MP」に変えます。
Gaugeのスクリプト
- TurnBasedRpg/Scriptsに「Gauge」スクリプトを作る
using TMPro;
using UnityEngine;
using UnityEngine.UI;
// ゲージの長さと「38/38」の数字を、今の値と最大値から決める
public class Gauge : MonoBehaviour
{
[SerializeField] private Image fill; // Image Type:Filled
[SerializeField] private TMP_Text valueText; // 「38/38」
private int current;
private int max;
public void SetValue(int newCurrent, int newMax)
{
current = newCurrent;
max = newMax;
fill.fillAmount = max > 0 ? (float)current / max : 0f;
valueText.text = $"{current}/{max}";
}
// 確認用:Inspector の右上の︙から、ゲージを半分にしてみる
[ContextMenu("半分にしてみる")]
private void TestHalf()
{
SetValue(current / 2, max);
}
}
- fill.fillAmount
- Filledの「どこまで塗るか」(0〜1)。HPが38のうち19なら0.5で、ゲージが半分になる
- (float)current / max
- intどうしの割り算は、小数が切り捨てられて0か1にしかならない。片方をfloatにしてから割るのがポイント
- max > 0 ? … : 0f
- MPが0のキャラクター(敵など)で、0で割らないようにしている
- [ContextMenu(“…”)]
- Inspectorのコンポーネントの︙(右上のメニュー)に、そのメソッドを呼ぶ項目を足す。再生中に、ゲージの動きを手で確かめられる
HpGauge・MpGaugeにGaugeを付けて、FillとValueをそれぞれドラッグします。
スライム︙のメニューから呼べるの、便利ですね・・・。確かめるためだけのボタンを作らなくて済みます
StatusRowとStatusWindow
StatusRow
- 「StatusRow」スクリプトを作る
using TMPro;
using UnityEngine;
// ステータスのウインドの1人分の行
public class StatusRow : MonoBehaviour
{
[SerializeField] private TMP_Text nameText;
[SerializeField] private TMP_Text levelText;
[SerializeField] private Gauge hpGauge;
[SerializeField] private Gauge mpGauge;
public void SetName(string characterName)
{
nameText.text = characterName;
}
public void SetLevel(int level)
{
levelText.text = $"Lv{level}";
}
public void SetHp(int hp, int maxHp)
{
hpGauge.SetValue(hp, maxHp);
}
public void SetMp(int mp, int maxMp)
{
mpGauge.SetValue(mp, maxMp);
}
}
行の中の部品をStatusRowの中に隠しておいて、外からはSetHpのようなメソッドだけで変えられるようにしています。ほかのスクリプトは、行の中がどう組まれているかを知らなくていいので、あとでゲージの形を変えても、呼ぶ側は直さずに済みます。
- StatusRowにStatusRowスクリプトを付けて、NameText・LevelText・HpGauge・MpGaugeをドラッグ
- StatusRowをTurnBasedRpg/Prefabsにドラッグしてプレハブにし、シーンのStatusRowは消す
シーンのStatusRowを残したままにすると、再生したときに、作られた3行の上にもう1行(中身が「スライム」のままの行)が並んでしまいます。プレハブにしたら、シーンの方は消しておきましょう。


StatusWindow
3人分の行は、StatusWindowの中に縦に並べます。
- StatusWindowにAdd Component>Vertical Layout Group
- Padding:Left・Right・Top・Bottom 24、Spacing:8
- Control Child Size:Width・Heightにチェック、Child Force Expand:Width・Heightにチェック
- 「StatusWindow」スクリプトを作る
using UnityEngine;
// 右下のステータスのウインド。データから1人分ずつ行を作る
public class StatusWindow : MonoBehaviour
{
[SerializeField] private StatusRow rowPrefab;
// 仲間1人分の行を足して、Lv1・HPとMPが満タンの状態で表示する
public StatusRow AddRow(CharacterData data)
{
StatusRow row = Instantiate(rowPrefab, transform);
row.SetName(data.CharacterName);
row.SetLevel(1);
row.SetHp(data.BaseStats.maxHp, data.BaseStats.maxHp);
row.SetMp(data.BaseStats.maxMp, data.BaseStats.maxMp);
return row;
}
}
- Instantiate(rowPrefab, transform)
- StatusWindow(自分)の子として行を作る。Vertical Layout Groupが付いているので、作るたびに自動で下に並んでいく
- return row
- 作った行を返しておくと、呼んだ側があとからHPを変えられる。#7でダメージを受けたときに使います
StatusWindowにStatusWindowスクリプトを付けて、Row PrefabにPrefabsのStatusRowをドラッグします。


BattleLineupから行を作る
最後に、#2のBattleLineupで仲間を並べるときに、ステータスの行も一緒に作るようにします。
using UnityEngine;
// データから仲間と敵を並べる(バトルの流れは #9 で BattleManager に移す)
public class BattleLineup : MonoBehaviour
{
[SerializeField] private CharacterData[] party; // バトルに出る3人
[SerializeField] private UnitView[] partyViews; // PartyArea の3人
[SerializeField] private EnemyData[] enemies; // 出てくる敵(1〜4体)
[SerializeField] private UnitView enemyPrefab;
[SerializeField] private RectTransform enemyArea;
[SerializeField] private float enemySpacing = 300f; // 敵の横の間隔
[SerializeField] private StatusWindow statusWindow;
private void Start()
{
for (int i = 0; i < partyViews.Length; i++)
{
CharacterData character = party[i];
partyViews[i].SetupCharacter(character);
statusWindow.AddRow(character);
}
for (int i = 0; i < enemies.Length; i++)
{
UnitView view = Instantiate(enemyPrefab, enemyArea);
// 真ん中をそろえて横に並べ、1体おきに上下へずらす
float x = (i - (enemies.Length - 1) / 2f) * enemySpacing;
float y = (i % 2 == 0) ? 60f : -60f;
((RectTransform)view.transform).anchoredPosition = new Vector2(x, y);
view.SetupEnemy(enemies[i]);
}
}
}
- 変わったのは、
statusWindowの欄と、仲間を並べるループの中だけ。データから見た目を作る流れに、行を作るのを1つ足しただけです - 同じ
party[i]を2回使うので、CharacterData character = party[i];で変数に入れてから使います。何度もparty[i]と書くより読みやすく、番号の書きまちがいも防げます - BattleのBattle LineupのStatus Windowに、StatusWindowをドラッグ
仲間の数は、ロビーで入れ替えても3人のまま変わりませんが、データから行を作る形にしておくと、どの3人が出てきても同じスクリプトで表示できます。#20の入れ替えでも、このまま使えます。
動かして確認!
再生すると、右下に3人分の行が並びます。


ゲージが動くかも確かめてみましょう。
- 再生中に、Hierarchyで1行目のStatusRow(Clone)>HpGaugeを選ぶ
- InspectorのGaugeの右上の︙>半分にしてみるを何回か押す


#3の動作確認
- 右下のウインドに、3人の名前・Lv・HP・MPが1行ずつ並んでいる
- HPのゲージは緑、MPのゲージは青で、中の数字が読みやすい大きさ
- 「半分にしてみる」で、ゲージが左から縮み、数字も変わる
- BattleのPartyを入れ替えると、ウインドの名前と数字も変わる



ゲージの端が、ちゃんと四角いままですね!



白い四角のおかげだね。#10では、ダメージを受けたときに減った分が少し遅れて縮む演出も足すから、楽しみにしててね
あとがき
今回は、仲間のHPとMPを表示するステータスのウインドを作りました。まだ数字は満タンのままですが、ゲージが並ぶと一気にRPGらしくなりますね。次回は、左下のウインドに「たたかう・まほう・どうぐ・ぼうぎょ・にげる」のコマンドを並べて、キーボードやゲームパッドでも選べるようにしたいと思います!
コメント
コメント一覧 (1件)
[…] 前回:#3 仲間のHPとMPを表示するステータスのウインドを作ろう […]