Я так делаю...
У префаба есть дочерний обьект Indicator c компонентом RectTransform и оправляющим скриптом.
Используется csharp
public abstract class UI_BotIndicatorBasys : MonoBehaviour
{
[Header("Ссылка на данный RectTransform")]
[SerializeField] protected RectTransform rectTarnsform;
[SerializeField]
protected BotControllerBasys botController;
[Header("Высота над обьектом - целью")]
[SerializeField]
protected float upValue = 1;
[Header("Максимальный угол видимости индикатора")]
[SerializeField]
protected float maxAngle;
[Header("Обьект идикатор, который вкл/выкл")]
[SerializeField]
protected GameObject indicatorObj;
[Header("Ссылка на ui обьект, к которому удачеряется данный обьект")]
[SerializeField]
protected Transform parentTransform;
protected Camera camera;
protected void Awake()
{
botController = GetComponentInParent<BotControllerBasys>();
}
protected virtual void OnEnable()
{
indicatorObj.SetActive(true);
if (camera == null)
{
camera = GameObject.Find("Player").GetComponentInChildren<Camera>();
}
}
protected virtual void Update()
{
}
protected bool CheckAngle(float maxAngle, Vector3 front1, Vector3 front2)
{
if (Vector3.Angle(front1, front2) > maxAngle)
{
return false;
}
return true;
}
protected void SetScreenPosition(Vector3 position, float upValue)
{
rectTarnsform.position = camera.WorldToScreenPoint(position + Vector3.up * upValue);
}
}
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class UI_HeathIndicator : UI_BotIndicatorBasys
{
[Header("Локальные переменные")]
[SerializeField]
private RectTransform healthImageTransform;
[Header("Debug")]
public float currentHealth;
public Vector2 currentSize;
protected override void Update()
{
base.Update();
if (botController.Health <= 0)
{
indicatorObj.SetActive(false);
return;
}
if (botController.gameObject.activeSelf == false)
{
indicatorObj.SetActive(false);
return;
}
if (GameController.showBotIndicator == false)
{
indicatorObj.SetActive(false);
return;
}
if (CheckAngle(maxAngle, PlayerController.selfTransform.TransformDirection(Vector3.forward * 100), botController.thisTransform.position - PlayerController.selfTransform.position) == false)
{
indicatorObj.SetActive(false);
return;
}
indicatorObj.SetActive(true);
SetScreenPosition(botController.thisTransform.position, upValue);
SetSizeImage(botController.Health);
//Debug
currentHealth = botController.Health;
currentSize = rectTarnsform.sizeDelta;
//EndDebug
}
private void SetSizeImage(float value)
{
healthImageTransform.sizeDelta = new Vector2(value, 10);
}
}
На старте indicator находит Canvas и удочеряется к нему.
В дальнейшем он имеет ссылку на класс обьект - цель и может оперировать его данными(здоровье, позиция, имя, все, что вам может понадобится отобразить на экране)
А свою видимость на экране он определяет расчетом угла между камерой и целью.
Остается только отсортировать индикаторы по расстоянию до камеры, что бы они правильно налаживались друг на друга. Самые дальние в иерархии сцены были первые и самые ближние - последние.
вот таким кодом
arrayEnemyBot = arrayEnemyBot.OrderByDescending(obj => ((botController.transform.position + tempVector) - (obj.transform.position + tempVector)).sqrMagnitude).ToList();
У меня этим занимается радар.