HealthBar и имя противника

В долгих попытках найти приемлемый хелбар для противников в моём проекте так ничего и не найдя было решено крафтить хелбар под себя. Перелопатив кучу англоязычных форумов была выработана концепция и получен результат. Если кому вдруг понадобится берите и используйте, весь код откомментированный так что проблем быть не должно.

Для начала настроим сцену:

Создадим канвас:

HealthBar и имя противника


В канвасе создадим пустой обьект это и назовём его HealthBar:



Добавим к нему текст и слайдер:




Почти готово, у слайдера в инспекторе отключим Background и Handle Slide Area они нам не понадобятся. (хотя в своём проекте можете с ними поиграться и настроить как вам надо)



Чтобы не заморачиваться с выставлением текста и полоски здоровья добавим к нашему основному хелбару vertical layout group:



А также canvas group чтобы сделать его не видимым пока мы его не видим.

Вешаем на него скрипт: DepthUIScript (передаёт положение переменной дальность на канвас)


using UnityEngine;

public class DepthUIScript : MonoBehaviour {

    //Дальность отображения обьекта на канвасе в мировом пространстве (вычисляется в скрипте здоровья вражины)
    public float depth;
    //Канвас группа 
    private CanvasGroup canvasGroup;

    void Start()
    {   //Берём канвас группу для дальнейшего взаимодействия
        canvasGroup = GetComponent();

    }

    // Update is called once per frame
    void Update ()
    {
		
	}

    //Функция в которой задаём альфу канвас группе
    public void SetAlpha(float alpha)
    {   //Стартовую альфу равняем альфе полученной из скрипта здоровья вражины
        canvasGroup.alpha = alpha;
        //если альфа меньше или равна нулю
        if (alpha  0)
        {   //делаем панель активной
            healthPanel.SetActive(true);
        }
        else
        {   //если вне зоны видимости делаем не активной
            healthPanel.SetActive(false);
        }

    }

