проект «Мир в бутылке»

Мир в бутылке: графика

Хочу немного остановиться на том, откуда взялась графика моего проекта, который я условно пока называю «Мир в бутылке», и какие нейросети я использовал для рисования.

Первых персонажей для будущего перформанса я нарисовал в «ЧатеГПТ 5.4». На вход дал несложный промпт, что-то типа такого:

нарисуй 10 характерных персонажей-человечков в пиксельном стиле маленького размера. референс в картинке

В качестве референса был приложен первый попавшийся скрин из какой-то бродилки времён ДОСа и, если честно, я не ожидал, что результат мне понравится настолько, что, по сути, определит всех будущих персонажей:

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

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

Картинки я на спрайты не резал: нейросеть справилась с этим самостоятельно — вырезала, сделала им прозрачный фон и даже добавила простенькую анимацию ходьбы. Кстати, позже я обнаружил, что у меня в коде оказалось два варианта спрайтов — для ходьбы влево и вправо, — и попросил оставить только один вариант, а второй делать поворотом спрайта.

Травку, камешки, насекомых и игровые предметы мне рисовал уже «Опус». С мелкими предметами он справился хорошо, а с теми, что покрупнее, — хуже. В итоге котёл, костёр, сундук и так далее я снова попросил нарисовать «ЧатГПТ». На мой взгляд, он их нарисовал слишком детализированно:

Пиксельные иконки: кувшин, закрытый и открытый сундук, надгробие, костёр, котёл, мишень, чучело и пень на белом фоне.

Поскольку их надо было сделать сильно меньше, «Опус» перерисовал новую версию «по мотивам». В итоге качество меня устроило. Текущий вариант лучше, чем было раньше, но выглядит менее натурально, чем то, что нарисовал «ЧатГПТ». В силу того, что я придерживаюсь ретро-стиля, как будто бы нужный баланс достигнут.

Гидру я рисовал в «Нанобанане 2», приложив как референс картинки персонажей. Текущий результат получился примерно с четвёртой или пятой попытки и, если честно, не кажется мне идеальным, но мне больше хотелось проектировать мир, а не возиться с графикой настолько долго.

Претензия всё та же: по сравнению с персонажами гидра чересчур детализирована.

Пиксельные спрайты гидры с тремя и пятью головами, а также двух вариантов пещеры гидры: многоуровневой с одним входом и одноуровневой с тремя входами.

Что делать дальше я пока не решил. Либо доделаю этот мир — там осталась ещё одна нереализованная задумка, либо перейду на другую платформу (кое-что заказал на «Авито») и спроектирую что-то там (идеи, опять же, есть).

4 комментария

Мир в бутылке: поведение ведьмы

Вчерашняя идея прикрутить небольшую нейросетку, которая будет выстраивать поведение ведьмы, в общем-то, провалилась. Ушло 4,5 часа, чтобы обучить простенькую трёхслойку на нескольких тысячах игровых ситуаций, но она показала прирост по сравнению с обычным поведением на основе уже существующих правил на уровне шума.

Обидно, досадно, но ладно. Там было пространство для манёвра, но слишком медленно тренируется. Чтобы ускорить, нужно переписывать весь игровой мир на какой-нибудь фреймворк для ускорения через видеокарту, а это долго даже с нейросетками. Да и качество такого переноса потом не проверишь.

Решил пойти другим путём — попробовать «дерево решений», оно легче в обучении и его проще потом разбирать. Это помогло — эксперименты пошли бойчее, и я довольно быстро увеличил метрику с 1,715601 до 1,933353, что довольно много на самом деле. Метрика там по простенькой формуле учитывает результативность кампании — удалось ли убить гидру и сколько народу выжило.

Потом «Курсор» просто разобрал мне получившееся дерево и перенес ту же логику в правила. Следующий шаг — хочу расширить количество «решений», которые может принять ведьма и посмотреть что получится.

Дерево решений Witch Policy Tree с узлами условий и цветными листьями действий (stay, deposit, revive_danger). Пиксельный маг в углу.
Визуализированное дерево решений эксперимента №2 (в данный моменту у меня кончается эксперимент №4)

Оставить комментарий

Мир в бутылке: гидра и ведьма

Довольно интересно получается вместе с дочкой проектировать игровой мир через нейросети. Ей не хватает усидчивости, чтобы довести дело до конца, но пока я его создавал, она иногда прибегала и вкидывала какие-то идеи. Так у нас появилась лошадка, а позже — гидра. Вообще дочка хотела дракона, но мне почему-то очень хотелось гидру, в ходе переговоров сошлись на том, что гидра визуально — почти дракон.

