Skip to content

第09回 UIエフェクト2

前回: 第08回 UIエフェクト1 / 次回: 第10回 シェーダー連携1

注意

この授業には提出課題があります

提出方法は 授業内で説明します

前回の振り返り

UI上の数字表示を作りました

  • 第08回では、ダメージ数字、回復数字、コンボ数字などの UI エフェクトを扱いました
  • Canvas の表示モード、World Space 表示、ビルボード、 AnimationCurve や DOTween による簡易アニメーションを確認しました
  • UI は単なる表示ではなく、ゲームの状態を伝える演出として機能します
  • 今回は、状態量の変化を可視化するゲージ系 UI を扱います

今回の授業の目的

状態量を視覚的に伝える

画像

  • HP
  • スタミナ
  • クールタイム
  • 必殺技ゲージ
  • 敵の体力表示
  • 典型的なゲージ表示の方法を学びます

今回の授業内容

ゲージ表示の実装方法

  • Image.fillAmount による横ゲージの実装
  • UI の Mask による横ゲージの応用
  • Image TypeFilled による円形ゲージ
  • World Space Canvas による頭上 HP ゲージ
  • 3D 座標を RectTransform 座標へ変換する表示方法
  • 授業内課題

ゲージの役割

変化量を直感的に伝える

  • ゲージは、現在値 / 最大値 の割合を視覚化する UI です
  • HP やスタミナのように、プレイヤーが頻繁に確認する情報の視覚化に使われます
  • 数字だけでは読み取りに時間がかかる場面でも、 ゲージなら一瞬で大まかな状態を把握できます
  • 直感性と演出の両立が重要で、見た目の調整も大切な要素になります

ゲージの基本式

0 から 1 の割合に変換

csharp
// 比率の計算例
var rate = currentValue / maxValue;
rate = Mathf.Clamp01(rate);
  • こででの currentValue は現在の HP やスタミナ、 maxValue は最大 HP や最大スタミナです
  • UI 側では、この rate を使って幅、マスク、fillAmount などを更新します
  • ゲージの実装はまず割合を求め、UI の幅、色などに反映させるのが基本です

Image Type: Filled

画像の表示割合を変更する

画像
画像割合変更の例

  • uGUI の Image は、 Image TypeFilled に設定すると fillAmount で表示割合を制御できます
  • 横ゲージを作る場合は、Fill MethodHorizontal にします
  • fillAmount0 で空、1 で満タンです
  • シンプルな構成ですが、これだけで十分な 場合もあるかもしれません

横ゲージの基本設定

Inspector で確認する項目

画像
Image コンポーネントの設定例

項目設定例
Image TypeFilled
Fill MethodHorizontal
Fill OriginLeft か Right
Fill Amount0 から 1
  • 左から右へ増えるゲージなら Fill OriginLeft に 右から左へ増えるゲージなら Fill OriginRight に設定しましょう

fillAmount を操作するコードの例

Image の表示割合を更新する

  • fillImage には Image Type: Filled の Image を指定します
  • SetValue に現在値と最大値を渡すだけで ゲージの表示割合を更新できます
  • 最も簡単な横ゲージの実装方法です 何かと便利ですので覚えておきましょう
csharp
using UnityEngine;
using UnityEngine.UI;

public class FillAmountGauge : MonoBehaviour
{
  [SerializeField] private Image fillImage;

  public void SetValue(float current, float max)
  {
    if (max <= 0f)
      return;

    var rate = Mathf.Clamp01(current / max);
    fillImage.fillAmount = rate;
  }
}

UI Mask の利用

親の画像で子の表示をくりぬく

画像
画像
画像
最上段のImageにMaskを付与した例

  • Mask は、UI の子要素を親の形の内側だけに 表示するためのコンポーネントです
  • マスクを指定すれば、単に矩形だけではなく より自由な形状のゲージを作れます
  • ※ 今回の目的とはあまり噛み合いませんが 単に範囲制限をするだけなら画像無しで使えて 軽量な Rect Mask 2D も便利です

Mask ゲージの実装例

親をマスク、子をバーにする

画像
マスク兼BG
画像
FillImageに画像を設定
画像
フレームを重ねて完成

