Вывод потерянных хит поинтов на экран

Такое, часто используется в играх, с видом от третьего лица. Суть в том, что, когда происходит попадание в бота, помимо того, что у него отнимается здоровье, еще на экран выводится число, которое и отображает, сколько здоровья было выбито с бота. Данный текст имеет характерную анимацию, движение вверх экрана и плавное затухание. Вся система очень просто встраивается в игру и чтобы вывести текст, нужно отправить несколько параметров: позицию попадания, уровень повреждения, цвет и размер шрифта, а так-же время жизни текста на экране. Кроме того, мы не будем использовать функции, создать/уничтожить объект, каждый раз. Так как, ботов может быть множество, а соответственно и попаданий тоже, лучше сразу перейти на пул объектов. Иначе говоря, создать сразу нужное количество объектов на основе шаблона, а потом переключаться между ними.


Для начала, сделаем пул объектов. Добавим на сцену новый Canvas и удаляем компонент Graphic Raycaster, так как нам не требуется взаимодействие с текстовыми объектами. Теперь, нужно создать шаблон на основе UI Text, настроить шрифт, выравнивание текста и прочее.

Далее, на UI Text вешаем:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class HitsComponent : MonoBehaviour {

	[SerializeField] private float speed = 100; // скорость движения текста
	[SerializeField] private Text _Text;
	[SerializeField] private RectTransform _RectTransform;

	private float lifeTime;
	private Vector3 hitPosition;
	private float curTime;
	private Color clear;
	private Vector2 upPosition;

	public RectTransform getTransform
	{
		get{ return _RectTransform; }
	}
	
	public Text getText
	{
		get{ return _Text; }
	}

	public void SetOptions(Color clearColor, float time, Vector3 hitPos)
	{
		clear = clearColor;
		lifeTime = time;
		hitPosition = hitPos;
	}

	void LateUpdate() // анимация текста
	{
		Vector2 curPosition = Camera.main.WorldToScreenPoint(hitPosition);
		upPosition += Vector2.up * speed * Time.deltaTime;
		clear.a = 1 - curTime/lifeTime;
		_Text.color = clear;
		_RectTransform.anchoredPosition = curPosition + upPosition;
		curTime += Time.deltaTime;
		if(curTime > lifeTime)
		{
			_RectTransform.anchoredPosition = Vector2.zero;
			upPosition = Vector2.zero;
			curTime = 0;
			gameObject.SetActive(false);
		}
	}
}

Навастриваем поля и шаблон готов.

Возвращаемся к нашему Canvas и вешаем на него:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class HitsPool : MonoBehaviour {

	[SerializeField] private HitsComponent sample; // шаблон UI Text
	[SerializeField] private int objectCount = 50; // сколько копий создать

	void Awake()
	{
		if(Hits.Sample.Length > 0) return;
		sample.gameObject.SetActive(false);
		List<HitsComponent> list = new List<HitsComponent>();
		for(int i = 0; i < objectCount; i++)
		{
			HitsComponent clone = Instantiate(sample) as HitsComponent;
			clone.getTransform.SetParent(transform);
			clone.getTransform.localScale = Vector3.one;
			list.Add(clone);
		}
		Hits.SetHitsComponent(list.ToArray());
	}
}

Здесь главное определиться, сколько объектов создавать. Зависит это от динамики игры, сколько ботов в кадре, частота попадания по ним. В принципе, где-то 50-100 копий должно вполне хватить.

В папке проекта со скриптами, создадим еще один:

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class Hits {

	private static HitsComponent[] sample = new HitsComponent[]{};

	public static HitsComponent[] Sample
	{
		get{ return sample; }
	}

	public static void SetHitsComponent(HitsComponent[] arr)
	{
		sample = arr;
	}

	static bool IsBehind(Vector3 position) // находится ли позиция за камерой
	{
		if(Vector3.Dot(Camera.main.transform.TransformDirection(Vector3.forward), position - Camera.main.transform.position) < 0)
		{
			return true;
		}

		return false;
	}

	public static void AddHit(Vector3 position, float damage, Color color, int fontSize, float lifeTime)
	{
		int j = -1;

		for(int i = 0; i < sample.Length; i++)
		{
			if(!sample[i].isActiveAndEnabled) // поиск не активного элемента
			{
				j = i; // сохраняем id элемента
				break; // выходим
			}
		}

		if(j == -1 || IsBehind(position)) return;

		Color clear = color;
		clear.a = 0;
		sample[j].getText.fontSize = fontSize;
		sample[j].getText.text = damage.ToString();
		sample[j].getTransform.sizeDelta = new Vector2(sample[j].getText.preferredWidth, sample[j].getText.preferredHeight);
		sample[j].getText.color = color;
		sample[j].SetOptions(clear, lifeTime, position);
		sample[j].gameObject.SetActive(true);
	}
}

