3D空間に浮かぶHPバー

課題

3Dゲームオブジェクト(敵キャラクター、プレイヤーキャラなど)用に、フローティング表示の「HPバー」をつけたい。

解決策

この解決策として、既存の TextureProgressBar ノードをベースにした 2D HPバーを再利用します。すでにテクスチャが設定されており、値と色を更新するためのコードも実装済みです。既に同様のシステムをお持ちの場合は、それをそのまま使用していただいて構いません。サンプルではこのシーンを「Healthbar2D」と名付けます。

alt alt

必要なアセットがある場合、バーで使用している以下の3つの画像を紹介します。

alt alt

alt alt

alt alt

メモ

既存のオブジェクトを再利用すれば、大幅に作業時間を節約できます。HPバーやカメラ、その他一般的なコンポーネントが必要なたびにゼロから作り直す必要はありません。

プロジェクト設定

例として使用する「モブ」の開始点として、CharacterBody3Dノードを設定します。このノードは自動で出現し、直線的に移動するプログラムが組まれています。また、以下のコードでダメージ処理を実装します。

func _on_input_event(_camera, event, _position, _normal, _shape_idx):
    if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
        health -= 1
        if health <= 0:
            queue_free()

alt alt

単位をクリックするたびに1ダメージが与えられます。合計10ダメージを与えると、そのユニットは破壊されます。この状態を2Dバーを使って視覚的に表現する必要があります。

2Dを3Dに変換

Sprite3Dを使用することで、2D画像を3D空間で表示することが可能です。新しいシーンに追加し、「Healthbar3D」という名前を付けます。まず設定とサイズ調整を行いますので、 Texture プロパティに緑色のバー画像を設定してください。

Sprite3Dは通常の3Dオブジェクトと同様に動作します。カメラを移動させると、視点が変わるためです。ただし、HPバーは常にカメラの方を向くようにして、いつでも確認できるようにしたいです。

インスペクターで、 Flags セクションの Billboard を「Enabled(有効)」に設定してください。

続いてカメラを動かして、テクスチャが常にプレイヤー側を向いているか確認してください。

alt alt

このシーンのインスタンスをMobシーンに追加し、バーをモブの体の上に配置してください。

alt alt

ビューポートテクスチャ

Sprite3D ノードが静的なテクスチャを表示するのではなく、TextureProgressBar を表示したいです。これは、テクスチャをエクスポートできる SubViewport ノードを使用することで実現できます。

以下の手順で操作してください。

  1. SubViewportSprite3D の子要素として追加してください。
  2. インスペクタウィンドウで、Transparent BG 設定を オン に設定してください。

さらに、HPバーテクスチャのサイズに合わせてビューポートのサイズを設定する必要があり、そのサイズは(200, 26)です。

インスタンス化する際に、HealthBar2DViewport の子要素として配置してください。シーン構成は以下のようになるはずです。

alt alt

もし SubViewportSprite3D の子要素でなかった場合、インスペクター上で直接スプライトのテクスチャとして設定できます。しかしこれは子要素であるため、適切なタイミングで準備が整っていない可能性があります。そのため、以下のように Sprite3D にアタッチされたスクリプト内で設定します。

extends Sprite3D

func _ready():
    texture = $SubViewport.get_texture()

作ったものを統合しよう

モブの _on_input_event() メソッド内で、HPを減少させた後に以下を追加してください。

$HealthBar3D.update(health, max_health)

以下の内容を HealthBar3D.gd に追加してください。

func update_health(_value, _max_value):
    $SubViewport/HealthBar2D.update_health(_value, _max_value)

このコードは、2Dバーに既に存在するupdateメソッドを呼び出しています。進捗バーの値を設定するとともに、バーの色を選択しています。

func update_health(_value, _max_value):
    value = _value
    if value < _max_value:
        show()
    texture_progress = bar_green
    if value < 0.75 * _max_value:
        texture_progress = bar_yellow
    if value < 0.45 * _max_value:
        texture_progress = bar_red

クリックしてモブのHPゲージが変化する様子を確認してください。

alt alt

まとめ

このテクニックを使えば、Node2Dノードはもちろん、Controlノード全般(例:LabelVideoStreamPlayerなど)を3D空間に表示できます。さらに、SubViewportを使えば、2Dゲーム全体を3D空間に「投影」することもできます。

プロジェクトのダウンロード

プロジェクトコードはこちらからダウンロードできます。https://github.com/godotrecipes/3d_object_healthbars