text
HP Gauge
├─ FillMask
│  └─ FillImage
└─ FrameImage
  • FillMaskMask コンポーネントを追加します
  • FillImage は塗りつぶし用です Mask の子にして、マスクの形で表示します
  • FrameImage はマスクの外側に置いて 枠や背景を表現します

マスク方式の使いどころ

矩形以外の形状でゲージを作りたいはず

  • マスクを使えば、円形や波形など、様々な形のゲージを作ることができます
  • いまのゲームで、単なる矩形でゲージが表示されることはあまりありません マスクの利用は、ゲージ表示の定番テクニックの一つです
  • 一方で階層が増え、Mask による描画負荷の増加もあるため、 大量に表示する場合は実装方法を検討する必要があります

円形ゲージの作り方

Image の塗りつぶし機能を利用する

画像
画像
Image Type:Filled と Fill Method: Radial 360 の設定例

  • Image コンポーネントの Image TypeFilled に設定すれば 画像の表示割合を fillAmount で制御できる ようになります
  • Fill MethodRadial 360 に設定するだけで 円形のゲージを作ることができます
  • Fill OriginClockwise で開始位置と 回転方向を変更できます

円形ゲージの設定

Inspector で確認する項目

画像
Photoshop での作成例 図形で円を作成し、線の太さでリング化している

項目設定例
Image TypeFilled
Fill MethodRadial 360
Fill Origin基点を上下左右のいずれかに設定
Clockwise時計回り / 反時計回り
Fill Amount0 から 1
  • 扇形のゲージには円形のスプライトを使います 中央を透明に抜けばリング状のゲージを作れます

円形ゲージの用途

横ゲージとの使い分け

  • クールタイムやチャージ量のように、オンタイムでの増減を表現するのには 円形ゲージが向いています
  • 円形ゲージは面積が大きく目立ちます 重要度の低い情報に使いすぎると画面がうるさくなるので注意が必要です
  • HP のように残量を常に表示したい情報には横ゲージの方が向いています 用途ごとに使い分けましょう

頭上表示の目的

移動するキャラクターの状態表示

画像
HP ゲージを頭上に表示した例

  • World Space Canvas は 3D 空間上の オブジェクトとして配置できる Canvas です
  • 3D キャラクターの子にするだけで UI を一緒に 表示することができます
  • キャラクターの頭上に HP ゲージなどを 表示する場合などに便利ですが、 距離によって画面上のサイズが変わるため 常に最適な選択肢とは限りません

World Space Canvas の作り方

キャラクターの子に配置する

画像
World Space Canvas の設定例 Face Camera はビルボード制御用のスクリプト(後述)

  1. キャラクターの子に Canvas を作成する
  2. Render ModeWorld Space にする
  3. Canvas のサイズを小さく調整する
  4. 頭上に来るように localPosition を設定する
  5. HP ゲージ用の Image や Text を配置する
  6. カメラを向くようにビルボード制御を入れる

World Space Canvas のサイズ

そのままでは巨大に表示される

  • World Space Canvas は、UI の 1 ピクセルがワールド上の1ユニットに対応します 通常の UI の感覚で使用すると、非常に大きなサイズになってしまいます
  • Canvas の WidthHeight を 3D 空間上のサイズに合わせるのがおすすめですが、 2D のサイズを流用したまま Scale で縮小しても問題ありません
  • 3D キャラクターの子として運用する場合は、親のスケールに影響されることになります サイズ調整には注意が必要です

World Space Canvas をカメラ正面に向ける

LateUpdate でビルボード化

  • 第08回で扱ったビルボード処理で、 UI 表示をカメラ方向に向けられます
  • LateUpdate で 回転をカメラと揃えるだけの シンプルな処理ですが、これで UI を常に 正面に向けることができます
csharp
using UnityEngine;

public class FaceCamera : MonoBehaviour
{
  [SerializeField] private Camera targetCamera;

  private void LateUpdate()
  {
    if (targetCamera == null)
      targetCamera = Camera.main;

    if (targetCamera == null)
      return;

    transform.rotation = targetCamera.transform.rotation;
  }
}

World Space Canvas の注意点

距離で見た目の大きさが変わる

  • 遠くのキャラクターほどゲージは小さく見えます
  • 近いキャラクターほどゲージは大きく見えます
  • 遠距離の敵まで常に同じ大きさで表示したい場合は、 World Space Canvas ではなく、画面上の Canvas に表示する方法もあります
  • ゲーム内の距離感を加味したいなら World Space Canvas で問題ありませんが 読みやすい固定サイズにしたいなら画面座標変換が必要です