Именно через этот класс мы и будем выводить хит поинты на экран.

В качестве примера, сделаем вариант для триггера (пуля, снаряд):

using UnityEngine;
using System.Collections;

public class HitsTrigger : MonoBehaviour {

	[Header("Hits")] // настройки для вывода текста
	[SerializeField] private float damage;
	[SerializeField] private float duration;
	[SerializeField] private Color color;
	[SerializeField] private int fontSize;

	[Header("Trigger")] // настройки триггера
	[SerializeField] private string[] tagList;
	[SerializeField] private LayerMask layerMask;

	bool CheckObject(GameObject obj) // проверка объекта на соответствие по, маске слоя или тега
	{
		if(((1 << obj.layer) & layerMask) != 0)
		{
			return true;
		}

		foreach(string t in tagList)
		{
			if(obj.tag == t) return true;
		}

		return false;
	}

	void OnTriggerEnter(Collider coll)
	{
		if(!coll.isTrigger && CheckObject(coll.gameObject))
		{
			Hits.AddHit(transform.position, damage, color, fontSize, duration);
			Destroy(gameObject);
		}
	}
}

Как только снаряд, сталкивается с нужным объектом, на экран будет выведен текст.

Всё достаточно просто:

Hits.AddHit(transform.position, damage, color, fontSize, duration);

Позиция попадания, урон, цвет текста, размер шрифта, время жизни текстового объекта.

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

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

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

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

Офлайн
Light 9 февраля 2018
Feuermagier, само собой на каждой сцене должен присутствовать пул объектов, который используется классом Hits.
Офлайн
Feuermagier 8 февраля 2018
Light,
Ошибку решил добавлением в метод Awake
DontDestroyonload(transform.gameObject);
Офлайн
Feuermagier 7 февраля 2018
Light,
Огромное спасибо. Прям полвечера проковырялся пока сюда не зашел. Забрал, в практически первозданном виде вкорячил в свой проектик. На циферки кстати можно Outline повесить чтобы поконтрастнее на неоднородном фоне смотрелись, но это так уже, красивости.

Ошибка при рестарте тоже появилась:
MissingReferenceException: The object of type 'HitsComponent' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
Hits.AddHit (Vector3 position, Single damage, Color color, Int32 fontSize, Single lifeTime) (at Assets/NULLcode Studio/Hits/Scripts/Hits.cs:43)
AgentBehaviour.OnTriggerEnter2D (UnityEngine.Collider2D col) (at Assets/scripts/AI/0.Common/AgentBehaviour.cs:78)
Офлайн
Light 30 ноября 2017
Trafalgar, подробнее, для начала - что за ошибка.
Офлайн
Trafalgar 29 ноября 2017
При рестарте не создаются клоны и выдается ошибка, можете помочь (проект 2D)?
Офлайн
Light 28 марта 2017
vaseel1ch, в статью добавлено демо для 2д проектов.
Офлайн
vaseel1ch 28 марта 2017
Как можно адаптировать скрипты под 2D игру ?
переписал OnTriggerEnter на 2D, коллайдеры тоже, в некоторых местах переписал векторы на двумерные, но так ничего и не отображается
Офлайн
Light 27 октября 2016
alex.protek, проверка объекта делается в CheckObject в момент контакта. Настройки масок или тегов, делается в скрипте HitsTrigger. Это скрипт для пули/снаряда, и получается что разные пули/снаряды можно настроить на разные типы целей.
Офлайн
alex.protek 26 октября 2016
не пойму как вичисляется проверка объекта на соответствие по, маске слоя или тега. где указывать по какому тегу должна быть проверка?
Офлайн
PlayGS 30 июля 2016
Прикольно смотрится. Можно побаловаться
Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.
  • Яндекс.Метрика