    //Собственно само полученние урона (получаем урон от обьекта который попал в коллайдер)
    public void TakeDamage(int amount, Vector3 hitPoint)
    {   //отнимаем полученное значение урона от текущей жизни
        currentHealth -= amount;
        //если текущая жизнь меньше нуля
        if (currentHealth  0)
        {
            // Задаём рейкаст
            RaycastHit hit;
            // Если рейкаст в старойй позиции но по нужному направлению и дистанции
            if (Physics.Raycast(oldPos, direction, out hit, dist))
            {
                // берём скрипт здоровья в точке попадания
                EnemyHealth enemyHealth = hit.collider.GetComponent();

                // Если в точке попадания есть скрипт здоровья
                if (enemyHealth != null)
                {
                    // Наносим урон
                    enemyHealth.TakeDamage(attackDamage, hit.point);
                }
            
        // Задаём положение как старое
        oldPos = transform.position;
        // Задаём актуальное положение как новое
        transform.position = newPos;
    }

}

На Канвас вешаем SSCScript (отвечает за расположение хелбаров на канвасе в мировом пространстве) :

using System.Collections.Generic;
using UnityEngine;

public class SSCScript : MonoBehaviour {

    //создаём колекцию панелей содержащих скрипт дальности отображения обьекта на канвасе в мировом пространстве
    List panels = new List();

    void Awake()
    {   //Удаляем все панели 
        panels.Clear();
    }
    void Update()
    {   //запускаем функцию сортировки
        Sort();
    }

    //Добавляем на канвас из коллекции
    public void AddToCanvas(GameObject objectToAdd)
    {   //берём скрипт дальности отображения
        panels.Add(objectToAdd.GetComponent());
    }

    //функция сортировки
    void Sort()
    {
            // сортируем в зависимости от дальности
            panels.Sort((x, y) => x.depth.CompareTo(y.depth));
            //добавляем панели если такие появляются к коллекции
            for (int i = 0; i < panels.Count; i++)
            {   // присваеваем номер в коллекции
                panels[i].transform.SetSiblingIndex(i);
            }
        //И чистим коллекцию (для того чтобы скрипт не искал уже уничтоженные панели и не пытался их вернуть в коллекцию)
        panels.Clear();
    }

}


Вот в принципе и всё готово.

Осталось только певесить скрипт EnemyHealth на самого врага:

using UnityEngine;
using UnityEngine.UI;

public class EnemyHealth : MonoBehaviour
{
    // Имя врага (этого игрового обьекта)
    public string monsterName = "Вражина";
    // Стартовое здоровье
    public int startingHealth = 100;
    //Префаб смертных мук :)) 
    public Transform DeathEffect;
    //Вражины хелбар (этого игрового обьекта)
    public GameObject healthPrefab;
    //На какой высоте распологать хелбар над вражиной (этим игровым обьектом)
    public float healthPanelOffset = 2f;
    //Дальность появления хелбара
    public float healthPanelVisible = 10f;
    //Наш канвас (Общий)
    public Canvas canvas;

    //Рабочие переменные

    // Здоровье на данный момент
    private int currentHealth;
    //Панель здоровья (этого игрового обьекта)
    private GameObject healthPanel;
    //Имя вражины (этого игрового обьекта)
    private Text enemyName;
    //Слайдер хелбара (этого игрового обьекта)
    private Slider healthSlider;
    //Скрипт расположения хелбара на канвасе в мировом пространстве
    private DepthUIScript depthUIScript;
    //Визуализатор (отображает хелбар этого игрового обьекта)
    private Renderer selfRenderer;
    


    void Awake()
    {
       
        // Текущее здоровье приравниваем к стартовому
        currentHealth = startingHealth;
        // Извлекаем из перфаба хелбара Панель здоровья
        healthPanel = Instantiate(healthPrefab) as GameObject;
        //Назначаем Канвас родителем панели здоровья (родитель это тот обьект от которого потом пляшут все размеры детей) 
        healthPanel.transform.SetParent(canvas.transform, false);
        //Извлекаем имя вражины
        enemyName = healthPanel.GetComponentInChildren<Text>();
        //Печатаем имя вражины
        enemyName.text = monsterName;
        //Берём слайдер (хелбара) из панели здоровья
        healthSlider = healthPanel.GetComponentInChildren<Slider>();
        //Берём скрипт расположения обьекта на канвасе в мировом пространстве
        depthUIScript = healthPanel.GetComponent<DepthUIScript>();
        //С канваса берём скрипт сортировки обектов в мировом пространстве и добавляем Панель здоровья
        canvas.GetComponent<SSCScript>().AddToCanvas(healthPanel);
        //отображаем панель здоровья
        selfRenderer = GetComponent<Renderer>();
    }

    void Start()
    {
        healthSlider.maxValue = startingHealth;
    }

    void Update()
    {
        //Приравниваем значение слайдера текущему здоровью
        healthSlider.value = currentHealth;
        //вычисляем мировые координаты
        Vector3 worldPos = new Vector3(transform.position.x, transform.position.y + healthPanelOffset, transform.position.z);
        //вычисляем координаты камеры
        Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPos);
        //меняем положение панели здоровья в соответствии с полученными координатами
        healthPanel.transform.position = new Vector3(screenPos.x, screenPos.y, screenPos.z);
        //вводим переменную дистанции (вычисляем расстояние между кмерой и игровым обьектом)
        float distance = (worldPos - Camera.main.transform.position).magnitude; depthUIScript.depth = -distance;
        //вводим переменную для канвас группы ( и в зависимости от дальности меняем альфу)
        float alpha = healthPanelVisible - distance / 2.0f;
        //задаём альфу
        depthUIScript.SetAlpha(alpha);
        //если обьект в зоне видимости камеры
        if (selfRenderer.isVisible && alpha > 0)
        {   //делаем панель активной
            healthPanel.SetActive(true);
        }
        else
        {   //если вне зоны видимости делаем не активной
            healthPanel.SetActive(false);
        }

    }

    //Собственно само полученние урона (получаем урон от обьекта который попал в коллайдер)
    public void TakeDamage(int amount, Vector3 hitPoint)
    {   //отнимаем полученное значение урона от текущей жизни
        currentHealth -= amount;
        //если текущая жизнь меньше нуля
        if (currentHealth <= 0)
        {
            // запускаем функцию уничтожения
            Death();
        }
    }

    // Функция уничтожения
    void Death()
    {
        //вычисляем кватерион
        Quaternion rotation = Quaternion.FromToRotation(Vector3.up, Vector3.left);
        //По этим координатам создаём обьект смертных мук
        Instantiate(DeathEffect, transform.position, rotation);
        //уничтожаем панель здоровья
        Destroy(healthPanel.transform.gameObject);
        //уничтожаем этот игровой обьект
        Destroy(this.transform.gameObject);
        
    }
    
}

В публичные поля в инспекторе добавляем:

Monster Name - Имя;
Starting Health - количество жизни;
Death Effect - префаб который инстанится после смерти персоонажа;
Health Prefab - наш недавно созданный префаб хелбара;
Health Panel Offset -на какой высоте над объектом будет находиться хелбар;
Health Panel Visible - на каком расстоянии будет отображаться

Скачать проект:

Внимание! Посетители, находящиеся в группе Гости, не могут скачивать файлы.
Тестировалось на: Unity 5.6.5f1

Комментариев 2

Офлайн
JohnnyHazz 14 мая 2018
много ошибок в текстовом описании.
Например в DepthUIScript:
canvasGroup = GetComponent(); вместо canvasGroup = GetComponent<CanvasGroup>();
if (alpha 0) вместо if (alpha <= 0) и т.д. (всего не буду описывать но рили много)

тем не менее проект рабочий, да.
Офлайн
khokhlov30 19 августа 2018
:) описание с юмором, респект
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика