UIの部品が作れるようになったら、次はゲームの状況に合わせて表示を変えていきましょう。スコアの数字、HPのバー、押せる・押せないボタン。スクリプトからUIを書き換える方法をご紹介します!
目次
この記事で学べること
- スクリプトからUIの部品を操作する準備(using と参照)
- TextMeshProの文字を書き換える方法
- SliderでHPバーを作る方法
- Imageの色を変える方法
- ボタンを押せなくする・スクリプトから処理を登録する方法
前提知識
- よく使うUnity専用の関数とプロパティ:[SerializeField]での参照
- テキスト、ボタン、画像の基本UI要素
- TextMeshProで美しいテキストを表示しよう
UIをスクリプトから使う準備
usingを書く
UIの部品を使うスクリプトでは、ファイルの先頭に次のusingを書きます。
using UnityEngine;
using UnityEngine.UI; // Slider、Image、Button など
using TMPro; // TextMeshProの文字(TMP_Text)
これを書き忘れると「型が見つからない」というエラーになります。UIを使うスクリプトでは、まずこの3行を書くクセをつけましょう。
Inspectorで参照を設定する
6-9の記事で説明したとおり、ほかのオブジェクトは[SerializeField]で変数を作り、Inspectorでドラッグ&ドロップして設定するのが一番確実です。
[SerializeField] private TMP_Text scoreText;
[SerializeField] private Slider hpBar;
- 文字は
TMP_Text型にしておくと、UIのText (TMP)をドロップできます - 設定し忘れて「None」のままだと、NullReferenceExceptionになります
文字を書き換える
スコアを表示する
「ScoreDisplay」という名前でスクリプトを作ります。
using UnityEngine;
using TMPro;
public class ScoreDisplay : MonoBehaviour
{
[SerializeField] private TMP_Text scoreText;
private int score = 0;
void Start()
{
UpdateText();
}
// ほかのスクリプトやボタンから呼ぶ
public void AddScore(int points)
{
score += points;
UpdateText();
}
private void UpdateText()
{
scoreText.text = "スコア: " + score;
}
}
scoreText.text = 文字列;で、表示が書き換わります- 数字が変わったときだけ
UpdateText()を呼んで書き換えます。Updateで毎フレーム書き換えるのは無駄が多いので避けましょう
残り時間を表示する
using UnityEngine;
using TMPro;
public class TimerDisplay : MonoBehaviour
{
[SerializeField] private TMP_Text timerText;
[SerializeField] private float timeLimit = 60f;
private float timeRemaining;
void Start()
{
timeRemaining = timeLimit;
}
void Update()
{
if (timeRemaining <= 0f)
{
return;
}
timeRemaining -= Time.deltaTime;
if (timeRemaining < 0f)
{
timeRemaining = 0f;
Debug.Log("タイムアップ!");
}
int minutes = (int)(timeRemaining / 60f);
int seconds = (int)(timeRemaining % 60f);
timerText.text = minutes.ToString("00") + ":" + seconds.ToString("00");
}
}
ToString("00")で、「5」を「05」のように2けたで表示できます- 時間のように毎フレーム変わるものは、Updateで書き換えてOKです
SliderでHPバーを作る
Sliderの準備
- Canvasを右クリック>UI>Sliderで作り、名前をHPBarにする
- HPバーとして使うので、つまみ(Handle Slide Areaの子のHandle)は削除するか非表示にする
- SliderのInteractableのチェックを外す(プレイヤーが動かせないようにする)
- Min Value:一番左のときの値(ふつうは0)
- Max Value:一番右のときの値(最大HP)
- Value:今の値
HPバーのスクリプト
「HealthBarUI」という名前でスクリプトを作ります。
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class HealthBarUI : MonoBehaviour
{
[SerializeField] private Slider hpBar;
[SerializeField] private TMP_Text hpText;
[SerializeField] private int maxHp = 100;
private int hp;
void Start()
{
hp = maxHp;
// バーの最大値をHPの最大値に合わせる(これを忘れると、初期値の1が最大になってしまう)
hpBar.minValue = 0;
hpBar.maxValue = maxHp;
UpdateUI();
}
public void TakeDamage(int damage)
{
hp = Mathf.Max(hp - damage, 0); // 0より小さくしない
UpdateUI();
}
public void Heal(int amount)
{
hp = Mathf.Min(hp + amount, maxHp); // 最大HPより大きくしない
UpdateUI();
}
private void UpdateUI()
{
hpBar.value = hp;
hpText.text = hp + " / " + maxHp;
}
}
- maxValueを必ず設定する:Sliderの初期のMax Valueは1なので、HPが100でも「1以上はずっと満タン」に見えてしまいます
Mathf.Max(a, b)は大きい方、Mathf.Min(a, b)は小さい方を返します。HPが0〜最大の間に収まるようにしています- 試すときは、9-2のようにボタンのOn Click ()にTakeDamage(数値は10など)を登録してみましょう
スライムHPを減らしても、バーがずっと満タンのまま・・・



maxValueの設定忘れかも!Sliderの最大値は最初1になっているから、HPの最大値に合わせてあげてね
Imageの色を変える
using UnityEngine;
using UnityEngine.UI;
public class StatusIndicator : MonoBehaviour
{
[SerializeField] private Image statusImage;
public void SetDanger(bool isDanger)
{
statusImage.color = isDanger ? Color.red : Color.green;
}
public void SetAlpha(float alpha)
{
// 色はそのままで、透明度(a)だけ変える
Color color = statusImage.color;
color.a = alpha;
statusImage.color = color;
}
}
image.colorで色を変えられます- 透明度だけ変えたいときは、一度色を変数に入れて
aを書き換えてから戻します(statusImage.color.a = 0.5f;とは直接書けません)
ボタンを操作する
押せる・押せないを切り替える
using UnityEngine;
using UnityEngine.UI;
public class ShopButton : MonoBehaviour
{
[SerializeField] private Button buyButton;
[SerializeField] private int price = 100;
public void UpdateButton(int money)
{
// お金が足りるときだけ押せる
buyButton.interactable = money >= price;
}
}
interactableをfalseにすると、ボタンがグレーになって押せなくなります。
スクリプトから押したときの処理を登録する
9-2ではInspectorのOn Click ()で登録しましたが、スクリプトからも登録できます。
using UnityEngine;
using UnityEngine.UI;
public class ButtonSetup : MonoBehaviour
{
[SerializeField] private Button startButton;
void Start()
{
// 押されたらOnStartを呼ぶ
startButton.onClick.AddListener(OnStart);
}
void OnDestroy()
{
// 片付け:登録した処理を外す
startButton.onClick.RemoveListener(OnStart);
}
private void OnStart()
{
Debug.Log("スタート!");
}
}
onClick.AddListener(メソッド名)で、押されたときに呼ぶメソッドを登録します(カッコは付けずに名前だけ書きます)- スクリプトから登録する場合は、メソッドはprivateでもOKです
実践:スコアとレベルの表示
ボタンを押すとスコアが増えて、100点ごとにレベルが上がり、次のレベルまでのバーが伸びる仕組みを作ってみましょう。
UIの準備
- ScoreText(Text – TextMeshPro):スコアの表示
- LevelText(Text – TextMeshPro):レベルの表示
- ExpBar(Slider):次のレベルまでのバー。Interactableのチェックを外し、つまみを非表示に
- AddScoreButton(Button – TextMeshPro):テスト用のボタン。文字は「スコア +10」
スクリプト
「ScoreSystem」という名前でスクリプトを作り、空のゲームオブジェクト(名前はGameUI)にアタッチします。
using UnityEngine;
using UnityEngine.UI;
using TMPro;
public class ScoreSystem : MonoBehaviour
{
[SerializeField] private TMP_Text scoreText;
[SerializeField] private TMP_Text levelText;
[SerializeField] private Slider expBar;
[SerializeField] private Button addScoreButton;
[SerializeField] private int pointsPerLevel = 100; // 何点ごとにレベルが上がるか
[SerializeField] private int pointsPerClick = 10;
private int score = 0;
void Start()
{
expBar.minValue = 0;
expBar.maxValue = pointsPerLevel;
addScoreButton.onClick.AddListener(OnAddScoreClicked);
UpdateUI();
}
void OnDestroy()
{
addScoreButton.onClick.RemoveListener(OnAddScoreClicked);
}
private void OnAddScoreClicked()
{
int oldLevel = GetLevel();
score += pointsPerClick;
if (GetLevel() > oldLevel)
{
Debug.Log("レベルアップ! Level " + GetLevel());
}
UpdateUI();
}
// スコアからレベルを計算する(0〜99点でレベル1、100〜199点でレベル2…)
private int GetLevel()
{
return score / pointsPerLevel + 1;
}
private void UpdateUI()
{
scoreText.text = "スコア: " + score;
levelText.text = "レベル: " + GetLevel();
// 今のレベルの中で、何点たまっているか(0〜99)
expBar.value = score % pointsPerLevel;
}
}
このスクリプトのポイント:
- レベルはスコアから計算する:
score / pointsPerLevel + 1。int同士の割り算は小数点以下が切り捨てられるので、150 / 100 は1になります - バーは「今のレベルの中での点数」:
score % pointsPerLevel(%は割った余り)。150点なら50で、バーが半分まで伸びます - レベルを別の変数で持たずに毎回計算しているので、数字がずれる心配がありません
InspectorでScoreSystemの各欄にUIをドラッグ&ドロップして再生し、ボタンを押してみましょう。
よくあるエラーと対処法
エラー:The type or namespace name ‘TMP_Text’ / ‘Slider’ could not be found
- 原因:
using TMPro;やusing UnityEngine.UI;を書き忘れている - 対処法:ファイルの先頭にusingを追加する
エラー:NullReferenceException
- 原因:Inspectorで参照を設定し忘れている(「None」のまま)
- 対処法:Inspectorで、UIの部品をドラッグ&ドロップで設定する
エラー:Sliderのバーが動かない・ずっと満タン
- 原因:maxValueがHPなどの最大値に合っていない(初期値は1)
- 対処法:Startで
maxValueを設定する。Inspectorで設定してもOK
エラー:文字の欄にText (TMP)をドロップできない
- 原因:変数の型が古い
Text型になっている - 対処法:
using TMPro;を書き、変数をTMP_Text型にする
エラー:ボタンを押しても反応しない
- 原因:EventSystemがない、またはAddListenerが呼ばれていない
- 対処法:EventSystemを確認する。Startでの登録がエラーで止まっていないか、Consoleを確認する
まとめ
- UIを使うスクリプトには
using UnityEngine.UI;とusing TMPro; - 参照は
[SerializeField]でInspectorから設定 - 文字:
text、Slider:maxValueとvalue、Image:color、Button:interactableとonClick.AddListener - 表示は、値が変わったときだけ書き換える
次のステップ
次は、プレイヤーが文字を入力したり、スライダーで音量を変えたりする「入力系」のUIを学びましょう:
コメント