Гексы и пиксели: советы по рисованию
Как правильно рисовать шестиугольники для тактических видеоигр и пошаговых стратегий.
Привет! На связи Саша Тюпин. Последние несколько лет я разрабатываю пошаговые стратегиями на гексагональных картах.
В этой статье расскажу как собрать из шестиугольных тайлов нормальную карту с нормальными переходами, да и вообще поделюсь всякими мыслями, техниками, фишечками и прочим.
Речь пойдет прежде всего про 2D и пиксель-арт в частности. Если вы любите 3D и/или текстуры высокого разрешения, то стоит обратить пристальное внимание на туториалы Catlike Coding, там все очень подробно и с кодом объясняется.
Впрочем, про используемые там техники я тоже немного напишу.
Проблематика
Для начала объясню в чем, собственно, сложность и почему для квадратных тайлов есть сотни туториалов, тысячи примеров, специальные инструменты в редакторах и движках, а для гексагональных нет вообще ни черта, хотя про их существование вроде как всем известно.
Проблем тут две:
- Бесшовные текстуры — их сложно рисовать, поскольку тайлы не прямоугольные и нетривиально стыкуются между собой. Нет инструментария в редакторах.
- Переходы между биомами — опять же, сложная стыковка гексов и практически полное отсутствие наработанных практик. Непонятно, как вообще подступиться к задаче.
Первая проблема — бесшовные текстуры
Как обычно рисуется прямоугольный тайл? Создаем спрайт, ставим tiled mode по обеим сторонам и смотрим, чтобы он был красивый и бесшовный. А с гексом что делать?
Здесь есть несколько решений и пара из них даже хорошие.
Забить на бесшовность
Тоже вариант, конечно. Сделать каждый гекс отдельным и хорошо заметным. Путь простой, но скучный. Кроме того, игра становится похожей на настолку, что глубокому погружению не способствует.
Заранее отрисованная карта
Ну тут уж совсем все просто. Рисуется красивая карта, а слой с гексами натягивается поверх нее. Опционально можно раскидать какие-нибудь препятствия. Такое мы видели в Panzer General и в Героях.
Основная проблема решения — ограниченная вариативность карт, но если этого не требуется, то вариант роскошный. Можно делать сколь угодно сложные и красивые задники.
Бесшовные гексы
А может все-таки можно как-то заморочиться и нарисовать бесшовные гексы? Ладно, варианты есть, но все они так себе.
Чудовищная настойчивость
Нарисовал, сохранил, посмотрел в игре. И так сто раз по кругу. Для настоящих самураев. Если игра очень быстро собирается или способна обновлять ресурсы в рантайме (так кроме веба вообще умеет кто-то?), то, в принципе, терпимо.
Плагины и скрипты
Для Aseprite, кажется, ничего нет, но можно написать скрипт. Правда, придется кнопку жать все время, но хоть что-то. Когда-то я даже делал на Node.js скрипт, который следит за файлом и показывает в браузере превью.
В общем, тут только грусть и костыли, человеческих решений нет. Если знаете редактор, который поддерживает гексагональный тайлинг — напишите в комментах.
Математика и искажения
А что если нарисовать прямоугольный тайл, а потом как-то хитро его повернуть, нарезать и превратить в гексагональный? Пара вариантов есть — они описаны в гайде для Battle for Wesnoth, так что повторять их не буду.
Существует еще несколько вариантов натянуть прямоугольную текстуру на гексагональную сетку, например вот эти:
В первом случае нужно 4 разных гекса для создания бесшовности, во втором всего один, но текстура очень часто повторяется.
На мой взгляд этот путь тупиковый, хотя бы потому что есть следующий, и он намного лучше.
Использовать гексы как маску для текстуры
Берем бесшовную текстуру побольше и обрезаем ее в шейдере по маске гекса. Решение современное, красивое и удобное. Требует знания шейдеров на уровне «сложить и перемножить числа».
Делается достаточно просто, выглядит прекрасно. На мой вкус — лучший вариант.
Ок, с бесшовностью вроде разобрались.
Переходы между биомами
Так, а вот это уже намного сложнее. Биомы-то у нас есть, но они все еще выглядят как из настолки. Нужны красивые переходы между ними.
Посмотрим, что мы тут можем сделать.
Не делать ничего
Ну да, это мы уже проходили. Ничего не делай и ничего не будет.
Блендинг
Есть одна текстура, есть другая, давайте мы их сблендим и будем красиво. Основной способ стыковки игр с 3D окружением и/или текстурами высокого разрешения. Может выглядеть очень пристойно, особенно если блендинг нелинейный и дополнен геометрией.
Пустыня мягко перетекает в равнину, а в более резком переходе к траве уже используется другой паттерн — с пятнами. Эффект усиливают геометрия, объединяющая гексы.
Решение это, конечно, хорошее, но для пиксель-арта подходит слабо. Скорее всего получится шумная каша. Я с трудом смог найти пример такого подхода в единственной игре — Emperor of the Fading Suns, где это немного сглажено видимой границей гекса и CRT-монитором.
При этом переходы к воде здесь все еще сделаны нормально.
В наше время такое делать уже, конечно, стыдно.
Переходы от вершин
Я не знаю игр где используется этот паттерн, но я видел его в паре паков, предназначенных для создания карт. В нем переход рисуется от вершины к вершине для каждого их сочетания. Выглядит это так:
На мой вгляд, этот подход состоит целиком из недостатков:
- Полный сет переходов это целых 30 тайлов.
- Все их как-то надо состыковать друг с другом или замаскировать стыки границами гексов.
- Переходы жестко привязаны к биомам.
- Иногда непонятно к какому конкретно биому принадлежит гекс.
В общем, не рекомендую.
Переходы от граней
Перейдем к рабочему решению — сделать кучу стыковочных гексов с вариантами для каждого сочетания граней. Вот так это может выглядеть:
Тут читатель может сказать — ты вообще считать умеешь? Здесь же 64 варианта, до пенсии рисовать можно! А ты еще говорил, что 30 это много. А стыковать все добро как?
На самом деле всё не так страшно. Как можно заметить, переходы по граням все очень похожи друг на друга, а значит их можно собрать из боле мелких элементов и в следующей части статьи я расскажу как. А пока просто будем считать, что они у нас есть.
Поясню как это все работает. Возьмем вот такой кусок местности:
Сначала сортируем биомы по приоритету, от этого будет зависеть то, как они будут перекрывать друг друга. В нашем случае это вода — земля — трава.
Биом с самым низким приоритетом, воду, пропускаем.
От земли делаем переходы ко всем биомам с более низким приоритетом, в данном случае к воде.
Покрасим переходы. Я их просто залью одним цветом, но можно применить ту же текстуру, что используется на гексах (см. выше про маски).
Теперь повторяем все то же самое с травой.
Вот и все. Как можно заметить, переходы к воде смотрятся, мягко говоря, не очень. Ну да, чтобы выглядело хорошо, нужно для воды специальные рисовать. Этот подход применяется в небезызвестной Battle for Wesnoth. Когда-то и там были стремные переходы к воде:
А потом ничего, нарисовали красивые (правда не для всех биомов):
Двойные переходы от граней
Это мой выбор!
Решение похоже на предыдущее, но, если надо, то переходы рисуются с обоих сторон грани — можно одного типа, а можно разные. Это позволяет делать промежуточные биомы, что решает сразу две проблемы.
Во-первых переходы к воде теперь выглядят по-человечески:
Во-вторых, если переход двух биомов друг в друга выглядит странно — ну там снег в лаву или что-то такое — то можно сделать промежуточный биом из обычной землицы:
Бонус-трек: генерация переходов шейдером
Теоретически возможна, практических реализаций я не встречал. Однако, это не значит, что шейдеры бесполезны — с их помощью можно усилить эффектность перехода, например сделать волны и прибой:
Как нарисовать шаблоны переходов
Теперь давайте разберемся как вообще рисовать все это добро. Я делаю это скриптом на JS (не входит в комплект), как и всю подготовку ассетов, но можно и прямо в игре все собирать, просто спрайтов будет больше в несколько раз.
Каждый гекс может примыкать к другому биому любой комбинацией из своих 6 граней. Я помечу каждую из них номером от 0 до 5, начиная с северо-восточной.
Каждая грань находится в одном из двух состояний — примыкает или нет. Таким образом, каждый шаблон можно обозначить числом от 000000 до 111111 в двоичном формате или от 0 до 63 в десятичном. То есть нам нужно сгенерировать 64 шаблона чтобы покрыть все возможные комбинации.
На самом деле, можно все дико вращать и зеркалить и тогда понадобится только 14, но если уж мы делаем все скриптом, то проще подготовить сразу все варианты.
Теперь надо придумать как бы все это разбить на кусочки, повращать и сложить обратно. К счастью, эта работа уже проделана мной.
Если долго вглядываться в гексы, то можно заметить что каждая вершина в переходе может быть открытой (1), то есть граничить только с одной гранью с переходом, или закрытой (2), то есть с двумя.
Это важное наблюдение, которое позволит нам разбить грани на 4 группы:
- A — переход от одной открытой вершины к другой.
- B — переход от закрытой вершины к открытой по часовой стрелке.
- C — переход от открытой вершины к закрытой по часовой стрелке.
- D — переход от одной закрытой вершины к другой.
Нарисуем для каждой группы грани 0, 1 и 2. Остальные зеркалим. Можно только 0 и 1, но я считаю, что если уж что-то зеркалить, то нужно делать это по обеим осям сразу, иначе очень заметны повторения. Кроме того, при такой разбивке отзеркаленные грани никогда не буду примыкать друг к другу.
Помимо прочего, я обрезал кусочки шаблонов таким образом, чтобы они не перекрывали друг друга при сборке — резать надо ту половину, которая примыкает к закрытой вершине. Поэтому кусочки из группы D такие куцые.
Теперь собираем шаблоны. Алгоритм простой — берём числа от 0 до 63, переводим в бинарный формат и пробегаемся по всем граням. Для каждой из них смотрим на соседей и выбираем группу, а потом и номер грани. Для 3, 4 и 5 зеркалим по обоим осям 0, 1 и 2 соотвественно. Иногда двигаем кусочек шаблона куда надо.
Теперь неплохо бы проверить как всё это стыкуется. Я собрал для теста вот такую вот загогулину, которая, по идее, включает в себя все возможные стыки:
В качестве финального штриха я подрезал и повернул некоторые кусочки, чтобы часть стыков была видна сразу и вся конструкция занимала меньше места.
Теперь огонь! Можно пользоваться.
Заключение
Такие вот мысли про гексы. Статья не претендует на какой-то ультимативный гайд по теме, скорее на точку отсчета для своих мыслей. Про то как рисовать обычные тайлы материала миллионы, а вот про гексы совсем нет. Пусть будет.
Этой статьи не было бы, если я не разрабатывал свою пошаговую 4x-стратегию на гексагональной карте. Она называется «Луна» и почитать про нее можно в обзорной статье. Девлог я веду в Телеграме и Твитере.
Будьте клевыми, играйте в стратегии! До встречи.