3D 座標を UI 座標に変換する

あくまで 2D で UI を表示するには

  • World Space Canvas は、3D 空間上のオブジェクトとして配置されるため、 距離によって見た目の大きさが変わってしまいます
  • 表示サイズを一定に保ちたい場合は、2D の Canvas に表示する方法が適しています
  • 3D 空間の座標を画面上の Canvas 座標に変換するユーティリティ関数で 2D 表示に必要な座標変換を行います
  • 若干複雑ですが、ゲーム内の二次元情報表示には必須のテクニックです

3D座標 → スクリーン座標 → Canvas座標

変換手順

  1. キャラクターの頭上のワールド座標を取得
  2. カメラ経由でワールド座標を画面に映った際の座標(スクリーン座標)に変換
  3. 得られたスクリーン座標を Canvas 内の RectTransform 座標に変換
  4. 変換後の座標に UI 部品を配置
  • UI は画面上の Canvas にあるため、距離が変わってもサイズは変わりません

座標変換に使うメソッド

2段階で変換する

処理メソッド
3D座標から画面座標Camera.WorldToScreenPoint
画面座標からUI座標RectTransformUtility.ScreenPointToLocalPointInRectangle
  • WorldToScreenPoint の戻り値の z が 0 以下なら 対象はカメラの後ろに回っていることになります 画面外やカメラ後方にいる対象の UI は非表示にして処理を終えます
  • ScreenPointToLocalPointInRectangle は、 Canvas の RectTransform を基準にしたローカル座標を返します

3D 座標に 2D の UI を追従させる実装例

csharp

using UnityEngine;

public class WorldToCanvasFollower : MonoBehaviour
{
  [SerializeField] private Transform target;
  [SerializeField] private Vector3 worldOffset;
  [SerializeField] private Camera worldCamera;
  [SerializeField] private Camera uiCamera;
  [SerializeField] private RectTransform canvasRect;
  [SerializeField] private RectTransform uiRect;

  private void LateUpdate()
  {
    if (target == null)
      return;

    if (worldCamera == null)
      worldCamera = Camera.main;

    if (worldCamera == null)
      return;
csharp

    var worldPosition = target.position + worldOffset;
    var screenPoint =
      worldCamera.WorldToScreenPoint(worldPosition);

    var visible = screenPoint.z > 0f;
    uiRect.gameObject.SetActive(visible);

    if (!visible)
      return;

    RectTransformUtility.ScreenPointToLocalPointInRectangle(
      canvasRect,
      screenPoint,
      uiCamera,
      out Vector2 localPoint);

    uiRect.anchoredPosition = localPoint;
  }
}

座標変換方式の注意点

奥行きとの関係は自分で処理する

  • 3D 空間の座標を2Dに変換しただけでは ゲーム内の距離感や見え方を阻害したり、矛盾した表現になる場合があります
  • ゲーム内容によっては、表示の有無や表示サイズの調整も必要です
  • 特に敵の HP 表示などはゲーム体験に直結します ただ実装しただけで終わらせず、ゲームの質を高めるための調整を行いましょう

3D → 2D 変換の基本的な対応

距離や奥行きに応じて表示を調整する

  • カメラの後ろにいる対象を非表示にする
  • 画面外の対象を非表示にする、または画面端に固定する
  • 手前の壁に隠れている対象を表示するかどうか決める
  • 対象が多い場合は、表示距離や重要度で間引く

即時ゲージと遅延ゲージ

ダメージの量を見せる

  • HP が減った瞬間、前景ゲージはすぐに減らします
  • 背後に置いた別色のゲージを少し遅れて減らすと、 どれだけダメージを受けたか分かりやすくなります
  • 回復の場合は、増える方向の遅延表現にすることもできます
  • ゲージの変化が速すぎると読めないため、 UI では少しだけ余韻を入れると見やすくなります

ゲージのアニメーション例

DOTween でのアニメーション

  • コードはダメージを受けたときに前景ゲージが 即時に減り、遅れて背後のゲージも減る例です
  • UI アニメーションには細かな時間管理が 必要で、直接コーディングするのは大変です
  • DOTween などのライブラリで大幅に省力化 できますので、積極的に活用しましょう