Пиксельная сцена: персонажи на зелёном поле с тропой, сундуком, пещерой, надписью «HELP!» и водяным знаком Bolkleis.dev.
Мир в текущем его виде: появился «босс» — гидра

Эта гидра — то, что называется «боссом», то есть сильный монстр, для убийства которого требуются усилия большинства персонажей. Гидра сильно спутала мне карты, так как, по сути, все мои персонажи — одиночки. Да, они могут подлечивать друг друга и воскрешать, но основной алгоритм у них написан так, чтобы зачищать свою окрестность от врагов и не умирать.

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

Не бог весть какая стратегия, но я до сих пор с ней бьюсь. Пришлось выделить поведенческий код в отдельный модуль и проводить симуляции на тысячах прогонов, чтобы отладить логику. Так удалось отладить поведение лекаря (я в разговоре с ИИ называю её «девочка»), а вот ведьма пока далека от идеала.

Скриншот терминала с результатами симуляции: успех BASELINE 36%, FIX:girl-range only 39,9%, FIX:girl-range+route 99,9%; ниже — анализ ошибок и комментарий про ведьму и гидру.
Процесс общения с «Курсором» по поводу изолированной симуляции поведения персонажей

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

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

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

Я как-то не думал, что это займёт столько времени, но планирую экспериментировать до успеха.

Оставить комментарий

Мир в бутылке: а где лошадка?

Пока программировал свой «Мир в бутылке», пришли жена и дочка и, как фанатки лошадей, потребовали ввести в игру лошадку. Я согласился с условием, что дочка нарисует прототип и хоть немного продумает механику — как именно лошадка будет себя вести.

В итоге, дочка по-быстрому нарисовала как она видит лошадь, а я двумя проходами вместе с нейросеткой довёл её до пиксельного совершенства.

Рисунок лошади в стиле Minecraft с пиксельной текстурой и синим седлом, рядом два уменьшенных пиксельных изображения той же лошади на чёрном фоне.

С игровой механикой всё-таки больше пришлось разбираться мне, так что я решил, что лошадь будет магическим средством бегства для лекаря, которая не умеет атаковать — теперь, если её атакуют, то она может куда-нибудь ускакать, призвав лошадь. У заклинания есть период охлаждения, так что постоянно бегать не получится.

Оставить комментарий

Мир в бутылке: сжатие в картинку

Вчера я писал, что код и вероятности перехода в цепях Маркова упакованы в картинку, но не объяснил что это и для чего сделано.

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

Это позволяет, во-первых, отдавать сжатый ответ даже на тех серверах, где сжатие выключено, во-вторых, использовать иногда более продвинутые методы сжатия, которые есть в современных форматах изображений, но могут отсутствовать при сжатии данных сервером через HTTP.

Скриншот консоли: вывод сборки проекта bolklet, показывающий размеры файлов (JS, модель, спрайты), выбор формата PNG/RGB как оптимального и итоговое сжатие изображения на 89%.
Процесс сжатия в картинку — выбираем формат, который сжимает эффективнее

Сжатие при этом реализовывать в ДжаваСкрипте не нужно — браузер за нас распаковывается картинку, а мы её просто попиксельно читаем.

Поскольку веса для цепей Маркова занимают аж 3,5 мегабайта в джейсоне, я воспользовался этой идеей, чтобы поэффективнее его ужать, бинарно сериализуя его в картинку, а потом затянул туда и остальное — основной код и спрайты.

Оставить комментарий

Мир в бутылке

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

При запуске такие программы чаще всего отображали какое-то интерактивное животное — котёнка, который прыгал по вашим окнам или тараканов, которые прятались за ними.

Не то, чтобы я по таким приколам скучал, но время от времени их вспоминаю, непонятно почему. Даже была мысль попробовать написать что-то своё. Но своими руками написать что-то подобное я не сподобился, зато, когда на днях вышла сеть «Опус 4.7», я решил попробовать посмотреть на неё именно на такой задаче.

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

В процессе написания идея модифицировалась — персонажи поселились на полоске внизу страницы, у них появились враги и некоторая специализация. Всё это полностью сделано «Опусом», я только направлял, тестировал и давал идеи.

Технически всё упаковано в одну картинку (так оказалось эффективнее) из которой читается и код, и спрайты, и вероятности перехода между состояниями для цепей Маркова.

Пиксельная сцена: зелёное поле с тропинкой, персонажами, сундуками, прудом и знаком с символами.

Оставить комментарий