Ранее я рассказывал и показывал базовые приёмы создания игры в Unity. В этой заметке сделаю эффект на кнопку, который можно включать при её выделении или как в проекте из примера - чтобы показать, что режим активирован.
Эффект будет выглядеть как комбинация время от времени пробегающего по кнопке диагонального блика и рамки вокруг кнопки. В ходе создания этого эффекта можно будет познакомиться с основными приёмами для решения массы подобных задач.
Подобные вещи логичнее всего реализовывать с помощью шейдерных эффектов. В свежих версиях Unity пользоваться чем-то сторонним или писать шейдеры кодом не надо благодаря возможностям Shader Graph. В Unity 6 по-умолчанию используется Universal Render Pipeline (URP) - для него и буду делать.
Я сделал подписи на скриншотах, так что если по тексту будет не совсем понятно - смотрите на них.
Canvas Shader Graph
В окне Project кликнем правой кнопкой мыши и выберите контекстное меню: Create > Shader Graph > URP > Canvas Shader Graph и называем его как нравится.
Откроем его (двойным кликом). Откроется вкладка Shader Graph. Вы увидите базовую структуру: пока здесь только Fragment Node, отвечающий за цвет кнопки.
Входы узла Fragment (или ещё говорят ноды) в зависимости выбранных параметров отличаются, но по-умолчанию цвет, свечение и прозрачность). Наша задача сделать такое преобразование перед его входами, чтобы на выходе получился желаемый результат.
Диагональный блик (Sweep)
Настроим цвет эффекта. Я буду делать равномерный полупрозрачный цвет. Если захотите сделать градиент или анимацию на самом блике - после прочтения этой заметки вам будут понятны принципы и известны необходимые приёмы и инструменты, так что проблем не возникнет.
Создадим узел Color: (ПКМ -> Crate Node -> Input \ Basic \ Color (но проще в строку поиска сразу Color)). Выберем в нём цвет и уровень прозрачности (у меня в примере будет оранжевый непрозрачный на 150 из 255).
Как вы видите в момент настройки цвета, что у него 4 канала из которых получается результирующий оранжевый полупрозрачный: красный (R), зелёный (G), синий (B), прозрачность (A). Так как нам надо будет иметь непрозрачную картинку на кнопке, то я перемножу значение цвета (RGB) на прозрачность (A). Для этого я помощью Split (Channel \ Split) отделю канал A а канал RGB объединю в Vector3 с помощью одноимённой ноды. В узле Multiply ( Math \ Basic \ Multiply) перемножу их.
Чтобы соединить выход одного узла со входом следующего, надо "потянуть" его зажав мышкой на выходе и отпустив на нужном входе. Но иногда удобнее делать в обратном порядке так как на месте где будет отпущена мышка появится предложение создания нового узла.
Повернём координаты, чтобы блик был по диагонали. Для этого добавим узел UV (Input \ Geometry \ UV) (выдаёт координаты текстуры кнопки).
Создадим узел Rotate (UV \ Rotate) и подключим к нему UV. В поле Rotation поставьте значение 0.78 (примерно 45 градусов). Если вам нужен другой угол то проще всего написать в поисковике или нейросети "градусы в радианы". Это сделает блик диагональным.
Настроим скорость. Создадим узел Time (Input \ Basic \ Time) (он даёт со временем увеличивающуюся последоватьльность 0, 1, 2 ..) его подадим в узел Fraction (Math \ Range \ Fraction) - он сделает циклическим от 0 до 1. Но 0 это середина объекта. Поэтому подадим его в Remap (Math \ Range \ Remap) (0:1 превращаем в его в -1:1) и умножим его с помощью Multiply на небольшое значение (например, 0.5), чтобы настроить скорость. Это и будет анимация.
Смещение. Создадим узел Tiling And Offset (UV \ Tiling And Offset). Подключим к нему повёрнутый UV, в Tiling указываем 1:1 (то есть без изменений), а в Offset подаём результат манипуляций со скоростью по координатам.
Ограничим зону эффекта прямоугольником, он будет двигаться по диагонали под настроенным углом с настроенной скоростью.
Для этого создадим узел Rectangle (Procedural \ Shape \ Rectangle). Подключим к нему изменённые UV. Настроим параметры, чтобы получить узкую полоску (например, Width = 0.2, Height = 2.0). Этот узел создаст маску, похожую на белую полоску.
Раскрасим эффект с помощью ещё одного Multipy, подав на него цвет и движущуюся прямоугольную маску.
Добавим условную логику включения.
Чтобы всё заработало надо сложить нашу маску с исходной картинкой на кнопке с помощью Add ( Math \ Basic \ Add).
Но возникает вопрос: как передать исходную картинку, ведь на каждой кнопке она своя. Добавим два поля в шейдер: исходную картинку и переключать включен или выключен эффект.
Для этого в панели с названием Шейдер Графа (её ещё называют Blackboard, она обычно сверху слева) и нажмём на +.
Для переключателя создам Boolean и назову его _IsActivated (на скриншотах и в скрипте это он). Для текстуры создам Texture2D параметр с именем _MainTex. Раньше параметры с именами _MainTex и _IsActivated автоматически связывались с соответствующими параметрами материала, поэтому традиционно их так называют.
Выделим созданные параметры и в их Node Settings (обычно справа сверху, на соседней вкладке с Graph Settings) настроим их: поставим галочку "Show in Inspector", чтобы видеть состояние в инспекторе и изменим поле Reference на то же имя (например _IsActivated), чтобы на него можно было сослаться из скрипта. На время отладки можно задать значение по-умолчанию (включен и выбрать картинку).
Овалы созданных параметров можно перетащить мышкой в нужное место графа, чтобы потом связать с входом какого-то, узла где захотим использовать этот параметр.
Создадим узел Sample Texture2D (Input \ Texture \ Sample Texture2D). Подключим _MainTex (перетащим овал этого параметра в граф) в порт Texture, а в порт UV подключите узел UV (координаты текстуры). Обратите внимание что на вход может быть подана только одна связь, а выход может быть соединён с любым количеством входов. Именно выход RGBA этого узла будем использовать в качестве исходной картинки.
Перетащим параметр _IsActivated в граф. И используем его, чтобы управлять состоянием эффекта (вкл\выкл) с помощью узла Branch (Utility \ Logoc \ Branch), подключив к его входу Predicate. На входы True подам результат, полученный после сложения картинки с движущейся полосой, а на False - исходную картинку.
Результат подадим в качестве Base Color ноды Fragment.
Скрипт
В примере выше я для отладки настраивал картинку кнопки по-умолчанию. Но если кнопок много, то естественно там надо всё очистить (эффект выключен, картинки нет). На все кнопки которые будут использовать эффект надо добавить компонент скрипта с примерно таким текстом как на следующем скриншоте.
Рамка
А вот как сделать рамку я подробно описывать не буду (но приложу скриншот) - потому что она делается с использованием этих же узлов и приёмов. Рекомендую вам, если повторяете этот урок, постараться подумать и сделать самому и только потом сравнить с моим вариантом.
Для подсветки кнопки логичнее сделать эффект внешнего свечения или обводки (рамки, но не внутрь, а наружу), но элемент Transform внутри которого находится картинка и который ограничевает размер кнопки, обрезает все эффекты, выходящие за его границы. Поэтому для такого придётся включать или отключать ещё какой-то родительский элемент на котором будет этот эффект.