Unityで敵体力HPゲージを実装したメモ。普段は非表示で攻撃したら表示し透明な最大HPも

Unity 敵 体力 HP ゲージ 最大HP 表示 3Dゲームの作り方
※記事内に広告が含まれています。

バーチャル3Dクリエイター神部まゆみです(*^_^*)

この記事はUnityで敵体力HPゲージを実装したので、それについての記事です。

動作確認した最新バージョンは Unity 6000.3.1 です。

●PRスペース●
■PR■

現在、約2000個の人気Unityアセットが50%オフで買える Unityニューイヤーセールをやってるみたいです。

Unityニューイヤーセール 50%オフ

Very Animation Umotion Pro なども50%オフなので、欲しいアセットはこの機会に買っておくと良いかも。

veryanimation  umotion pro   

〇まゆみマート|BOOTH

BOOTHでVRoidテクスチャやVRChat向けオブジェクトなどを販売しています。いいねしてくれると励みになります(*^-^*)

やりたいこと:攻撃したら敵体力ゲージを表示させたい

前回↓こんな感じで攻撃したらダメージが表示されるようにしたけど、敵の体力ゲージも表示させたい。

攻撃した時だけ表示されるようにして、一定時間で消えるようにしたいですね。

ChatGPTパイセンに聞いてみる

彼に聞けばたちどころに答えてくれるに違いない…。

Unity 敵 体力 HP ゲージ
神部まゆみ
神部まゆみ

次は敵の体力ゲージを表示したいです。普段は非表示で、こちらが攻撃してダメージを与えた時に見えるようにしたいです。デザインはシンプルな横のバー形式で、最大HPがわかりやすく半透明で表示されていると理想的です。あまり大きいと邪魔になってしまうためほどほどの大きさでお願いします。これもUIワールド空間でいけるのでしょうか。

ChatGPT
ChatGPT

いいですね、その仕様はTPSだと王道かつ「気持ちいい」やつです 👍
結論から言うと UIワールド空間でバッチリ実現できます。
しかも構成をちゃんと分ければ、敵味方どちらにも流用できます。

まず結論まとめ

  • World Space Canvas でOK
  • ✅ 普段は非表示、ダメージを受けた瞬間に表示
  • ✅ 最大HPが分かる 半透明の背景バー
  • ✅ HP量に応じて 前面バーが減る
  • ✅ サイズは小さめで敵の頭上に表示

全体構成(これが完成形イメージ)

Enemy
 ├─ Collider
 ├─ EnemyHealth.cs
 └─ HPBar (Canvas : World Space)
     └─ HPBarRoot
         ├─ Background (Image 半透明)
         └─ Fill (Image HP量)

① HPバー用UIを作る(World Space)

手順

  1. Enemyの子に Canvas を作成
    • Render Mode:World Space
    • Scale:0.01, 0.01, 0.01(超重要)
    • サイズ例:Width 100 / Height 20
  2. Canvasを敵の頭上へ移動
    例:Y = 1.8 くらい

中身のUI

Background(最大HP用・半透明)

  • Image
  • 色:黒 or グレー
  • Alpha:100〜150くらい(半透明)

Fill(現在HP用)

  • Image
  • 色:緑(後で赤にもできる)
  • Image Type:Filled
  • Fill Method:Horizontal
  • Fill Origin:Left

② HPバー制御用スクリプト

EnemyHealth.cs(既存があれば統合OK) ※IDamageble重複を避けるためDamageReceiver.csと統合したので後述

using UnityEngine;

public class EnemyHealth : MonoBehaviour, IDamageable
{
    public int maxHP = 100;
    public int currentHP;

    [Header("HPバー")]
    public EnemyHPBar hpBar;
    public float visibleTime = 2f;

    float hideTimer;

    void Start()
    {
        currentHP = maxHP;
        hpBar.SetHP(currentHP, maxHP);
        hpBar.gameObject.SetActive(false);
    }

    public void TakeDamage(int damage)
    {
        currentHP -= damage;
        currentHP = Mathf.Max(currentHP, 0);

        Debug.Log($"Enemy Hit! HP: {currentHP}");

        hpBar.gameObject.SetActive(true);
        hpBar.SetHP(currentHP, maxHP);
        hideTimer = visibleTime;

        if (currentHP <= 0)
        {
            Die();
        }
    }

    void Update()
    {
        if (hpBar.gameObject.activeSelf)
        {
            hideTimer -= Time.deltaTime;
            if (hideTimer <= 0)
            {
                hpBar.gameObject.SetActive(false);
            }
        }
    }

    void Die()
    {
        Destroy(gameObject);
    }
}

③ HPバー側のスクリプト

