Делаю игру с помощью ИИ: почему «сделай мне игру» не работает. Часть 2 — вайбкодинг
Давайте поговорим про вайбкодинг. Тут у ИИ есть особенно неприятная привычка: он может сделать всё, что вы попросили, и всё равно сделать совсем не то.
Пишешь: «Хочу игру, где маг сражается с толпами монстров, собирает опыт и выбирает улучшения». Добавляешь механику заклинаний, описываешь врагов, расписываешь развитие персонажа. Отправляешь. Получаешь код, запускаешь — маг бегает, монстры идут, что-то взрывается.
Первые пять минут хочется написать друзьям, что разработчики больше не нужны.
На шестой начинаешь разбираться, что именно тебе сделали.
Я делаю Magic Survivors — игру про мага, который собирает заклинания и отбивается от толп врагов. Ниже — примеры из разработки и то, что я бы делал иначе, если бы начинал заново. По ссылке можно попробовать игру самому.
Ты описал игру. Остальное нейросеть придумала сама
Допустим, вы попросили сделать огненный шар, который взрывается при попадании.
Нормальная задача. Что тут можно понять не так?
Шар попадает во врага. Враг получает урон от попадания. Потом происходит взрыв — и тот же враг получает урон ещё раз. Вы рассчитывали на один удар, а нейросеть решила, что их должно быть два.
Или наоборот: вы как раз хотели урон от попадания плюс взрыв, но получили только взрыв. В описании ведь не было сказано.
А шар должен исчезать после первого столкновения? Может ли пробивать врагов? Если может, он взрывается на каждом или только на последнем? Что происходит, когда он ни в кого не попал и долетел до конца?
Вы написали одно предложение. За ним спряталось несколько решений, от которых зависит поведение заклинания. Нейросеть эти решения примет. Только узнаете вы об этом уже в игре.
Самое неприятное — такой код вполне может работать без единой ошибки. Просто у вас в голове был другой огненный шар.
Со змейкой проще. У неё меньше поводов вас удивить
Классическую змейку ИИ обычно собирает без особой драмы. Там понятные правила: ползаешь по клеткам, ешь, растёшь, врезаешься — проигрываешь. Даже если вы что-то не уточнили, привычный вариант, скорее всего, вас устроит.
В своей игре вы уже можете хотеть что-то другое.
Например, чтобы игрок собирал заклинания из отдельных частей. Менял снаряд, добавлял пробивание, усиливал взрыв, делал двойной выстрел. Каждая механика по отдельности звучит просто. Потом вы начинаете их совмещать.
И нейросеть не всегда продумывает, как каждое заклинание будет работать с каждым модификатором. Добавила пробивание — снаряд проходит сквозь врагов. Добавила взрыв — он взрывается. А что получится, если поставить оба улучшения сразу?
У вас в голове шар пробивает трёх врагов и взрывается на последнем. А в игре он устраивает взрыв на каждом попадании. По отдельности обе механики работают. Только вместе получается совсем не то, что вы хотели.
С двойным выстрелом та же история: оба снаряда получают все улучшения? Мана тратится один раз или два? Нейросеть может решить по-своему, а какое-то сочетание вообще упустить. Поэтому проверять приходится не только каждое новое заклинание, но и то, как оно работает с уже добавленными модификаторами.
Большой запрос не избавляет от этой проблемы
В какой-то момент хочется решить всё одним длинным сообщением. Сейчас подробно опишу всю игру, перечислю механики, добавлю примеры — и наконец получу то, что надо.
Подробности помогают. Но даже большой текст оставляет пробелы. Пока вы описываете врагов, легко забыть, что должно происходить с ними после смерти игрока. Пока придумываете улучшения — не заметить, что два из них противоречат друг другу.
Часть вещей вообще трудно нормально описать заранее. «Приятное управление» ничего не говорит о том, насколько быстро персонаж набирает скорость. «Плотная толпа» не объясняет, сколько свободного места должно оставаться для побега. А «мощное заклинание» может оказаться огромной вспышкой, за которой не видно, куда бежать.
Нейросеть выдаст свою версию. Вам всё равно придётся её запускать, смотреть и объяснять, что именно не так.
Пусть сначала замучает вопросами
Тут очень помогает навык grill-me. С ним нейросеть сначала подробно расспрашивает тебя об идее: что именно должно происходить, как поведёт себя механика в разных ситуациях и какие решения ты ещё не принял.
Причём вопросы идут по одному. Отвечаешь — разбираете следующий момент. Нейросеть предлагает свой вариант и объясняет, почему советует именно его, но решение остаётся за тобой. До реализации вы сначала должны договориться, что вообще собираетесь делать.
Вот пример из моей переписки про Magic Explosion. Я попросил красивый магический эффект, который быстро расширяется от центра до радиуса урона. А первый вопрос оказался вообще не про красоту: когда враг должен получать урон? Сразу во всей области или только тогда, когда до него дойдёт волна?
Вроде попросил переделать картинку, а пришлось определиться с тем, как работает само заклинание. Без этого уточнения нейросеть могла бы оставить мгновенный урон, а сверху просто нарисовать растущий круг.
Мне нравится, что в таком разговоре приходится разбираться и в собственной задумке. Иногда кажется, что ты точно знаешь, чего хочешь. А потом тебя спрашивают про конкретную ситуацию — и ты сидишь: «Так, а действительно, как это должно работать?» Лучше подумать об этом сейчас, чем после того, как на спорном решении уже построили половину механики.
Сам grill-me не делает код безошибочным. Он помогает заранее договориться о поведении игры, чтобы потом было с чем сравнивать результат. Проверять его всё равно придётся самому.
Добавил механику — сам пошёл проверять
Если бы я начинал заново, то добавлял бы в игру по одной механике. И после каждой сам садился бы играть в роли тестировщика: проверял, что получилось, находил косяки и просил внести правки. Снова запускал, снова проверял. Пока на экране не появлялось именно то, что я хотел видеть в своей игре.
Например, добавил стрельбу. Снаряд летит куда надо? Попадание засчитывается? Стрелять вообще приятно? Если что-то не нравится, разбираюсь с этим сразу. До взрывов, пробивания и десятка улучшений ещё успею добраться.
Причём проверять — это не один раз выстрелить во врага и сказать «работает». Я бы прогонял каждое заклинание со всеми доступными модификаторами: сначала по одному, потом в сочетаниях. Как огненный шар ведёт себя с пробиванием? А если добавить двойной выстрел? А самонаведение поверх всего этого? Именно в таких комбинациях может вылезти то, чего ни ты, ни нейросеть не предусмотрели.
И очень круто, если есть друзья, которым можно дать игру потестить. Самому найти все баги тяжело: привыкаешь к своему управлению, выбираешь любимые заклинания и незаметно для себя играешь одним и тем же способом. А друг соберёт комбинацию, которую ты даже не пробовал, — и пришлёт видео с вопросом: «Это так и должно быть?» Поэтому я бы давал поиграть другим уже на ранних этапах, пока найденные проблемы ещё проще исправить.
Довёл стрельбу до нужного состояния — добавил следующую механику. И опять пошёл проверять её сам, в том числе вместе с тем, что уже работает. Новый эффект вполне может сломать старый, даже если по отдельности к обоим вопросов нет.
На словах это медленнее, чем заказать всю игру одним сообщением. Но мне было бы гораздо проще править одну механику, пока я хорошо понимаю, как она должна работать, чем потом распутывать целый клубок: почему враг получил урон трижды, откуда взялся лишний снаряд и когда вообще всё поехало.
Сохраняй версию, в которой всё работало
Вот что я бы делал с самого начала: проверил механику, убедился, что она работает как надо, — сохранил эту версию. И только потом просил нейросеть добавить следующую.
Иначе легко попасть в неприятную историю. Только что всё работало, потом ты попросил небольшую правку, за ней ещё одну — и теперь персонаж стреляет куда-то не туда. Пишешь «верни как было», но после нескольких переделок уже сам не помнишь, на каком шаге всё сломалось.
Для этого есть Git. Он хранит историю изменений проекта: можно посмотреть, что поменялось, и вернуться к сохранённому состоянию. Такое сохранение называется коммитом. А GitHub позволяет хранить эту историю ещё и в интернете, чтобы она не оставалась только на твоём компьютере.
Необязательно сразу учить все команды. Можно попросить ИИ сохранить проверенное состояние проекта коммитом и отправить его на GitHub. Главное — делать это до следующего эксперимента. Если новая идея не сработает, у тебя останется версия, к которой можно вернуться.
Но сам по себе коммит не означает, что всё исправно. Это просто сохранённое состояние. Поэтому сначала я бы проверял игру, а уже потом отмечал версию как рабочую.
А игру всё равно придётся делать тебе
С ИИ легко увлечься: только придумал новое заклинание — уже хочется увидеть его в игре. Потом ещё одно, ещё модификатор, ещё врага. Но в какой-то момент стоит закрыть чат и просто поиграть в то, что получилось. Именно там выясняется, что интересно, что раздражает и что вообще работает не так, как ты представлял.
Если бы я начинал заново, то меньше пытался бы получить всё одним запросом. Выбрал одну механику, обсудил спорные моменты, довёл до нужного состояния, сохранил — пошёл дальше. И почаще давал бы игру другим: они не знают, как в неё «правильно» играть, и это очень полезно.
Сообщение нейросети «готово» я бы считал приглашением к проверке. Готово — это когда я сам запустил игру, попробовал и понял: да, вот так и хотел.
Посмотреть, что у меня получается, можно в Magic Survivors на itch.io.