Вывод внутриигровых сообщений с помощью Particle System
Реализовываем показ урона, нехватки здоровья и другой важной для игрока информации на примере нашей игры The Unliving
Задача
При разработке игры, мы поставили перед собой задачу по отображению различных сообщений, таких, как нанесенный урон, нехватка здоровья или энергии, величина награды, количество восстановленных очков здоровья и т.д., с помощью Particle System. Это было решено сделать для того, чтобы получить больше возможностей для кастомизации эффектов появления и дальнейшего поведения таких сообщений, что проблематично при использовании стандартных элементов UI-системы Unity.
Кроме того, данный подход подразумевает использование всего лишь одного инстанса Particle System для каждого типа сообщений, что дает огромный прирост в производительности по сравнению с выводом этих же сообщений с помощью Unity UI.
Алгоритм решения
С помощью шейдера отображаем заранее подготовленную текстуру, используя правильные UV-координаты. Информацию с UV-координатами передаем двумя потоками (vertex streams) в ParticleSystem с помощью ParticleSystem.SetCustomParticleData в виде списка Vector4.
Наша реализация предполагает использование текстуры содержащей 10 строк и 10 столбцов символов. В качестве шрифта может быть использован любой моноширинный шрифт. Это необходимо во избежание разных интервалов между символами сообщения.
Пошаговая реализация
Создание Vector4 для передачи в Vertex Stream
Для описания набора символов будем использовать структуру SymbolsTextureData.
Массив chars необходим заполнить вручную, по порядку добавив в него все символы текстуры шрифта начиная с левого-верхнего угла.
В результате мы получим класс TextRendererParticleSystem. При вызове публичного метода SpawnParticle, будет происходить спаун одной частицы Particle System в нужную позицию, с нужным значением, цветом и размером.
Particle System в Unity позволяет передать кастомные данные в виде 2х потоков Vector4.
Мы намеренно добавили лишний поток с UV2, чтобы избежать сдвига по координатам потоков. Если этого не сделать, то координатам X и Y Custom1-вектора в C # будут соответствовать Z и W TEXCOORD0 шейдера. И соответственно, Custom1.z = TEXCOORD1.x, Custom1.w = TEXCOORD1.y. Что доставит много неудобств в дальнейшем.
Как было описано ранее, для передачи длины сообщения и UV-координат символов мы будем использовать два Vector4. Так как Vector4 содержит 4 элемента типа float, то по умолчанию мы можем упаковать в него 4 * 4 = 16 байт данных. Т.к. наше сообщение будет содержать только длину сообщения (двузначное число) и координаты символов (двузначное число для каждого символа), то диапазон типа byte (0-255) для нас избыточен. В то время как использование десятичных разрядов подойдет отлично.
Точность float составляет 6-9 символов, значит мы смело можем использовать 6 разрядов каждой координаты Vector4 и не переживать за целостность и точность данных. На самом деле, мы пробовали паковать 7, 8 и 9 символов, но точности float не хватает.
Получается, что в каждый float, используя десятичные разряды, мы упакуем целых 6 цифр, в отличии от стандартного варианта с четырьмя байтами. Итого, один Vector4 будет содержать 24 однозначных числа.
Мы можем передать в потоке 2 вектора, поэтому будем использовать оба для передачи сообщения длиной до 23 символов:
Custom1.xyzw — первые 12 символов сообщения.
Custom2.xyzw — еще 11 символов сообщения + длина сообщения (последние 2 символа).
В коде упаковка строки в два Vector4 будет выглядеть следующим образом:
Вектора с CustomData готовы. Пришло время вручную заспаунить новую частицу с нужными параметрами.
Спаун частицы
Первое, что мы должны сделать, убедиться, что CustomData потоки активированы в настройках Renderer системы частиц:
Для создания частицы воспользуемся методом Emit() класса ParticleSystem.
Добавим оба блока в метод SpawnParticle() и C # часть готова: сообщение упаковано и передано GPU в виде двух Vector4 в Vertex Stream. Осталось самое интересное — принять эти данные и правильно отобразить.
Код шейдера
Редактор Unity
Создаем материал и назначаем ему наш шейдер. На сцене создаем объект с компонентом ParticleSystem, назначаем созданный материал. Затем настраиваем поведение частиц и отключаем параметр Play On Awake. Из любого класса вызываем метод RendererParticleSystem.SpawnParticle() или используем дебажный метод.
С исходным кодом, ресурсами и примером использования можно ознакомиться здесь.
Вот и все. Вывод сообщений с помощью Particle System готов! Надеемся, это решение принесет пользу разработчикам игр на Unity.
Знатно заморочились, приятно видеть такое на DTF. Но я пожалуй продолжу делать подобные вещи на UI, это проще и выглядит как-то гибче всё же.
А если попробовать эти надписи локализовать еще, ух!
Отличная статья уровня хабра в техническом плане)Спасибо
Комментарий недоступен
Она кстати сперва там появилась)
Учитывая, что уровень нынешнего хабра это двадцатая за полгода статья на тему "посмотрите на список 10 новых возможностей JS (за 2017 год)". Весьма тонко.
Комментарий недоступен