csharp
// ダメージを受ける
public void TakeDamage(float damage)
{
    _hp = Mathf.Clamp(_hp - damage, 0f, 1f);

    var sequence = DOTween.Sequence();
    sequence.
        Append(front.DOFillAmount(_hp, 0.2f)).
        Join(_rectTransform.DOShakePosition(0.5f, 10f, 20)).
        SetDelay(0.1f).
        Append(back.DOFillAmount(_hp, 0.5f));
}

// 回復する
public void Heal(float heal)
{
    _hp = Mathf.Clamp(_hp + heal, 0f, 1f);

    var sequence = DOTween.Sequence();
    sequence.Append(front.DOFillAmount(_hp, 0.5f));
    sequence.Join(back.DOFillAmount(_hp, 0.5f));
}

実習

各種ゲージを 実装してみよう

ひとつ作ると つぶしがきくよ

実習1:横ゲージを作る

fillAmount で残量を表示する

  1. Canvas に HP ゲージ用の UI を作成する
  2. 背景、FillImage、枠を配置する
  3. FillImageImage TypeFilled にする
  4. Fill MethodHorizontal にする
  5. スクリプトから fillAmount を変更して HP の残量を表示する

実習1-2:Mask ゲージを試す

画像を潰さずに残量を表示する

  1. FillImage を子に持つ FillMask を作成する
  2. FillMaskRect Mask 2D を追加する
  3. FillMask の Pivot と Anchor を左寄せにする
  4. スクリプトから FillMask の幅を変更する
  5. fillAmount 方式との見た目の違いを確認する

実習2:円形ゲージを作る

Image Type を Filled にする

  1. 円形の Image を配置する
  2. Image TypeFilled にする
  3. Fill MethodRadial 360 にする
  4. fillAmount を変更して残量が変わることを確認する
  5. クールタイムやチャージ量として使える見た目に調整する

実習3:頭上 HP ゲージを作る

World Space Canvas を使う

  1. キャラクターの子に Canvas を作成する
  2. Render ModeWorld Space にする
  3. Transform の Scale を小さくする
  4. 頭上に来るように位置を調整する
  5. ビルボード処理でカメラの方を向かせる

実習4:固定サイズの頭上 UI を作る

3D座標をUI座標へ変換する

  1. 画面上の Canvas に HP ゲージ Prefab を配置する
  2. キャラクターの頭上位置を取得する
  3. WorldToScreenPoint でスクリーン座標に変換する
  4. ScreenPointToLocalPointInRectangle で Canvas 座標に変換する
  5. anchoredPosition に反映して追従させる

授業内課題

ゲージ UI を一つ作成して 提出してください

HP、スタミナ、 クールタイムなど

課題の条件

以下を満たしてください

  • 現在値 / 最大値 を割合に変換して表示している
  • 横ゲージ、円形ゲージ、頭上ゲージのいずれかを実装している
  • 値を変更すると見た目が変化する
  • 背景や枠などでゲージの範囲が分かる
  • 色や形で用途が伝わるように調整している
  • スクリーンショットまたは動画で提出する

余裕があれば挑戦

以下のような調整もしてみましょう

  • ダメージ時の遅延ゲージを入れる
  • 値の変化をなめらかに補間する
  • 危険域で色を変える
  • キャラクターの頭上に追従させる
  • 3D 座標変換でサイズ固定の UI として表示する

提出時の説明

調整の意図を添えてください

  • 何を表すゲージか
  • どの方式で実装したか
  • 値の変化をどのように見せたか
  • 色や形をどう決めたか
  • 読みやすくするために調整した点
  • 改善したい点

今回のまとめ

ゲージは状態量を見せる UI エフェクト

  • Image.fillAmount を使うと、横ゲージをシンプルに実装できます
  • Mask を使うと、画像を潰さずに横ゲージを表現できます
  • Image Type: FilledRadial 360 で円形ゲージを作れます
  • World Space Canvas は、キャラクターに紐づく UI 表示に向いています
  • 3D 座標を Canvas 座標へ変換すると、サイズ固定の頭上 UI を表示できます
  • ゲージは派手さより、変化の読みやすさを優先して設計しましょう

おつかれさまでした!

次回予告 第10回 シェーダー連携1

UVスクロールとマスクで 多様な表現