Post image

Bubbly Tap: цветовые темы

В прошлом году я разработал небольшое игровое приложение Bubbly Tap. Сейчас переделываю его на Unity, попутно изменяя дизайн интерфейсов. Игра простая, перенос на новый движок не должен составить большого труда. Тем более, она была разработана с использованием Entity Component System.

Flash версия Bubbly Tap содержит возможность переключаться между светлой и темной цветовыми схемами. В планах добавить больше палитр с возможностью увеличения их количество со временем. Цвета подбирается с помощью простенького, но удобного приложение Coolors.co. (К примеру, светлая тема: https://coolors.co/fffff0-99cc99-636b9e-b5b2ab-bf4e30)

CES реализация

Не хочу сильно углубляться в детали старого алгоритма работы с цветом. Опишу принцип вкратце. Существует компонент Color хранящий информацию о цвете. Сущности с данным компонентом обрабатываются системой ColorSystem, расположенной выше системы рендеринга (RenderSystem) в стеке исполнения. При изменении палитры ColorSystem назначает компоненту новый целевой цвет и постепенно изменяет текущий цвет пока он не станет равным целевому.

Код (ActionScript):

Система RenderSystem берет текущий цвет из Color и применяет его к текстуре.

При переносе на Unity хотелось сохранить гибкость этой реализации.

Первый вариант

После некоторых размышления я пришел к мысли, что подобного можно добиться при помощи ImageEffects, изменяя цвет пикселей с помощью шейдера на этапе постобработки. До прохода результирующим шейдером, игра рисуется в градации серого, где в каналы цвета игровых объектов записывается идентификаторы цветов. В шейдер задается текущая цветовая схема, то есть соотношение идентификаторов к цвету (Например: "MainColor" = 0xFF00FF00). При проходе шейдер извлекает Id из цветового канала и назначает новый цвет пикселю в соответствии с текущей схемой. Таким образом при задании новой цветовой темы шейдер "перекрасит" всю игру в нужные цвета.

Но в данном подходе присутствуют два огромных изъяна. Первый - нет возможности использоваться цвета не записанные в шейдер. Сейчас Bubbly Tap использует схему из пяти цветов. И для корректного отображения иконок выбора цветовой темы (color picker) пришлось бы придумывать способ обойти свой же алгоритм.

Вторая проблема заключается в альфа канале, а именно: при смешении цветов, там где альфа канал меньше 255, итоговый Id цвета буде неправильным и щейдер назначит ошибочный цвет пикселю. Если бы у игры отсутствовали полупрозрачные элементы этот изъян можно было бы игнорировать.

Обе проблемы я обнаружил после того как реализовал работу с щейдером: "странные" цветовые артефакты, особенно на границах игровых объектов, неправильные цвета в color picker.

Конечный вариант

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

Для этого был создан абстрактный компонент ColorBehaviour ответственный за изменения цвета у renderer'а игрового объекта или элемента интерфейса. Подход похожий на старую реализацию, только здесь отсутствуют системы, а весь функционал вынесен непосредственно внутрь компонента. Скрипту задается идентификатор по которому он ищет цвет в палитре игры и назначает его целевым. Update метод трансформирует целевой цвет в текущий пока они не станут равны друг другу. Текущий цвет применяется к rendere'у. Когда текущий цвет соответствует целевому скрипт "выключается", чтобы не потреблять ресурс на бесполезные обновления. Из-за того что rendere'ы у объектов разного типа, пришлось создать несколько наследников ColorBehaviour реализующих метод UpdateColor. (SpriteColorBehaviour, TextColorBehaviour, ImageColorBehaviour etc.)

При изменении темы, глобальный менеджер (ColorManager) проходит по всем элементам которые содержат ColorBehaviour и "говорит" им обновиться, через публичный метод Refresh.

Код (C#):

Так же я написал небольшой класс для Unity Editor (ColorSetterInspector.cs), с помощью которого можно изменять цвет элементов во время выполнения.

Получилась гибкая система контроля палитры для Bubbly Tap. Вот небольшой ролик показывающий переключение схем и изменения цвета элемента из Unity Editor: