Bloometry

This article is also available in English.

Здравствуй, дорогой читатель. Это свершилось – я разместил своё первое рабочее приложение в Google Play. Скачать можно по ссылке либо на официальном сайте. А в этом посте кратко расскажу о его жизненном пути.

Предыстория

Реализовать неказуальный игровой проект в одиночку и монетизировать его – не такая уж быстрая задача. К тому же в свете известных всем событий возникла необходимость заняться более приземлёнными прагматичными вещами.

На полке запылившихся проектов у меня давно валялось полусырое приложение для дизайнеров/печатников, нацеленное на упрощение самых разных задач, связанных с цветом. Среди них подбор цветовых гамм, извлечение основных цветов из фото, механическое смешение, поиск ближайших оттенков в популярных цветовых палитрах и системах, измерение Delta-E и множество других специфичных функций навроде построения спектральных кривых.

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

Самое смешное, что у меня была готова собственная .NET библиотека для работы с цветами и их преобразований. Были дополнительные надстроечные модули, каждый из которых предоставлял возможности решения поставленных выше задач. Было и чёткое понимание того, как подключить сторонние библиотеки (и это важно, потому что они делают Bloometry отличным от других подобных приложений).

Можно только спросить себя: как же так, ведь у тебя были на руках все кусочки паззла, почему не удалось соединить их воедино ещё тогда? Ответ кроется в том, что нельзя просто взять их все одновременно и сложить в цельную картину. Возможно, если у тебя детская мозаика из 10 элементов, то что-то и получится. Но если фрагментов куда больше, то всё равно придётся собирать что-то отдельно, формировать более крупные части, прибегать к хитростям навроде собирания общей рамки или поиска закономерностей в нарезке кусочков.

Тогда я переоценил свои силы и взялся за всё сразу. К счастью, нынешний я стал по-другому смотреть на некоторые вещи, и два месяца назад мне в голову пришла идея вернуться к этому проекту, разделив его на отдельные этапы. А для стартового запуска взять самые общие задачи – создание цветовых схем вручную и на основе изображений.

Детали реализации

Многие знают, что экраны наших устройств отображают цвета на основе модели RGB (красный – зелёный – синий). По крайней мере, слышали об этом. Кто-то так же знает, что для печати используется другая цветовая модель – CMYK (голубой – пурпурный – жёлтый – чёрный).

Чтобы задать цвет, мы просто указываем, сколько в нём должно присутствовать того или иного компонента (например, R = 255, G = 0, B = 0 – это красный). Но прелесть в том, что числовые значения RGB или CMYK сами по себе ничего не значат. Точно так же, как ничего не значат, например, координаты X = 10, Y = 20, Z = 30. Чтобы их использовать, а уж тем более преобразовывать друг в друга, необходимо задать какую-то систему отсчёта. В случае с цветами – обозначить цветовое пространство. Только тогда ваш компьютер, а вместе с ним монитор или принтер, смогут понять, какой цвет требуется воспроизвести.

Один из универсальных способов задания подобных цветовых пространств – это ICC-профили, стандарт для которых был разработан не абы кем, а Международным консорциумом по цвету. Те, кто плотно работает с Photoshop, Illustrator, InDesign или CorelDRAW наверняка сталкивались с ними, поскольку в таких профессиональных редакторах возможность их использования и перенастройки жизненно необходима.

Но в более простых утилитах дела обстоят по-другому. Они напрочь игнорируют факт существования разных цветовых пространств и предлагают для работы некие абстрактные модели RGB, CMYK, Lab или другие. Мне всегда казалось это странным, поскольку совершенно непонятно, из чего и во что они преобразуют, и как использовать полученные после преобразования цифры. Ну то есть использовать-то их можно, но насколько это будет корректно? Для примера я вам покажу, как выглядит цвет с компонентами R = 30, G = 130, B = 190 в пяти различных пространствах: sRGB, Adobe RGB, Apple RGB, ProPhoto и Wide Gamut.

Sample RGB swatches

Нужно сделать оговорку: ваш экран, скорее всего, работает с пространством sRGB, и реальные цвета отличаются от тех, которые вы видите. В любом случае, заметить отличия несложно. Именно поэтому в Bloometry я решил чётко разделить понятия цветовой модели и цветового пространства. После указания модели вам будет предложено в соответствующем поле выбрать конкретное пространство. А при возможности ещё и «подгрузить» ICC-профиль (что уж совсем космос 😀🚀).

Есть и другая немаловажная деталь, на которую разработчики дизайнерских приложений почему-то часто не обращают внимания – цветовой круг. Так уж повелось, что художники пользуются цветовым кругом Иттена на основе триады RYB (красный – жёлтый – синий), из которой путём смешивания получают другие оттенки. А вот дисплеи оперируют уже упомянутыми выше компонентами RGB, и цветовой круг для этой модели отличается (в кодировке HSL/HSV за позицию на круге отвечает компонент Hue – оттенок). И здесь возникают проблемы.

На изображении я разместил «классический» цветовой круг снаружи, а цветовой круг RGB – внутри. На первый взгляд, разница не так уж и велика. Но если мы решим найти на этих кругах контрастные (комплементарные) цвета, то обнаружим, например, что в классическом варианте это вполне себе привычная пара красный – зелёный, а вот в варианте RGB противоположным красному станет голубой. С точки зрения цифр все корректно – и там, и там цвета отделяет угол в 180 градусов. Но вот с точки зрения восприятия контраст в первом случае всё же считается сильнее.

Для примера я привёл ещё несколько образцов контрастных цветов. В левом столбце – «классика», в правом – RGB (образцы не выровнены по яркости/насыщенности). В Bloometry, конечно же, реализован более устоявшийся цветовой круг с красным, жёлтым и синим в качестве основных цветов.

Философия проекта

В предыдущем разделе я описал одни из самых ярких деталей, которые отличают Bloometry от других служб и приложений подобного рода. Наверное, они несколько усложняют функционал всего проекта и могут отпугнуть часть пользователей, но мне всё же видится, что лучше иметь возможность настроить что-то более детально, чем не иметь её вообще. С другой стороны, я уже рассматриваю для внедрения возможность переключения интерфейса между режимами «простой»/«профессиональный», которая могла бы решить данный вопрос.

В целом, как вы уже могли понять, я решил подойти к делу более основательно и «научно». В этом отношении мой максимализм/перфекционизм никуда не делся, поэтому в каждый элемент приложения я вкладываю стремление копнуть глубже и сделать детальнее. Сможет ли такое стремление дать свои плоды – вопрос интересный. Возможно, он даже лежит в плоскости того, должны ли мы делать то, что нам кажется правильным, или то, что будет более популярным.

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


Здесь заканчивается лирическая часть моего повествования. Спасибо за прочтение. Для страждущих оставлю в качестве послесловия ещё один раздел.

Технические тонкости

Bloometry реализовано с помощью Xamarin.Forms, поскольку C# остаётся моим основным рабочим инструментом. Да и возможность написания кроссплатформенных решений для независимого разработчика – это всё же больше плюс, чем минус, поскольку пресловутые человеко-часы никто не отменял, и необходимо как можно больше кода сделать независимым от целевой платформы. По итогу могу сказать, что даже с обилием кастомных UI-элементов, примерно 70% кода осталось общим (а если учитывать библиотеки, то и все 80–90).

В сердце проекта – моя собственная библиотека для работы с цветами Scol. Математическая модель преобразований основана на формулах с широко известного в узких кругах сайта Брюса Линдблума (Bruce Lindbloom). Извлечение цветов производится с помощью методов машинного обучения, реализованных в Accord.NET. Смешение и построение спектральных кривых отчасти базируется на идеях с этого прекрасного сайта, отчасти – на теории Кубельки-Мунка (Kubelka-Munk theory), отчасти – на моих способностях к реверс-инжинирингу (но это уже совсем другая история). Экспорт в различные форматы сделан на основе (не)официальных спецификаций в зависимости от того или иного типа файла.

Не обошлось и без использования других языков. Для интеграции рекламной платформы потребовались Android-библиотеки, написанные на Java, которые после танцев с бубнами всё же интегрировались в проект и повели себя вполне буднично по отношению к окружению. Смимикрировали, так сказать, как будто бы они изначально были написаны для .NET. Далее на очереди – что-нибудь аналитическое навроде Google Analytics или Flurry.

А вот для особого функционала, связанного с ICС-профилями, пришлось прибегать к более тяжёлым веществам тяжёлой артиллерии – языку C и библиотеке Little CMS. Изначально я писал свою собственную обёртку через P/Invoke, но за то время, пока приложение пылилось на полке, вышла готовая библиотека lcmsNET. Дело оставалось только за тем, чтобы скомпилировать сишный код с помощью Android NDK. На выходе получаются несколько файлов под каждую архитектуру процессора, которые без проблем добавляются к проекту.

Моделирование дорожного трафика и библиотека FollowMe

Как часто вы сидите у окна в кафе, наблюдая за суетой города? За мерцающими огнями улиц, проходящими мимо людьми, ползущими в разные стороны машинами – всё то же, что следить за пляской огня или метаморфозами воды. Не знаю, как вы, а я могу часами смотреть с какой-нибудь высотки на нескончаемое движение города.

Пришла пора рассказать вам о моём основном проекте, которым я был занят в последние три месяца (на самом деле, гораздо больше, если учитывать изучение большого количества научных работ и прошлых попыток реализации). Пожалуй, это одна из самых сложных вещей, которыми мне приходилось когда-либо заниматься. Но эта крепость больше не выглядит неприступной, и по завершении текущего цикла мне действительно есть, что показать и о чём рассказать.

Логотип для своего проекта я ещё не придумал, но только посмотрите, как притягательны эти низкополигональные модельки

В той игре, которую я планирую разработать, дорожный трафик занимает чуть ли не центральную часть. По крайней мере, это будет один из самых важных аспектов во всём дизайне игрового мира. К тому же система с таким количеством сущностей (100 000 транспортных средств для моей задумки – не предел) сама по себе является достаточно сложным программным проектом, реализация которого может неплохо поднять уровень навыков да и вообще быть показателем того, насколько мои идеи реализуемы.

Поэтому сейчас я работаю над модулем, позволяющим создавать транспортные сети любых конфигураций и моделировать дорожное движение на них. Представьте себя инженером автодорожного профиля, проложите несколько магистралей, создайте между ними развязки и пересечения, запрограммируйте светофоры. А потом просто наблюдайте, как виртуальные легковушки, автобусы, грузовики и трамваи пытаются пробраться через ваш лабиринт, следуя из точки А в точку Б. Уже сам по себе этот танец способен заворожить, даже без цели и смысловой нагрузки.

Follow Me library traffic jam
Не успели выехать на улицы, как тут же встали в виртуальные пробки. Реализм!

Надо сказать, что реализуемая мной идея далеко не нова – самые ранние публикации на тему компьютерного моделирования трафика, которые мне довелось изучить, датировались началом 80-х годов. С тех пор появилось множество наработок в этом направлении, но все их можно разделить на три большие подгруппы: макро, микро и гибридные. В макро, как следует из названия, мы опускаем индивидуальные детали каждого транспортного средства и пытаемся сформировать некий общий поток, как если бы наши магистрали были трубами, а потоки машин потоками воды. Я не шучу, многие макромодели используют в качестве основы законы гидродинамики. В противоположность им ставятся микромодели, где моделируется поведение отдельных сущностей в зависимости от дорожной ситуации, особенностей транспортного средства и характера водителя. Здесь основу составляют following-модели (модели следования, то есть большую часть времени мы ориентируемся на следующее впереди нас ТС). Здесь сразу напрашивается очевидный плюс этих систем: более точное моделирование с учётом индивидуальных особенностей. К сожалению, это требует и бОльших расчётов – для крупных сетей такие модели не всегда подходят (особенно для моделирования в реальном времени). Поэтому существуют гибридные модели, объединяющие два этих подхода. Ведь, по сути, большую часть времени машины движутся в общем потоке, который мало отличается от потока воды, а на перекрёстках мы просто переходим к индивидуальным моделям. Из минусов – сложность разработки таких систем. По крайней мере, с моим текущим уровнем математики мне пока что не удалось создать в голове чёткого понимания их работы.

Follow Me library with debug info
Отображение технической информации позволяет отследить детали, важные для создания и функционирования сетей

Как видно из названия моей библиотеки, я выбрал в качестве основы модель следования. В самом простом понимании эта модель рассчитывает ускорение транспортного средства в конкретный момент времени t. И всё. То есть мы берём наши сущности, рассчитываем для каждой ускорение в зависимости от окружающих условий. А, узнав ускорение, вычисляем скорость и положение в некий последующий момент времени t+Δt. И «перемещаем» глобальное время на эту позицию. Чтобы повторить всё то же самое снова.

И всё было бы просто, если бы весь мир стоял на одной единственной очень длинной дороге шириной в две полосы. Но ведь есть ещё перекрёстки, светофоры, дорожные знаки, многополосное движение, парковки, непредсказуемые пешеходы, велосипедисты и неопознанные летающие объекты. Они-то и вносят всю смуту в нашу стройную систему. И простая following-модель превращается в массивного динозавра, который должен учесть множество дополнительных факторов, прежде чем наше авто перепрыгнет в своё счастливое Δt-будущее.

Им ещё многому предстоит научиться. Но хотя бы не сталкиваются, уже хорошо!

На текущий момент я уже более-менее разобрался со скоростным режимом полос, приоритетами, перекрёстками, светофорами и стоп-линиями. А также добавил возможность формировать составные ТС (ведь трамваи и грузовики могут состоять из нескольких частей). На повестке дня – параллельные перестроения. Крепкий орешек, который затрагивает практически все аспекты моделирования. Многие части уже написанного кода, в которые оно обещало хорошо вписаться, на деле оказались неподготовленными, и подвергаются переработке. Причиной тому некоторые преждевременные оптимизации (никогда не начинайте оптимизацию прежде, чем у вас будет готов рабочий прототип – успеется!). А также наивная уверенность в том, что простые прикидки в уме позволят в будущем подружить существующий код с крупной партией новых возможностей. Но, в целом, всё не так уж печально. Ведь мои подопечные хоть и с неохотой, но всё же начинают перестраиваться в новые полосы, расталкивая конкурентов и устраивая опасные ситуации.

Сейчас рано говорить о дате релиза библиотеки, но она обязательно будет иметь модуль интеграции с движком Unity, доступный на Asset Store. Чтобы получилось многофункциональное решение для внедрения в любой игровой мир масштабной транспортной сети. Кому-то это позволит оживить статичное окружение, добавить очарования или даже написать свою собственную стратегию. Но ещё больше я надеюсь на то, что мой проект поможет в дизайне реальных транспортных систем и решении проблем городского трафика. Ведь, пусть он и реализован в игровой форме, весь его фундамент заложен на научной основе. Как и во многих других проектах индустрии. Так что никогда не стоит сбрасывать игры со счетов в вопросах реального мира.

Pure It!

Как-то в своём профиле в Instagram я рассказывал тебе о модификации, которую разрабатываю для компьютерной игры Factorio. Той, которая позволяет сделать игровой мир чуть лучше путём очистки воздуха. Осенью я наконец-то взял себя в руки и довёл этот мод до стадии альфа-тестирования, так что теперь он доступен для скачивания на официальном портале игры.

Bery0za's Pure It rendered machines
Рендер всех механизмов, которые мне довелось смоделировать для дополнения. Без текстур смотрится даже лучше

В процессе я неплохо поднял уровень своих навыков в Cinema 4D, в которую, кстати, влюбился (за исключением карт развёртки). Припомнил невероятно обаятельный язык Lua. С любовью и ненавистью покопался в чужом коде и документации (весьма туманной местами). А также написал пару удобных утилит, которые позволили упростить работу со спрайтами. Но давай обо всём по порядку.

Идея пришла ко мне после многочасовых игровых сессий с @softkitty___warmkitty, в ходе которых нам периодически приходилось устраивать рейды на местную фауну и её гнездилища. Весьма агрессивную, надо сказать. Но её можно понять: сидишь себе спокойно, растишь кровожадных ядовитых деток, а тут налетает туча сернистых облаков и портит всю малину (или что у них там на завтрак?). Естественно, надо этих владельцев заводов (газет, пароходов) покусать. А заодно погромить эти самые заводы. Что, в свою очередь, не могло понравиться нам, строителям светлого будущего. Вот я и решил сделать игровой мир ещё чуть светлее. В прямом смысле. Убрать те самые облака с тяжёлыми металлами и прочей химией и обрести, наконец, вселенскую гармонию.

Прежде всего мне хотелось, чтобы процесс улавливания и фильтрации был максимально приближен к реальности. Ведь пусть игра и происходит в некоем инопланетном сеттинге, вещества, материалы и предметы там приходится использовать вполне земные. Поэтому первым делом я пошёл бродить по промышленным сайтам и читать про методы очистки воздуха в нашем с вами вполне реальном (спорно!) мире. Как оказалось, их придумано немало, и мне пришлось сосредоточиться на основных: абсорбции (растворение в жидкости) и адсорбции (поглощение другим веществом). Для каждого я накидал небольшую схему, которая описывает техпроцесс от начала и до конца, начиная с «сырьевых» материалов и заканчивая побочными продуктами фильтрации. Так я смог понять, какие механизмы мне нужно будет реализовать и какие цепочки преобразований описать. А также определить те места, в которых игрок сможет позднее сделать улучшения.

Схема фильтрации
Одна из технологических ветвей процесса улавливания и фильтрации – абсорбционная

После этого процесс разделился на две основных ветви: собственно программирование механизмов и создание их прототипов (описание и графика). Если в части первого разработчики предоставили весьма исчерпывающую документацию (к тому же мне пригодился код из других пользовательских модов), то в плане прототипов официальный портал игры весьма немногословен. Да, он описывает всё. Но без каких бы то ни было деталей и примеров. Так что в этом вопросе я бы сразу порекомендовал смотреть на моды других игроков, благо там даже ничего декомпилировать не надо.

По кодингу сложностей у меня не возникло. Разве что пришлось немного поразбираться в игровых событиях, сохранении/загрузке и мультиплеерной совместимости. В этом плане все проблемы возникали только в тех местах, где я неправильно или не в тот момент обращался к глобальной игровой таблице. В остальном могу сказать, что авторы предоставили весьма исчерпывающий функционал, который позволяет добавлять в игру практически любые механики. Если вы не пользуетесь каким-нибудь сторонним инструментом для отладки (я находил плагины для Visual Studio Code), то game.print() станет одним из ваших любимых методов.

Bery0za's Pure It absorption workflow
Та же самая схема, но теперь уже реализованная в игре

С графикой мне предстояло решить куда больше вопросов: создание 3D моделей, конвертирование их в игровые спрайты (двумерные внутриигровые изображения, представляют собой один или несколько кадров анимации), создание описаний того, как эти спрайты должны отображаться. Могу сказать, что на это ушло процентов 80 всего времени, которое я потратил на мод. По ходу я создал предустановленню сцену для Cinema 4D, которая имитирует игровое освещение и атмосферу и позволяет сосредоточиться на создании модели, а также упрощает последующий экспорт в 2D изображения. После чего они подхватываются моей же утилитой, комбинирующей их вместе и выдающей в результате упакованные и готовые к использованию атласы.

Cinema 4D Factorio scene setup
Предустановленная сцена для трёхмерного моделирования

В моделировании мне помогли не столько видео-инструкции от зарубежных мододелов, сколько уроки по Cinema 4D, ведь каждый из них рисовал графику и организовывал экспорт по-своему. Так что я рекомендую вам сначала разобраться в деталях программы, это позволит организовать свой собственный рабочий процесс. О своём я, пожалуй, напишу отдельную статью.

Описание рецептов, самих сущностей и их графического представления – рутинная задача. Большую часть времени я просто копировал существующие описания, внося в них небольшие изменения, главное, нужно быть максимально внимательным при указании величин и ссылок. Сейчас я уже и не припомню, сколько раз во время загрузки игра показывала мне кукиш и говорила, что такая-то картинка не найдена или такой-то размер не соответствует реальности. Думаю, этот этап я тоже автоматизирую и напишу ещё одну утилиту. После чего можно будет говорить о готовом полноценном рабочем процессе, знай только придумывай механики и рисуй сущности.

Пока что для меня осталось не до конца понятным, каким образом в игре отображаются трубы и применяется окрашивание (tint), но, надеюсь, в сообществе мне помогут с этим вопросом. Кстати, если вы знакомы с английским, форум – отличное место для решения возникающих задач.

Bery0za's Pure It machines
Все механизмы с первой картинки так, как они выглядят в игре

Ух, как много получилось. А ведь это я буквально пробежал по верхам, описав в двух словах весь свой путь от идеи до рабочей альфа-версии. Понимаю, пост получился весьма техническим, такова уж природа моей деятельности. Но, возможно, кого-то он вдохновит поиграть в Factorio, а кого-то – придумать и реализовать свою собственную модификацию. Потому что для себя я усвоил главное – если ты можешь поставить себе задачу, то ты можешь и решить её. Чуть не забыл, а вот и сама ссылка для загрузки: играйте, наслаждайтесь и делайте мир лучше.

Mazeraptor

Вы любили в детстве разгадывать лабиринты? Искать выход из сложных переплетений, напечатанных в журналах с головоломками? Может быть, вы помните легенду о нити Ариадны или игру с пространством в фильме «Начало»? У всех этих лабиринтов был один минус. После того, как путь найден, уже не составляло труда пройти по нему снова.

Поэтому разработчики уже давно озаботились вопросом того, чтобы создавать лабиринты «на лету» и использовать их в своих проектах. Только представьте, что перед вами каждый раз – совершенно новый мир, в котором проверенная схема уже не действует и нужно искать новый путь.

Для этих целей я написал собственную программную библиотеку Mazeraptor. По-русски это слово звучало бы как-то навроде «Лабиринторатопс». Знаю, выглядит ужасно, а произнесение вслух может разбудить каких-нибудь древних богов, поэтому оставлю его, как есть, в своём изначальном варианте.

Что же нужно для создания лабиринта? Нужна некая структура, которая будет описывать положение его «комнат» относительно друг друга. Это может быть просто прямоугольная сетка с клетками, как в тетради, где каждая клетка исполняет роль такой комнаты. А может быть и множество колец друг в друге, разделённых на ячейки. Здесь всё ограничено только вашей фантазией. Главное, чтобы вы смогли объяснить логику своей структуры на понятном языке.

Как видите, моя библиотека умеет выдумывать и по-ньюйоркски прямоугольные лабиринты, и по-московски кольцевые. Скажу больше, в ней ещё реализована возможность создавать лабиринты в виде пчелиных сот или треугольной плитки. А на десерт – структуры из своих собственных изображений. Как, например, эта.

Логотип приложения, созданный в самом приложении

(Не)удивительно, но помимо формы и структуры лабиринтов теоретики также выдумали немало способов непосредственно его создания. Ведь мало организовать отдельные ячейки в структуру, нужно рассказать им, из какой в какую существует проход, а какие закрыты друг от друга глухой стеной. Все вышеприведённые примеры были созданы с помощью алгоритма обратного прохода. Но есть и другие. Например, алгоритм растущего дерева или алгоритм Prim.

Понимаю, в целом всё выгядит одинаково запутанно. Поэтому я добавил цветовую индикацию того, в каком порядке обрабатываются ячейки. От тёмных к светлым. Видите разницу? На картинке справа прослеживается характерная черта Prim – множество коротких тупиковых ответвлений. Можете вернуться к первым двум картинкам и взглянуть на ход работы алгоритма обратного прохода (его характерная особенность – длинные закрученные ходы).

Не составляет также труда для моей программы найти путь из ячейки А в ячейку Б. Причём начальную и конечную точку вы можете указать абсолютно любую. А для поиска использовать различные алгоритмы, в том числе и A Star. Надо сказать, что в среде компьютерных игр это, пожалуй, один из самых распространённых способов поиска пути. Играете ли вы в стратегии или шутеры, будьте уверены, где-то там под корпусом вашего ПК или консоли маленькие единицы и нули скачут под его управлением. Уже не удивлю вас, сказав, что придумано и множество других алгоритмов, решающих ту же задачу. Всем заинтересованным могу намекнуть, что смотреть стоит в сторону теории графов, о которой я вам как-нибудь обязательно расскажу.

Если же вы в целом интересуетесь темой создания лабиринтов, обратите внимание на книгу Jamis Buck «Mazes for Programmers», которая невероятно помогла мне в работе. На этом, пожалуй, достаточно слов. Оставляю ссылку на архив со своим генератором здесь. А также ссылку на github для тех, кому нужен функционал библиотеки. Играйтесь, ищите, создавайте и не забывайте делиться со мной своими впечатлениями.