Unityにおける1つのCanvasで複数のゲームオブジェクトの頭上にTextMeshProテキストを表示する方法

複数のゲームオブジェクトの頭上に名前やステータスなどのテキストを表示する際、各オブジェクトごとにCanvasを作成すると管理が煩雑になり、パフォーマンスにも影響を与える可能性があります。1つのCanvasでこれらのテキストを管理することで、効率的な開発とパフォーマンスの最適化が可能です。本資料では、1つのCanvasを使用して複数のゲームオブジェクトの頭上にTextMeshProテキストを表示する方法を詳しく解説します。

方法の概要

  • Screen Space – OverlayまたはCameraモードのCanvasを使用し、ゲームオブジェクトのワールド座標をスクリーン座標に変換してテキストの位置を設定します。
  • ワールド空間のCanvasを使用しないため、1つのCanvasで複数のUI要素を効率的に管理できます。

手順

1. Canvasの作成と設定

  1. Canvasの作成
  • ヒエラルキーウィンドウで右クリックし、UI > Canvasを選択してCanvasを作成します。
  1. Canvasの設定
  • 作成したCanvasを選択し、Inspectorウィンドウで以下を設定します。
    • Render ModeScreen Space - Overlay または Screen Space - Camera を選択。
    • Canvas ScalerUI Scale ModeScale With Screen Sizeに設定し、解像度の変化に対応。

2. テキストプレハブの作成

  1. TextMeshProオブジェクトの作成
  • ヒエラルキーウィンドウでCanvasを右クリックし、UI > Text - TextMeshProを選択してテキストオブジェクトを作成します。
  1. テキストの設定
  • 作成したTextMeshProテキストのフォント、サイズ、色、配置などを設定します。
  1. プレハブ化
  • テキストオブジェクトをプロジェクトウィンドウにドラッグ&ドロップし、プレハブとして保存します。

3. スクリプトの作成

  1. HeadUpDisplayManager.csの作成
   using UnityEngine;
   using TMPro;
   using System.Collections.Generic;

   public class HeadUpDisplayManager : MonoBehaviour
   {
       public Canvas canvas;
       public GameObject textPrefab;

       private Camera mainCamera;
       private Dictionary<Transform, TextMeshProUGUI> textElements = new Dictionary<Transform, TextMeshProUGUI>();

       void Start()
       {
           mainCamera = Camera.main;

           // 対象となるゲームオブジェクトを取得(タグなどで管理)
           GameObject[] targets = GameObject.FindGameObjectsWithTag("Target");

           foreach (GameObject target in targets)
           {
               CreateTextElement(target.transform);
           }
       }

       void Update()
       {
           foreach (var item in textElements)
           {
               UpdateTextPosition(item.Key, item.Value);
           }
       }

       void CreateTextElement(Transform target)
       {
           // テキストオブジェクトをCanvasの子として生成
           GameObject textObj = Instantiate(textPrefab, canvas.transform);
           TextMeshProUGUI tmp = textObj.GetComponent<TextMeshProUGUI>();

           // 初期設定
           tmp.text = target.name; // または他の表示内容
           tmp.alignment = TextAlignmentOptions.Center;

           // 辞書に登録
           textElements.Add(target, tmp);
       }

       void UpdateTextPosition(Transform target, TextMeshProUGUI tmp)
       {
           // ワールド座標からスクリーン座標に変換
           Vector3 screenPos = mainCamera.WorldToScreenPoint(target.position + Vector3.up * 2.0f); // 頭上2ユニット上

           // テキストの表示・非表示を制御(カメラの前にある場合のみ表示)
           if (screenPos.z > 0)
           {
               tmp.transform.position = screenPos;
               tmp.enabled = true;
           }
           else
           {
               tmp.enabled = false;
           }
       }
   }
  1. スクリプトのアタッチ
  • 空のゲームオブジェクトをシーン内に作成し、HeadUpDisplayManagerスクリプトをアタッチします。
  • Inspectorで、CanvasText Prefabを設定します。

4. ゲームオブジェクトの準備

  • タグの設定
  • 頭上にテキストを表示したいゲームオブジェクトに、共通のタグ(例:Target)を設定します。
  • オブジェクトのスクリプト(必要に応じて)
  • ゲームオブジェクトに表示内容を提供するためのスクリプトをアタッチし、HeadUpDisplayManagerでそれを参照します。

5. テキストの動的更新(オプション)

  • 情報の更新
  • UpdateTextPosition内で、必要に応じてテキストの内容を更新します。
  void UpdateTextPosition(Transform target, TextMeshProUGUI tmp)
  {
      // ...(前略)

      // テキスト内容の更新
      var status = target.GetComponent<Status>(); // Statusスクリプトから情報を取得
      tmp.text = $"{target.name}\nHP: {status.currentHP}/{status.maxHP}";
  }

注意点

パフォーマンス最適化

  • Canvasの再描画を抑制
  • Canvas全体が再描画されるのを防ぐため、テキスト要素のCanvasRendererSetMaterialDirtySetVerticesDirtyの呼び出しを最小限にします。
  • テキスト更新の頻度を制限
  • 毎フレーム更新が不要な場合、UpdateではなくLateUpdateや一定間隔での更新に切り替えます。

UIの見た目と配置

  • テキストが重ならないように
  • 近接するオブジェクトのテキストが重なる場合、位置を調整するか、縮小・非表示にするロジックを追加します。
  • 画面外のオブジェクトへの対応
  • screenPos.zが負の値の場合、オブジェクトはカメラの背後にあるため、テキストを非表示にします。
  • 解像度への対応
  • Canvas Scalerを適切に設定し、異なる画面解像度でもテキストが正しく表示されるようにします。

まとめ

1つのCanvasを使用して、複数のゲームオブジェクトの頭上にTextMeshProテキストを表示することは可能であり、適切なスクリプトと設定により効率的に実現できます。ワールド座標からスクリーン座標への変換を行い、テキストの位置を動的に更新することで、オブジェクトの移動にテキストが追従します。パフォーマンスや表示上の注意点に留意しながら、効果的なUIを構築してください。

参考資料

TextMeshPro,Unity

Posted by hidepon