OVIVO продолжают рассказывать о своём опыте разработки игр. Статья в первую очередь будет интересна новичкам в геймдеве и тем, кто уже освоил азы работы с Unity. Слово автору. :)
1. От хакатона до собственной студии разработки игр: часть 1, часть 2.
2. Unity3D и векторная графика.
3. Как общаться с игроком без слов.
4. Как выйти из хаоса и начать работать.
Привет, Хабр! Я занимаюсь программной частью в игре OVIVO и хочу поделиться с сообществом своим опытом внедрения векторной графики в Unity. Ниже я кратко опишу структуру SVG-файлов, расскажу о своих пробах и ошибках, а также продемонстрирую результат.
Имеем пустое пространство, заполненное белым цветом. Добавляем туда черные кляксы. Поскольку эти кляксы — интерактивный элемент 2D-игры, то будем звать их платформами. Также есть круглый персонаж, способный перемещаться по платформам и перескакивать из одного цвета в другой. Когда игрок находится в белом мире, на него действует гравитация, направленная вниз. Если же он очутился внутри черной платформы, то его тянет вверх. Перемещаясь между двумя мирами, у игрока сохраняется импульс, благодаря чему он может преодолевать препятствия, требующие определенной прыгучести. Так звучит краткое описание базовой механики нашей игры.
Но сегодня поговорим не о механике, а об этих черных кляксах. Поскольку платформы имеют относительно несложную форму и окрашены всего в один цвет, то для их создания идеальным инструментом будет любой векторный графический редактор. До моего прихода в команду всю графику ребята растрировали и оперировали громоздкими спрайтами в среде Unity. А громоздкими они были оттого, что требовалась высокая четкость картинки, следовательно, на разрешении спрайтов экономить нельзя было. Месяца два мы мучались с вопросом об использовании растра. Все методы перепробовали, но либо размер билда переваливал за один гигабайт, либо мобильные системы не выдерживали такого потребления ресурсов. И однажды мне стало интересно, что же такое векторная графика и с чем ее едят. В нашем случае все оказалось предельно просто: используются лишь кривые Безье и некоторые геометрические примитивы. А самым замечательным открытием для меня был формат SVG, в который без проблем можно было экспортировать всю нашу графику. Я очень обрадовался, узнав, что это всего лишь XML-документ.
Перед парсингом SVG необходимо было четко определиться с тем, как мы это все будем отображать в Unity. Самое очевидное решение: использовать сетку (Mesh). Поскольку наши платформы являются замкнутыми фигурами, то их контур можно представить в виде последовательно соединенных между собой точек, а благодаря триангуляции создать подходящий набор полигонов, которые будут служить заливкой для этой фигуры.
Каждую платформу мы также обертываем эдж-коллайдером (EdgeCollider2D — один из типов коллайдеров в Unity3D, представляющий собой ломаную линию). Это нужно для определения пересечения персонажем контура платформы, чтобы в нужный момент менять вектор гравитации. Таким образом мы должны убить двух зайцев одним выстрелом: рисовать графику и, основываясь на тех же данных, дополнять платформу физическими характеристиками.
Подробно рассказывать о структуре и всех возможностях SVG я не буду, однако остановлюсь на одном из его элементов — path. Ведь именно здесь хранятся почти все интересующие нас данные. Обратить внимание нужно на атрибут d, в котором записана информация о всех последовательно соединенных линиях, образующих единую фигуру.
Как видно из примера, набор чисел можно превратить в гладкую фигуру.
Забегая наперед скажу, что лишь в одном атрибуте d единственного path можно рисовать неограниченное количество фигур, будь то замкнутые контуры или произвольные линии, но об этом позже. Данные из d условно можно разделить на блоки с контрольными точками для каждой кривой.
В работе с каждой платформой мы можем задать ей точность построения контура. Например, если установлено число 8, то каждая кривая будет разбита на 8 отрезков. В итоге, зная тип кривой и владея всеми ее контрольными точками, мы с легкостью можем строить ломаную линию, которая при высокой точности будет выглядеть аналогично гладкой кривой.
В path поддерживаются несколько типов кривых Безье и прямых линий, поэтому необходимо было подстраивать инструмент под возможность парсить каждый тип. Самые неприятные моменты возникали с форматом записи данных в атрибуте d. На протяжении всей разработки игры ребята постоянно сталкивались с тем, что те или иные векторные спрайты просто не строились, а мой инструмент выдавал ошибки. Как оказалось, разные графические редакторы (в том числе и разные версии одной марки) генерировали код SVG зачастую по-разному. Например, один и тот же путь можно записать различными способами: используя в некоторых местах верхний регистр или нижний, пробел или новую строку. Приходилось вручную ковырять каждый такой спрайт и дописывать свой парсер под нужды художников. При том, что иногда редакторы генерировали удобочитаемый код, а иногда все лепили в одну строку. Дело со временем усложнялось еще и тем, что необходимо было строить множество платформ, записанных в один SVG-файл. Потом и вовсе оказалось, что все фигуры можно засунуть в один элемент path. На самом деле, было и множество других сюрпризов, которые уже не вспомнить. Тогда, конечно, все писалось на скорую руку, но на будущее я для себя усвоил урок: сначала детальное изучение спецификации, потом код.
В большинстве случаев точность у нас была фиксированной, однако не всегда итоговая картинка соответствовала ожиданиям. Чем выше степень кривизны линии, тем на большее количество отрезков ее нужно разбить для создания эффекта гладкости. В качестве тестовой фичи я добавил возможность автоопределения точности в зависимости от кривизны линии, но впоследствии мы перешли на ручную настройку точности контура.
Иногда необходимо было подправить совсем небольшой кусочек сетки, но повышать точность всей фигуры целиком не хотелось. Поскольку объекты в сцене никак не привязаны к каким-либо ассетам в проекте, то в каждой платформе я на всякий случай хранил XML-текст по которому можно было распарсить графику. Таким образом, имея возможность подтянуть любой кусок платформы в виде кривой, мы теоретически могли править сетку и коллайдер только в конкретных промежутках. Хотя и пришлось слегка нарушить автоматизм в просчете точек, но в итоге мы обзавелись небольшой утилитой, позволяющей задавать точность отдельно взятых кривых у платформы.
Практическое применение такого инструмента у нас сводится к двум задачам:
Альтернативные решения от сторонних разработчиков
Около полугода назад встал вопрос об отрисовке еще более высокодетализированных и сложных спрайтов. Нужна была стабильность, которую мой инструмент пока гарантировать не мог. В итоге начали смотреть в сторону покупки стороннего плагина из Asset Store. Выбор стоял между Simply SVG и SVG Importer. В итоге, изучив видеоматериалы, документацию и отзывы двух продуктов, остановились на втором варианте.
Однако от использования моего инструмента мы не отказались. Важными его особенностями является возможность построения эдж-коллайдера и редактирование точности отдельных кривых. Конечно, это все можно было бы написать и поверх купленного плагина, но когда вы активно готовитесь к релизу, то хочется сосредоточиться на более насущных вещах и не трогать то, что уже оттестировано и прекрасно работает.
Еще в начале разработки мы не уделили внимание изучению готовых решений и сразу приступили к написанию собственного велосипеда. Можно долго жалеть о потраченном времени и гадать на тему “что было бы, если…”, но, все же, я очень рад получению такого опыта. Это была та самая не рутина, программированием которой я занимался с искрой в глазах.
Лично я верю в то, что команда Unity в скором времени добавит поддержку векторной графики “из коробки”. Благодаря описанному в статье методу можно забыть о проблемах потребления ресурсов как минимум на мобильных платформах и сконцентрироваться на более важных вещах. Конечно, далеко не все сейчас рисуют графику для 2D-игр в векторе, однако, уверен, переход на неё будет вполне оправдан, если на первое место станет размер дистрибутива, раздутый громоздкими ресурсами.
Благодарю за внимание. Все личные вопросы и замечания просьба присылать squakoon_jr.
Цикл статей «GameDev с нуля»
1. От хакатона до собственной студии разработки игр: часть 1, часть 2.
2. Unity3D и векторная графика.
3. Как общаться с игроком без слов.
4. Как выйти из хаоса и начать работать.
Привет, Хабр! Я занимаюсь программной частью в игре OVIVO и хочу поделиться с сообществом своим опытом внедрения векторной графики в Unity. Ниже я кратко опишу структуру SVG-файлов, расскажу о своих пробах и ошибках, а также продемонстрирую результат.
Постановка задачи
Имеем пустое пространство, заполненное белым цветом. Добавляем туда черные кляксы. Поскольку эти кляксы — интерактивный элемент 2D-игры, то будем звать их платформами. Также есть круглый персонаж, способный перемещаться по платформам и перескакивать из одного цвета в другой. Когда игрок находится в белом мире, на него действует гравитация, направленная вниз. Если же он очутился внутри черной платформы, то его тянет вверх. Перемещаясь между двумя мирами, у игрока сохраняется импульс, благодаря чему он может преодолевать препятствия, требующие определенной прыгучести. Так звучит краткое описание базовой механики нашей игры.
Но сегодня поговорим не о механике, а об этих черных кляксах. Поскольку платформы имеют относительно несложную форму и окрашены всего в один цвет, то для их создания идеальным инструментом будет любой векторный графический редактор. До моего прихода в команду всю графику ребята растрировали и оперировали громоздкими спрайтами в среде Unity. А громоздкими они были оттого, что требовалась высокая четкость картинки, следовательно, на разрешении спрайтов экономить нельзя было. Месяца два мы мучались с вопросом об использовании растра. Все методы перепробовали, но либо размер билда переваливал за один гигабайт, либо мобильные системы не выдерживали такого потребления ресурсов. И однажды мне стало интересно, что же такое векторная графика и с чем ее едят. В нашем случае все оказалось предельно просто: используются лишь кривые Безье и некоторые геометрические примитивы. А самым замечательным открытием для меня был формат SVG, в который без проблем можно было экспортировать всю нашу графику. Я очень обрадовался, узнав, что это всего лишь XML-документ.
Перед парсингом SVG необходимо было четко определиться с тем, как мы это все будем отображать в Unity. Самое очевидное решение: использовать сетку (Mesh). Поскольку наши платформы являются замкнутыми фигурами, то их контур можно представить в виде последовательно соединенных между собой точек, а благодаря триангуляции создать подходящий набор полигонов, которые будут служить заливкой для этой фигуры.
Каждую платформу мы также обертываем эдж-коллайдером (EdgeCollider2D — один из типов коллайдеров в Unity3D, представляющий собой ломаную линию). Это нужно для определения пересечения персонажем контура платформы, чтобы в нужный момент менять вектор гравитации. Таким образом мы должны убить двух зайцев одним выстрелом: рисовать графику и, основываясь на тех же данных, дополнять платформу физическими характеристиками.
Описание метода решения
Подробно рассказывать о структуре и всех возможностях SVG я не буду, однако остановлюсь на одном из его элементов — path. Ведь именно здесь хранятся почти все интересующие нас данные. Обратить внимание нужно на атрибут d, в котором записана информация о всех последовательно соединенных линиях, образующих единую фигуру.
Как видно из примера, набор чисел можно превратить в гладкую фигуру.
<path d="M250.74,263.55C110.9,271.94,26.38,53.78,37.84,44.19,47.66,36,129.46,179.64,255.58,179.68
c92.05,0,152.25-76.47,161.29-66.13C427.82,126.07,356.16,257.22,250.74,263.55Z"/>
Забегая наперед скажу, что лишь в одном атрибуте d единственного path можно рисовать неограниченное количество фигур, будь то замкнутые контуры или произвольные линии, но об этом позже. Данные из d условно можно разделить на блоки с контрольными точками для каждой кривой.
В работе с каждой платформой мы можем задать ей точность построения контура. Например, если установлено число 8, то каждая кривая будет разбита на 8 отрезков. В итоге, зная тип кривой и владея всеми ее контрольными точками, мы с легкостью можем строить ломаную линию, которая при высокой точности будет выглядеть аналогично гладкой кривой.
В path поддерживаются несколько типов кривых Безье и прямых линий, поэтому необходимо было подстраивать инструмент под возможность парсить каждый тип. Самые неприятные моменты возникали с форматом записи данных в атрибуте d. На протяжении всей разработки игры ребята постоянно сталкивались с тем, что те или иные векторные спрайты просто не строились, а мой инструмент выдавал ошибки. Как оказалось, разные графические редакторы (в том числе и разные версии одной марки) генерировали код SVG зачастую по-разному. Например, один и тот же путь можно записать различными способами: используя в некоторых местах верхний регистр или нижний, пробел или новую строку. Приходилось вручную ковырять каждый такой спрайт и дописывать свой парсер под нужды художников. При том, что иногда редакторы генерировали удобочитаемый код, а иногда все лепили в одну строку. Дело со временем усложнялось еще и тем, что необходимо было строить множество платформ, записанных в один SVG-файл. Потом и вовсе оказалось, что все фигуры можно засунуть в один элемент path. На самом деле, было и множество других сюрпризов, которые уже не вспомнить. Тогда, конечно, все писалось на скорую руку, но на будущее я для себя усвоил урок: сначала детальное изучение спецификации, потом код.
В большинстве случаев точность у нас была фиксированной, однако не всегда итоговая картинка соответствовала ожиданиям. Чем выше степень кривизны линии, тем на большее количество отрезков ее нужно разбить для создания эффекта гладкости. В качестве тестовой фичи я добавил возможность автоопределения точности в зависимости от кривизны линии, но впоследствии мы перешли на ручную настройку точности контура.
Иногда необходимо было подправить совсем небольшой кусочек сетки, но повышать точность всей фигуры целиком не хотелось. Поскольку объекты в сцене никак не привязаны к каким-либо ассетам в проекте, то в каждой платформе я на всякий случай хранил XML-текст по которому можно было распарсить графику. Таким образом, имея возможность подтянуть любой кусок платформы в виде кривой, мы теоретически могли править сетку и коллайдер только в конкретных промежутках. Хотя и пришлось слегка нарушить автоматизм в просчете точек, но в итоге мы обзавелись небольшой утилитой, позволяющей задавать точность отдельно взятых кривых у платформы.
Практическое применение такого инструмента у нас сводится к двум задачам:
- Повысить точность графики в особо заковыристых местах.
- Снизить точность коллайдеров на областях платформы, куда игрок не доберется.
Альтернативные решения от сторонних разработчиков
Около полугода назад встал вопрос об отрисовке еще более высокодетализированных и сложных спрайтов. Нужна была стабильность, которую мой инструмент пока гарантировать не мог. В итоге начали смотреть в сторону покупки стороннего плагина из Asset Store. Выбор стоял между Simply SVG и SVG Importer. В итоге, изучив видеоматериалы, документацию и отзывы двух продуктов, остановились на втором варианте.
Однако от использования моего инструмента мы не отказались. Важными его особенностями является возможность построения эдж-коллайдера и редактирование точности отдельных кривых. Конечно, это все можно было бы написать и поверх купленного плагина, но когда вы активно готовитесь к релизу, то хочется сосредоточиться на более насущных вещах и не трогать то, что уже оттестировано и прекрасно работает.
Эпилог
Еще в начале разработки мы не уделили внимание изучению готовых решений и сразу приступили к написанию собственного велосипеда. Можно долго жалеть о потраченном времени и гадать на тему “что было бы, если…”, но, все же, я очень рад получению такого опыта. Это была та самая не рутина, программированием которой я занимался с искрой в глазах.
Лично я верю в то, что команда Unity в скором времени добавит поддержку векторной графики “из коробки”. Благодаря описанному в статье методу можно забыть о проблемах потребления ресурсов как минимум на мобильных платформах и сконцентрироваться на более важных вещах. Конечно, далеко не все сейчас рисуют графику для 2D-игр в векторе, однако, уверен, переход на неё будет вполне оправдан, если на первое место станет размер дистрибутива, раздутый громоздкими ресурсами.
Благодарю за внимание. Все личные вопросы и замечания просьба присылать squakoon_jr.