Cocos2d-x — Работа со спрайтами
Предисловие
Эта статья является второй, из серии переводов документации к игровому движку Cocos2d-x. Если вы не видели первую часть перевода, то советую сначала ознакомится с ней:
Cocos2d-x — Основные понятия
А теперь продолжим!
Что такое спрайт
Создание спрайтов
Существуют различные способы создания спрайтов, зависящие от того что вам необходимо выполнить. Вы можете создать спрайт, используя изображения различных графических форматов, включая: PNG, JPEG, TIFF и другие. Давайте рассмотрим некоторые методы создания и поговорим о каждом из них.
Создание простого спрайта
Спрайт может быть создан путем указания файла изображения.
Код выше создает спрайт, используя изображение mysprite.png. В результате, созданный спрайт использует целое изображение. Он имеет те же размеры, что и mysprite.png. Если файл изображения 200 x 200 то результирующий спрайт тоже будет 200 x 200.
Создание спрайта с использованием Rect (прямоугольника)
В предыдущем примере, созданный спрайт имел тот же размер, что оригинальное изображение. Если вы хотите создать спрайт использующий только часть файла изображения, вы можете сделать это путем указания прямоугольного участка – Rect.
Rect имеет 4 значения: origin x, origin y, width и height.
Rect берет левый верхний угол за начало координат. Это противоположно тому принципу, что мы использовали, когда устанавливали позицию на экране, отчитывая координаты от левого нижнего угла. Таким образом, результирующий спрайт – только часть исходного файла изображения. В этом случае, размер спрайта 40 x 40 начиная от левого верхнего угла.
Если вы не зададите Rect, Cocos2d-x автоматически будет использовать полную высоту и ширину заданного изображения. Взгляните на код ниже. Если вы используете изображение с размерами 200 x 200, то следующие два выражения будут иметь одинаковые результаты.
Создание спрайта из текстурного атласа (Sprite Sheet)
Sprite sheet – это способ объединения спрайтов в один файл. Использование sprite sheet помогает добиться лучшей производительности, путем пакетной обработки вызовов рисования. Они могут также сохранить дисковую- и видео-память, если упаковать спрайты более эффективно (обычно требуются специальные инструменты). Вы прочитаете больше об этом в продвинутой главе, но это только один из многих стандартных методов повышения производительности игр.
При использовании sprite sheet, он сначала загружается в SpriteFrameCache. SpriteFrameCache – это класс кеширования, который сохраняет объекты SpriteFrame, для быстрого доступа к ним. SpriteFrame загружается один раз и сохраняется в SpriteFrameCache.
Вот пример sprite sheet:
Давайте рассмотрим подробнее, что происходит:
Как вы можете видеть, sprite sheet объединяет все спрайты в один файл и минимизирует лишнее пространство.
Загрузка Sprite Sheet
Вероятнее всего, вы будете осуществлять загрузку в AppDelegate:
Теперь, когда мы имеем текстурный атлас загруженный в SpriteFrameCache, мы можем создать спрайт.
Создание спрайта из SpriteFrameCache
Это создание спрайта, путем вытягивания его из SpriteFrameCache.
Создание спрайта из SpriteFrame
Еще один способ создать такой же спрайт – получить SpriteFrame из SpriteFrameCache, и затем создать спрайт при помощи SpriteFrame. Пример:
Инструменты для создания Sprite Sheets
Создание sprite sheet вручную – утомительный процесс. К счастью, есть инструменты, которые могут генерировать их автоматически. Эти инструменты предлагают множество возможностей для максимальной оптимизации ваших спрайтов!
Здесь представлено несколько инструментов:
Манипуляции со спрайтами
После создания спрайта, вы получите доступ к разнообразным его свойствам, которыми можно манипулировать.
Опорная точка и позиция
Опорная точка (Anchor Point) – это точка, которую вы задаете, чтобы указать, какая часть спрайта будет использоваться, при установке его координат. Опорная точка влияет только на свойства связанные с трансформацией. Они включают: scale, rotation, skew. И не включают: color и opacity. Опорная точка использует систему координат от нижнего левого угла. Учитывайте это, при выполнении своих расчетов. По умолчанию, все Node объекты имеют стандартную опорную точку (0.5, 0.5).
Задать опорную точку просто:
Чтобы представить это визуально:
Свойства спрайтов, на которые влияет опорная точка
Использование опорной точки влияет только на свойства связанные с трансформированием. Такие как: scale, rotation, skew.
Position
Опорная точка влияет на позицию спрайта, поскольку именно эта точка используется в качестве основной при позиционировании. Давайте посмотрим, как это происходит. Обратите внимание на цветную линию, и то где находятся спрайты относительно ее. Важно отметить, что такой эффект был получен, лишь путем изменения опорной точки. Мы не использовали setPosition() для достижения этого:
Позицию спрайта можно также задать методом setPosition().
Rotation
Изменяет вращение спрайта, на положительное или отрицательное число градусов. Положительные значения поворачивают спрайт по часовой стрелке, в то время как отрицательные поворачивают против часовой стрелки. Стандартное значение – 0.0
Scale
Изменяет масштаб спрайта, либо по каждой оси отдельно, либо равномерно по обеим. Стандартное значение – 1.0
Изменяет наклон спрайта, либо отдельно по осям x и y, либо равномерно для всех. Стандартное значение – 0.0
Свойства спрайта, на которые не влияет опорная точка
Существует несколько свойств объекта Sprite, на которые не влияет опорная точка. Почему? Потому что они изменяют только внешний вид, подобно свойствам color и opacity.
Color
Изменяет цвет спрайта. Это делается при помощи Color3B. Мы еще не сталкивались с Color3B, но это просто объект, представляющий собой RGB цвет. RGB цвет включает в себя 3 значения (Red, Green, Blue), от 0 до 255. Cocos2d-x также предоставляет предопределенные цвета, из которых вы можете выбрать. Использование их будет немного быстрее, поскольку они уже определены заранее. Вот некоторые примеры:
Opacity
Изменяет непрозрачность спрайта на заданное значение. Это свойство принимает значения от 0 до 255, где 255 – полная не прозрачность, а 0 – абсолютная невидимость. Стандартное значение 255 (полная видимость).
Полигональные спрайты
Полигональный спрайт это тоже спрайт, который используется для вывода 2d изображения. Однако, в отличие от нормального спрайта, который является прямоугольником, состоящим из двух треугольников, полигональный спрайт состоит из серии треугольников.
Зачем использовать полигональный спрайт?
Ответ прост — производительность!
Существует много технических терминов о скорости пиксельного заполнения, которые мы могли сюда вывалить, но вам просто нужно понять, что PolygonSprite рисуется на основе формы вашего спрайта, а не прямоугольника с избыточной площадью. Этот способ прорисовки, позволяет сэкономить на ненужной работе. Рассмотрим пример:
Заметили различия между левой и правой версиями?
Слева, типичный Sprite, который прорисовывается, с использованием двух треугольников.
Справа, PolygonSprite, рисующийся большим количеством маленьких треугольников.
Стоит ли идти на такой компромисс, чисто по соображениям производительности, зависит от ряда факторов (форма/детализация спрайта, размер, количество нарисованного на экране, и так далее), но в основном, вершины дешевле пикселей на современных графических процессорах.
AutoPolygon
AutoPolygon – это вспомогательный класс. Его цель – создавать 2d полигональную сетку на основе изображения.
Существуют функции для каждого шага обработки этого процесса, от определения всех точек, до триангуляции. Результат может быть передан в функцию create объекта sprite, для создания PolygonSprite. Пример:
Разработка игр под NES на C. Главы 4-6. Рисуем персонажа
В этой части рассмотрим работу с графикой: фон и спрайты персонажей.
>>
Что такое V-blank?
PPU — графический процессор — может или отправлять сигнал в телевизор, или получать информацию от процессора, но не одновременно. Так что единственное время для пересылки это V-blank, период кадрового гасящего импульса.
90% времени PPU отправляет пиксели в видеовыход, строка за строкой слева направо и сверху вниз. Внизу экрана делается пауза, и все повторяется снова. Это происходит 60 раз в секунду. Пауза после отрисовки кадра и есть V-blank. Это весьма короткий промежуток времени. В него реально вложить обновление 2-4 столбцов фоновых тайлов и обновление спрайтов. Обновление фона особенно критично для игр с прокруткой.
Сейчас мы напишем программу, которая будет выводить “HELLO WORLD” по 1 букве каждые 30 кадров. После вывода всей фразы очистим экран, и повторим все по кругу.
Обратите внимание на фрагмент
в файле reset.s. Это код обработчика немаскируемого прерывания, который фактически реализует счетчик кадров в глобальной переменной. Каждый кадр выставляет флаг NMI_flag, и в случае если прошло 30 кадров (0.5 секунды), выводится спрайт очередной буквы. Вся логика реализована в main().
В идеале, надо ждать V-blank перед вызовом All_On(), иначе один кадр после него будет искажен, и экран будет мерцать. В этом примере этот эффект незаметен, потому что All_On() вызывается единственный раз при старте приставки, экран в это время черный, и искажение незаметно.
Немного цвета
Теперь можно раскрасить то что получилось.
Таким образом можно одновременно отрисовать 25 цветов из 50 возможных.
Для фона палитра определяется для блока из 2х2 тайлов, размером 16х16 точек. Для этой разбивки удобно использовать Nes Screen Tool. Большинство игр строит фон именно из таких счетверенных метатайлов.
Здесь одна буква соответствует одному тайлу, малый квадрат — метатайл 2х2.
То есть чтобы поменять палитру правого нижнего квадранта на первую из 4 возможных, надо поменять два старших бита атрибута на 01: 01хххххх.
Я добавил к прошлому примеру палитры, так что буквы теперь разноцветные. Палитры вынесены в отдельный файл и импортируются через #include, а переменные определены в нулевой странице памяти через #pragma — просто для демонстрации этой фичи. Нулевая страница работает быстрее, но 10-20 переменных там используется для внутренних нужд компилятора. Так что надо рассчитывать где-то на 235 доступных байт.
Вот полезная шпаргалка по адресам таблицы атрибутов и ее привязке к экранным координатам:
Экран шириной 256 точек, каждая клетка таблицы соответствует квадрату 32х32
Спрайты
Спрайт — это картинка 8х8, которая может перемещаться по экрану. Есть хитрый способ использовать спрайты 8х16, но мы так делать не будем. Почти все персонажи игр состоят из спрайтов. Хотя в некоторых случаях нужно отрисовывать их фоновыми тайлами из-за ограничений на количество спрайтов, такое используется для финальных боссов в некоторых играх.
8х8 точек это очень мало, поэтому придется собирать персонажа из нескольких спрайтов: маленького Марио из 2х2, а большого из 2х4.
Надо помнить об ограничениях. Поддерживается не больше 64 спрайтов, и не более 8 на одной строке экрана. При превышении лимита будут отрисованы только спрайты с большим приоритетом. Если менять приоритет спрайта между кадрами, он будет мигать. Этот способ часто используется в играх.
PPU хранит информацию о спрайтах в таблице OAM. Ее размер 256 байт: по 4 байта на каждый из 64 возможных спрайтов. Если накладываются два спрайта с одинаковым приоритетом, то спрайт с меньшим номером отрисовывается поверх. Если на одной строке экрана будет больше 8 спрайтов, то отрисуются только 8 с меньшими номерами.
Таблица OAM хранит такие атрибуты:
В нашем примере мы сделаем метаспрайт из 4 спрайтов и добавим анимацию.
Надо помнить, что спрайты отрисовываются на 1 точку ниже от ожидаемой координаты. На картинке с Марио вверху поста видно, что он на 1 пиксель ушел в пол.
Есть немного улучшенная версия, где персонаж поворачивается при движении по квадрату.
Основы пиксельарта (Часть 1)
Пиксельарт, также известный как дот-арт в Японии, это вид цифрового искусства, где рисование происходит на пиксельном уровне. В основном он ассоциируется с графикой игр 80-90 годов, в которых художники преодолевали технические ограничения (небольшое количество памяти и маленькое разрешение), создавая все более захватывающие картины.
Порог вхождения в пиксельарт довольно низкий, по сравнению с традиционным рисунком и 3D графикой, позволяя инди разработчикам воплощать свои идеи в жизнь. Но это никоим образом не означает, что закончить игру с ним будет легко. Я видел много пиксельарт проектов на кикстартере, которые думали, что управятся с игрой за год, когда в реальности нужно было около шести лет. Пиксельарт на том уровне, который хотят видеть люди требует достаточно много времени и усилий, есть лишь пару путей, позволяющих ускорить этот процесс.
Работая с 3D моделью ты, по крайней мере, можешь крутить ее, деформировать, перемещать её конечности, копировать анимацию с одной модели на другую и т.д, чего не скажешь о пиксельарте. Профессиональный пиксельарт почти всегда подразумевает под собой большое количество кропотливого размещения пикселей на каждом кадре анимации.
Как говорится “Кто предупрежден, тот вооружен!”, а теперь о моем стиле: по большей мере я использую пиксельарт для своих игр, они же и воодушевляют меня продолжать заниматься этим. Если быть точным, то я фанат Famicon(NES), 16 битных консолей и аркадных автоматов 90ых годов.
Мои любимые игры этой эры имели пиксельарт, который нельзя описать иначе как насыщенный, дерзкий и чёткий. но не настолько, чтобы быть чопорным или минималистичным. Это стиль, который я взял за основу своего, но вы можете легко использовать техники, применяемые в этом туториале для чего-то совсем другого. Смотрите на художников, которые вам нравятся и делайте пиксельарт, какой вашей душе угодно!
Самыми базовыми инструментами для занятия пиксельартом являются лупа и карандаш. Также будут полезными линия, фигуры, выделение и заливка цветом. Есть большое количество как платных, так и бесплатных программ, в которых имеются данные инструменты. Я расскажу о самых популярных из них (включая те, которые использую сам).
Если у вас Windows, вы можете использовать Paint, несмотря на скудность программы, в ней имеются все нужные инструменты, чтобы заниматься пиксельартом.
На удивление неплохой редактор, которым вы можете пользоваться прямо через ваш браузер. Может производить экспорт как в png и gif, так и сохранять спрайты в браузере. Неплохой способ начать заниматься пиксельартом.
Самый популярный редактор на данный момент. Содержит большое количество полезных функций и инструментов, постоянно обновляется, доступен как на Windows и Mac, так и на Linux. К тому же вы можете пользоваться программой бесплатно, скомпилировав её исходный код. Если вы серьёзно хотите заниматься пиксельартом и ещё не выбрали себе редактор, то Aseprite будет неплохим вариантом.
Так как Photoshop требует ежемесячную плату и не приспособлен для пиксельарта, я не рекомендую его, если только вы уже не используете его. Несмотря на выше сказанное, его вполне можно использовать для статических спрайтов, но он достаточно громоздкий по сравнению с GraphicsGale или Aseprite.
Я настоятельно рекомендую пользоваться графическим планшетом для любого вида иллюстраций, чтобы предотвратить заболевания повторяющейся длительной нагрузки на запястье (туннельный синдром). Такие заболевания намного легче предотвратить, чем вылечить. Когда появляется боль, вы уже обречены ( мои дни рисования мышкой, сделали невозможным играть в игры с быстрым нажатием кнопок). Так, что позаботьтесь о себе пока не поздно – это того стоит! В данный момент я использую маленький Wacom Intuous Pro.
Если у вас нет возможности купить планшет, по крайней мере, возьмите лучезапястный бандаж. Я использую от компании Mueller Green Fitted Wrist Brace. У других брендов бандажи были либо слишком неудобными, либо недостаточно эффективными.
Давайте приступим к делу! Мы начнем со спрайта персонажа размером 96×96 пикселей. Я решил нарисовать орка, но вы вправе выбрать что-то другое. Конечный вариант орка находится на скриншоте Final Fight, который вы можете увидеть выше, для того, чтобы вы понимали масштаб спрайта– он большой для большинства ретро игр (оригинальный скриншот имеет размер 384×224 пикселя).
Причина по которой мы начинаем с такого большого спрайта заключается в том, что мне будет легче показать техники пиксельарта именно на нем. К тому же, создание больших спрайтов очень похоже на обычное рисование, которое может быть вам знакомо. После того, как мы изучим базовые техники можно будет уменьшить размер спрайта.
Пиксельарт характеризуется своими ограничениями. Каждый пиксель имеет большое значение, по сравнению с другими видами иллюстраций, также как и цвета, количество которых должно быть ограничено.
Так, что да, выбор палитры цветов очень важен и помогает обозначить ваш стиль. Но для начинающих пиксельарт художников лучшим вариантом будет отложить теорию насчёт цветов в сторону и просто выбрать одну из существующих палитр ( или несколько рандомных цветов), чтобы начать рисовать. Одно из преимуществ пиксельарта заключается в том, что вы в любой момент можете поменять палитру цветов.
Именно для этого туториала я буду использовать палитру из 32 цветов, созданную специально для UFO 50. Палитры из 32 и 16 цветов используются достаточно часто. Данная палитра была создана для выдуманной консоли, которая бы находилась где-то между Famicon и PC Engine. Можете спокойно взять эту палитру и двигаться дальше (или нет! Это не столь важно).
Мы начнем рисовать наш спрайт с наброска карандашом, также как если бы мы рисовали на бумаге. Опираясь на свой опыт, могу сказать, что неплохие пиксельарт художники достаточно хороши в обычном рисовании и наоборот. Так что никогда не помешает улучшить свои навыки рисования.
Дальше мы должны убрать лишние пиксели и сделать все линии толщиной в один пиксель. Но какие пиксели являются лишними? – для того, чтобы ответить на данный вопрос, нам нужно познакомиться с таким понятием как зазубрины.
Нам нужно научиться делать два вида линий: прямые и закруглённые. На бумаге все будет зависеть от контроля мышц, но мы работаем с маленькими цветными блоками, что создает свои трудности.
Для того, чтобы делать хорошие линии, нужно свести к минимуму количество зазубрин: маленьких пикселей или группы пикселей, которые нарушают последовательность линии. Так как в пиксельарте каждый пиксель имеет большое значение, пару зазубрин могут испортить весь спрайт. Представьте, что вы рисуете линию на кусочке бумаги и кто-то внезапно стукает по столу, получившаяся у вас загогулина является тем же, что и зазубрины в пиксельарте.
Модульные спрайтовые персонажи и их анимация
Эта запись девлога целиком посвящена моей системе анимации персонажей, она наполнена полезными советами и фрагментами кода.
За последние два месяца я создал целых 9 новых действий игрока (такие забавные вещи как блокировка щитом, уворачивание в прыжке и оружие), 17 новых носимых предметов, 3 набора брони (пластинчатый, шёлковый и кожаный) и 6 видов причёсок. Также я завершил создавать всю автоматизацию и инструменты, поэтому всё уже используется в игре. В статье я расскажу, как этого добился!
Надеюсь, эта информация окажется полезной и докажет, что необязательно быть гением, чтобы самостоятельно создать подобные инструменты/автоматизацию.
Краткое описание
Изначально я хотел проверить, можно ли совместить наложенные друг на друга спрайты с синхронизованными аниматорами для создания модульного персонажа с заменяемыми причёсками, снаряжением и носимыми предметами. Можно ли объединить нарисованную вручную пиксельную анимацию с по-настоящему настраиваемым персонажем.
Разумеется, такие функции активно используются в 3D- и 2D-играх с пререндеренными спрайтами или в 2D-играх со скелетной анимацией, но насколько я знаю, существует не так много игр, совмещающих созданную вручную анимацию и модульных персонажей (обычно потому, что процесс оказывается слишком монотонным).
Я раскопал этот древний GIF моего первого месяца работы с Unity. На самом деле этот модульный спрайт оказался одним из первых моих экспериментов в разработке игр!
Я создал прототип при помощи системы анимаций Unity, а затем для проверки концепции добавил одну рубашку, одну пару штанов, одну причёску и три предмета. Для этого потребовалось 26 отдельных анимаций.
В то время я создавал всю свою анимацию в Photoshop и не заморачивался автоматизацией процесса, поэтому он был очень скучным. Потом я подумал: «Так, основная идея сработала, позже я добавлю новые анимации и снаряжение». Оказалось, что «потом» — это несколько лет спустя.
В марте этого года я нарисовал дизайн большого количества брони (см. мой предыдущий пост), и заметил, как этот процесс можно сделать более удобным. Я продолжал откладывать реализацию, потому что даже при наличии автоматизации нервничал, что ничего не получится.
Я ожидал, что придётся отказаться от кастомизации персонажа и создать единственного главного героя, как в большинстве игр с ручной анимацией. Но у меня был план действий, и настало время проверить, смогу ли я победить этого монстра!
Спойлер: всё получилось замечательно. Ниже я раскрою свои ***секреты***
Модульная система спрайтов
I. Познай свои границы
Предварительно я провёл много тестов арта и контроля времени, чтобы выяснить, сколько может занять такая работа, и будет ли достижим для меня подобный уровень качества.
Я придумал численную оценку для каждой анимации и отказался от всего с плохими показателями. Изначально я планировал создать 6 наборов брони, но быстро осознал, что это перебор, и выбросил три типа.
Аспект отслеживания времени оказался очень важным, и я крайне рекомендую использовать его, чтобы отвечать на вопросы типа: «Сколько врагов могу я позволить себе создать в игре?». Всего после нескольких тестов мне удалось экстраполировать достаточно точную оценку. При дальнейшей работе над анимациями я продолжил следить за временем и пересматривать мои ожидания.
Поделюсь копией моего журнала работы за последние два месяца. Учтите, что это время идёт в добавок к моей обычной работе, где я провожу по 30 часов в неделю:
II. Смена палитры ради светлого будущего
С умом используя цвета в дизайне спрайтов, можно отрисовать один спрайт и создать множество различных вариаций при помощи смены палитры. Можно менять не только цвета, но и создавать различные включаемые и отключаемые элементы (например, заменой цветов на прозрачность).
Каждый набор брони имеет 3 вариации, а смешивая верхние и нижние части, можно получить множество комбинаций. Я планирую реализовать систему, в которой можно собрать один набор брони для внешнего вида персонажа, а другой — для его характеристик (как в Terraria).
В процессе работы меня приятно удивляли обнаруживаемые любопытные комбинации. Если соединить пластинчатый верх с шёлковым низом, то можно получить нечто в стиле боевого мага.
Лучше всего реализовывать смену палитр, используя в спрайте цвета, кодирующие значение, чтобы в дальнейшем можно было брать их для поиска настоящего цвета из палитры. Я знесь немного упрощаю, так что вот видео, с которого можно начать:
Я не буду объяснять всё в подробностях, а вместо этого расскажу о способах реализации этой техники в Unity, и об их плюсах и минусах.
1. Текстура поиска для каждой палитры
Это наилучшая стратегия для создания вариаций врагов, фонов и всего того, где множество спрайтов иеет одинаковую палитру/материал. Различные материалы нельзя сгруппировать в батчи, даже если они используют одинаковый спрайт/атлас. Работа с текстурами довольно мучительна, но палитры можно изменять в реальном времени, заменяя материалы, с помощью SpriteRenderer.sharedMaterial.SetTexture или MaterialPropertyBlock, если вам нужны разные палитры для каждого экземпляра материала. Вот пример фрагментной функции шейдера:
2. Массив цветов
Я остановился на этом решении, потому что мне нужно было заменять палитры каждый раз, когда меняется внешний вид персонажа (например, при надевании предметов), и создавать некоторые палитры динамически (чтобы отобразить выбранные игроком цвета волос и кожи). Мне показалось, что во время выполнения и в редакторе для этих целей гораздо проще будет работать с массивами.
Я представил свои палитры как тип ScriptableObject и использовал для их редактирования инструмент MonoBehaviour. Проработав долгое время над редактированием палитр в процессе создания анимаций в Aseprite, я понял, какие инструменты мне требуются и писал эти скрипты соответствующим образом. Если вы хотите написать собственный инструмент для редактирования палитр, то вот какие функции я обязательно рекомендую реализовать:
— Обновление палитр на различных материалах при редактировании цветов для отображения изменений в реальном времени.
— Присваивание названий и изменение порядка цветов в палитре (используйте поле для хранения индекса цвета, а не его порядка в массиве).
— Выбор и редактирование нескольких цветов за раз. (Совет: поля Color в Unity можно копипастить: просто нажмите на один цвет, скопируйте, нажмите на другой цвет, вставьте — теперь они одинаковы!)
— Применение цвета оверлея ко всей палитре
— Запись палитры в текстуру
3. Единая текстура поиска для всех палитр
Если вы хотите переключать палитры на лету, но в то же время вам необходим батчинг для снижения количества вызовов отрисовки, то можно использовать эту технику. Она может оказаться полезной для мобильных платформ, но использовать её довольно неудобно.
Во-первых, нужно будет упаковать все палитры в одну большую текстуру. Затем вы используете цвет, заданный в компоненте SpriteRenderer (AKA цвет вершины) для определения строки, которую надо считать из текстуры палитры в шейдер. То есть палитра этого спрайта управляется через SpriteRenderer.color. Цвет вершины — это единственное свойство SpriteRenderer, которое можно менять без нарушения батчинга (при условии, что все материалы одинаковы).
В большинстве случаев лучше всего использовать для управления индексом альфа-канал, потому что вам скорее всего не понадобится куча спрайтов с различной прозрачностью.
Чудеса замены палитр и слоёв спрайтов. Так много комбинаций.
III. Автоматизируйте всё и применяйте подходящие инструменты
Для реализации этой функции автоматизация была совершенно необходимой, потому что в результате у меня получилось около 300 анимаций и тысячи спрайтов.
Первым моим шагом стало создание экспортёра для Aseprite, чтобы управлять моей безумной схемой слоёв спрайтов при помощи удобного интерфейса командной строки. Это просто скрипт на perl, который обходит все слои и метки в моём файле Aseprite и эспортирует изображения в определённой структуре каталогов и имён, чтобы я смог в дальнейшем их считывать.
На стороне Unity серьёзные проблемы у меня возникли в двух местах: в загрузке/нарезке спрайтшита и в построении клипа анимации. Мне бы очень помог понятный пример, поэтому вот фрагмент кода из моего импортёра, чтобы вы не так мучились:
Если вы этого ещё не делали, то поверьте — начать создавать собственные инструменты очень легко. Самый простой трюк заключается в размещении в сцене GameObject с привязанным к нему MonoBehaviour, которое имеет атрибут [ExecuteInEditMode]. Добавьте кнопку, и вы готовы к бою! Помните, что ваши личные инструменты не обязаны выглядеть хорошо, они могут быть чисто утилитарными.
При работе со спрайтами автоматизировать стандартные задачи довольно легко (например, создание текстур палитр или пакетную замену цветов в нескольких файлах спрайтов). Вот пример, с которого можно начать учиться изменению своих спрайтов.
Как я перерос возможности Mecanim: жалоба
Со временем прототип системы модульных спрайтов, который я создал с помощью Mecanim, стал самой большой проблемой при апгрейде Unity, потому что API постоянно сильно менялся и был плохо задокументирован. В случае простого конечного автомата было бы разумно иметь возможность запрашивать состояния каждого клипа или менять клипы во время выполнения. Но нет! Из соображений производительности Unity запекает клипы в их состояния и заставляет нас использовать для их смены неуклюжую систему переопределений.
Сам по себе Mecanim не такая уж плохая система, но мне кажется, что ему не удаётся реализовать свою основную заявленную особенность — простоту. Идея разработчиков заключалась в том, чтобы заменить то, что казалось сложными и мучительным (скриптинг) чем-то простым (визуальным конечным автоматом). Однако:
— Любой нетривиальный конечный автомат быстро превращается в дикую паутину узлов и соединений, логика которой разбросала по разным слоям.
— Простым случаям использования мешают обобщённые требования системы. Чтобы проиграть одну-две анимации, вам нужно создавать новый контроллер и назначать состояния/переходы. Разумеется, присутствует и излишняя трата ресурсов.
— Забавно, что в результате вам всё равно приходится писать код, ведь чтобы конечный автомат делал что-то интересное, нужен скрипт, вызывающий Animator.SetBool и подобные ему методы.
— Для многократного использования конечного автомата с другими клипами нужно дублировать его и заменять клипы вручную. В дальнейшем вам придётся вносить изменения в нескольких местах.
— Если вы хотите изменять то, что находится в состоянии во время выполнения, то у вас проблемы. Решением будет или плохой API, или безумный граф с одним узлом для каждой возможной анимации.
Рассказ о том, как разработчики Firewatch попали в ад визуального скриптинга. Самое забавное в том, что когда докладчик показывает наиболее простые примеры, они всё равно выглядят безумно. Зрители в буквальном смысле стонут на 12:41. Добавьте огромные затраты на обслуживание, и вы поймёте, почему я сильно не люблю эту систему.
Многие из этих проблем даже не вина разработчиков Mecanim, а просто естественный результат несовместимых идей: нельзя создать общую и в то же время простую систему, а описывать логику при помощи изображений сложнее, чем просто словами/символами (кто-нибудь помнит флоучарты UML?). Я вспомнил фрагмент из доклада Зака Макклендона на Practice NYC 2018, и, если найдётся время, рекомендую вам посмотреть видео целиком!
Однако я разобрался. Визуальный скриптинг всегда порицается агрессивными «пиши свой собственный движок» нердами, не понимающими потребностей художника. К тому же нельзя отрицать, что бОльшая часть кода выглядит как непостижимый технический жаргон.
Если вы уже немного программист и делаете игры со спрайтами, то вам возможно стоит подумать дважды. Когда я начинал, то меня был уверен, что никогда не смогу написать что-то связанное с движком лучше, чем разработчики Unity.