using UnityEngine;
using UnityEngine.UI;

public class EnemyHPBar : MonoBehaviour
{
    public Image fillImage;

    public void SetHP(int current, int max)
    {
        fillImage.fillAmount = (float)current / max;
    }
}

④ Inspector設定(ここ重要)

EnemyHealth

  • Hp Bar → HPBar(Canvas)を指定

EnemyHPBar

  • Fill Image → 緑のFill Imageを指定

⑤ カメラに向かせる(必須)

World Space UIはそのままだと横向きになります

Billboard用スクリプト

using UnityEngine;

public class Billboard : MonoBehaviour
{
    Camera cam;

    void Start()
    {
        cam = Camera.main;
    }

    void LateUpdate()
    {
        transform.LookAt(
            transform.position + cam.transform.forward,
            cam.transform.up
        );
    }
}

👉 HPBar(Canvas) にアタッチ


デザイン面のコツ(かなり大事)

  • 横幅:60〜100
  • 高さ:8〜12
  • 背景は必ず半透明
  • HPバーは原色すぎない緑
  • 敵が多い場合は 表示時間短め(1.5〜2秒)

発展(あとで簡単にできる)

  • HPが減るほど色を
    👉 緑 → 黄色 → 赤
  • ボスだけ常時表示
  • クリティカル時だけ赤くフラッシュ
  • 味方用HPバーに流用

結論

World Space Canvasは「敵HPバーのためにある」と言っていい

今の構成(Raycastダメージ・IDamageable)とも
相性100% です。

あーなるほど、最大HPと現在HP用のバーを用意すれば良いんだ。

背景に最大HPを、その上に現在HPを表示して、ダメージを受けたら現在HPを減らしてバーを縮めれば良いって感じ。

実際に実装してみる

とりあえず実装していってみます。

Enemyの子にキャンバスを追加、子に最大HPと現在HP用のImageを追加

Enemy

  ーImage

  ーImage

って感じ。Imageの一方は最大HPを表示する背景、もう一つは現在HPを表示する用です。

名前は適当にリネームしてください。

Unity 敵 体力 HP ゲージ 最大HP 表示

キャンバスはワールド空間にしてスケールを0.01に、位置はほぼXYZ0でいいけどYだけちょこっと上にして頭のあたりに表示する。

幅は100 200あたりがちょうどいいかな。

Unity 敵 体力 HP ゲージ 最大HP 表示

Backgroundは最大HPになるやつなので、色を黒っぽくしてアルファ値を100~150くらいにして半透明にする。

幅も100 20くらいで細長くしておく。

Unity 敵 体力 HP ゲージ 最大HP 表示

Fillは現在HP。後で詳しく設定するけど、とりあえず最大HPのBackgroundより幅高さを小さめに、色とアルファ値だけ設定しておく。

Unity 敵 体力 HP ゲージ 最大HP 表示

これでこんな感じに表示されます。

Unity 敵 体力 HP ゲージ 最大HP 表示

スクリプトをコピペする

スクリプトを3つ使うけど、ここで全部コピペしておきます。

EnemyHealth.cs

using UnityEngine;
using System.Collections;

public class EnemyHealth : MonoBehaviour, IDamageable
{
    public int maxHP = 100;
    public int currentHP;

    [Header("HP Bar")]
    public EnemyHPBar hpBar;
    public float hpBarVisibleTime = 2f;
    float hideTimer;

    [Header("Damage UI")]
    public GameObject damagePopupPrefab;
    public Transform popupSpawnPoint;

    [Header("Flash")]
    public Renderer[] renderers;
    public Color flashColor = Color.red;
    public float flashDuration = 0.1f;

    Color[] originalColors;

    void Awake()
    {
        currentHP = maxHP;

        originalColors = new Color[renderers.Length];
        for (int i = 0; i < renderers.Length; i++)
        {
            originalColors[i] = renderers[i].material.color;
        }

        if (hpBar != null)
            hpBar.gameObject.SetActive(false);
    }

    public void TakeDamage(int damage)
    {
        Debug.Log("EnemyHealth.TakeDamage 呼ばれた");

        currentHP -= damage;
        currentHP = Mathf.Max(currentHP, 0);

        ShowDamagePopup(damage);
        StartCoroutine(Flash());

        if (hpBar != null)
        {
            hpBar.gameObject.SetActive(true);
            hpBar.SetHP(currentHP, maxHP);
            hideTimer = hpBarVisibleTime;
        }

        if (currentHP <= 0)
        {
            Die();
        }
    }

    void Update()
    {
        if (hpBar != null && hpBar.gameObject.activeSelf)
        {
            hideTimer -= Time.deltaTime;
            if (hideTimer <= 0)
                hpBar.gameObject.SetActive(false);
        }
    }

    void ShowDamagePopup(int damage)
    {
        if (damagePopupPrefab == null)
            return;

        Vector3 pos = popupSpawnPoint != null
            ? popupSpawnPoint.position
            : transform.position + Vector3.up;

        Instantiate(damagePopupPrefab, pos, Quaternion.identity)
            .GetComponent<DamagePopup>()
            .Setup(damage);
    }

    IEnumerator Flash()
    {
        foreach (var r in renderers)
            r.material.color = flashColor;

        yield return new WaitForSeconds(flashDuration);

        for (int i = 0; i < renderers.Length; i++)
            renderers[i].material.color = originalColors[i];
    }

    void Die()
    {
        Destroy(gameObject);
    }
}
Unity 敵 体力 HP ゲージ 最大HP 表示

EnemyHPBar.cs

using UnityEngine;
using UnityEngine.UI;

public class EnemyHPBar : MonoBehaviour
{
    public Image fillImage;

    public void SetHP(int current, int max)
    {
        fillImage.fillAmount = (float)current / max;
    }
}
Unity 敵 体力 HP ゲージ 最大HP 表示

Billboard.cs

using UnityEngine;

public class Billboard : MonoBehaviour
{
    Camera cam;

    void Start()
    {
        cam = Camera.main;
    }

    void LateUpdate()
    {
        transform.LookAt(
            transform.position + cam.transform.forward,
            cam.transform.up
        );
    }
}
Unity 敵 体力 HP ゲージ 最大HP 表示

スクリプトをアタッチして設定する

EnemyにEnemyHealthをアタッチ、CanvasにEnemyHPBarとBillboardをアタッチします。

EnemyHealthをキャンバスにアタッチしてしまうと動きません。

EnemyHealthは前回追加したDamageReceiverと統合したので、HPBar以外は前回の設定を流用します。

HPBarにはキャンバスを指定する。

Unity 敵 体力 HP ゲージ 最大HP 表示

キャンバス(HPBar)の設定はこんな感じ。

BillboardコンポーネントはつけるだけでOK。EnemyHPBarには現在HPのほうのImageを指定します。

Unity 敵 体力 HP ゲージ 最大HP 表示

【重要】DamageReceiverは消す

IDamageableっていうのはInterface命令を使ったスクリプトを呼んでるんだけど、前回作ったDamageReceiverにも使っていて重複している。

public class EnemyHealth : MonoBehaviour, IDamageable
public class DamageReceiver : MonoBehaviour, IDamageable

Interface命令は重複しているとどちらが呼ばれるか分からないみたいで一つにした方が良いっぽい。

スクリプトではEnemyHealthにDamageReceiverの機能も入れて統合させています。

DamageReceiverがあるとGetComponentで呼ばれてしまうため削除しましょう。

インスペクターオフにしても呼ばれてしまうので削除するしかないです。

Fill(Image)の設定

Fill(Image)の設定はこんな感じ。

Unity 敵 体力 HP ゲージ 最大HP 表示

Imageのソース画像がNoneだと「画像タイプ」より下の設定が出ないので注意。

とりあえず適当な画像がなかったので、Unityデフォルトで入っていたUISPriteを表示しています。

UISPriteは四角いスプライト画像なので細長くすると端っこが滲んでしまうけど、とりあえず動けばいいので後で細長い画像を作って指定するとベストみたい。

Unity 敵 体力 HP ゲージ 最大HP 表示

これで動いた!

これで無事に動きましたね。

HPが50%以下なら黄色に、20%以下なら赤色にする

ついでにやってみました。

EnemyHPBar.csを書き換えればOK。

using UnityEngine;
using UnityEngine.UI;

public class EnemyHPBar : MonoBehaviour
{
    public Image fillImage;

    [Header("HP Color")]
    public Color highHPColor = Color.green;
    public Color midHPColor = Color.yellow;
    public Color lowHPColor = Color.red;

    public void SetHP(int current, int max)
    {
        float ratio = (float)current / max;
        fillImage.fillAmount = ratio;

        UpdateColor(ratio);
    }

    void UpdateColor(float ratio)
    {
        if (ratio <= 0.2f)
        {
            fillImage.color = lowHPColor;
        }
        else if (ratio <= 0.5f)
        {
            fillImage.color = midHPColor;
        }
        else
        {
            fillImage.color = highHPColor;
        }
    }
}

これでこんな感じになりました。

おわりに

無事に動いて良かった。

ダメージ関係はこれでだいたいできたかなぁ。

また何かあれば追記します(*^_^*)

タイトルとURLをコピーしました