Если коротко, то в GAMEBRO Arena я хочу, чтобы вы побеждали не прокачкой и не тем, кто больше задонатил, а собственной фантазией. Вы описываете героя и его способности словами или загружаете рисунок, а ИИ собирает из этого играбельного персонажа. И чтобы это не легло на колени в первом же бою, мы пришли к простой схеме: нейросеть дёргается ровно ОДИН раз, в момент создания героя, и переводит ваше описание в JSON поверх примерно 50 примитивов поведения. А дальше матч идёт сам, детерминистично, на 30 Hz, без всякого ИИ в рантайме, и поэтому тянет обычный телефон.
До этого решения я дошёл не сразу, и сначала меня тянуло в совсем другую сторону, как, наверное, потянуло бы любого, кто делал мобильные игры. Был соблазн сделать как у всех: вот вам пул способностей, копите очки, покупайте из пула. Удобно, предсказуемо, легко балансить. И я это отверг сразу, потому что оно убивает саму идею. Мне не нужен магазин способностей, мне нужна песочница, где тысячи игроков делают тысячи вариаций, и вот это я и сформулировал дословно: игрок загружает фотку, картинку, рисунок своего героя и описывает его способности, а не покупает из пула каких-то там, хуй пойми чего.
Главный вопрос, который я задал сам себе
А можем ли мы вообще такое реализовать? Я прямо так и спрашивал: можем ли мы вообще реализовать такой движок, такую механику, которая позволит тысячам игроков создавать тысячи вариаций способностей? И тут было важно не упустить момент, потому что когда вы приносите такую идею ассистенту, по умолчанию вам начинают её упрощать, резать, сводить к «давай как у всех». Я на это отвечал ровно: по идее, в эпоху ИИ должны сделать такое, вот щас моя фантазия работает, видишь, ты слишком упрощаешь. То есть моя задача была не дать выкинуть саму суть, а как её технически реализовать — это уже второй вопрос.
А наивная реализация выглядит так: игрок пишет «огненный шар, который оглушает и отскакивает от стен», мы в момент каста дёргаем нейросеть, она думает и выдаёт, что должно произойти. Звучит красиво ровно до того момента, пока вы не посчитаете задержку. Это лаги по 5 секунд на каждый каст, а в реалтайм-арене это не лаги, это просто смерть игры. Когда вы в бою жмёте кнопку, у вас нет пяти секунд, у вас есть доли секунды, и никакой ИИ в этот момент вызываться не должен.
Решение: разделить «придумывание» и «исполнение»
Развязка пришла, когда мы разнесли два процесса, которые я по привычке держал в голове как один. Есть момент, когда способность придумывается, и есть момент, когда она исполняется в бою, и это вообще разные миры по требованиям. Придумывание может быть медленным и умным, а исполнение обязано быть быстрым и тупым. Значит, ИИ работает только на этапе создания героя: вы описали способность, нейросеть один раз перевела ваш текст в структуру данных, в JSON, который собран из готовых кирпичиков. А кирпичики эти — те самые примерно 50 примитивов поведения, что-то вроде универсального исполнителя способностей: spawn_projectile, apply_damage, apply_stun, dash, create_aoe и так далее.
То есть ваш огненный шар с оглушением внутри превращается в комбинацию из «создать снаряд», «нанести урон», «наложить стан» с какими-то параметрами, и движку в бою уже плевать, что вы там нафантазировали, он просто исполняет понятный ему список действий. И вот это ключевой сдвиг: фантазия игрока бесконечная, а язык, на котором она в итоге записана, конечный и заранее проверенный. Пятьдесят примитивов покрывают, как мне кажется, почти всё, что человек способен придумать про двухмерную арену, а если чего-то не хватит, список примитивов можно расширять, не трогая ни сами способности, ни боевой движок.
Как это выглядело в работе
Сам код, честно скажу, писал не я руками, я не умею и не скрываю этого, я оркестрировал Claude Code, а до архитектуры мы доходили через спор, прямо как я люблю, когда два ИИ спорят, а я выбираю победителя. И в этих дебатах вылезла приятная вещь: netcode, то есть сетевая часть, где сервер главный и решает, что реально произошло в матче, уложился примерно в 200 строк. Без Colyseus, без тяжёлых движков, без всего того, что обычно тащат «на вырост». Матч детерминистичный, на 30 Hz, то есть состояние мира пересчитывается 30 раз в секунду, и у всех игроков оно одинаковое, потому что считается из одних и тех же входных данных по одним и тем же правилам. Никакого ИИ внутри этого цикла, поэтому и телефон не плавится.
Отдельная история — спрайты. Если игрок придумал способность, которой раньше не было, то и картинки под неё в игре нет. И тут опять же работает не магия в рантайме, а заготовка: новый визуал генерит image-API, стоит это около цента за штуку, генерация занимает 8–15 секунд на новую способность, и, внимание, результат кешируется в библиотеку навсегда. То есть первый игрок, придумавший «ледяной кулак», подождёт эти секунды один раз, а все остальные, кто соберёт что-то похожее, получат картинку мгновенно из готовой библиотеки. Со временем эта библиотека растёт, и расходы на генерацию стремятся к нулю, потому что одни и те же кирпичики визуала переиспользуются снова и снова. Отдельная боль тут — чтобы герой не плыл от кадра к кадру, и как удержать единый облик в AI-генерации я уже наелся в работе над мультиком.
Камера, прицел и неожиданный поворот
По ощущениям от управления я подсматривал в сторону Brawl Stars: камера-фолловер, которая едет за героем, арена при этом больше экрана, и прицеливание через drag-aim, то есть вы тянете палец и видите, куда полетит способность. Это привычно тем, кто играл в мобильные арены, и не требует объяснений на старте, что для игры, где и так много нового в механике героев, прямо важно. Нельзя одновременно ломать человеку и управление, и привычку.
А самый свежий поворот в голове — это вопрос «а что если упростить». Я ведь изначально упёрся в рисование: загрузи картинку, опиши способности. И в какой-то момент сам себя поймал на мысли: а что если упростить, зачем рисовать, когда можно сделать запрос и сгенерировать так же нейронкой? То есть рядом с режимом рисования встаёт prompt-режим: вы не рисуете героя, а пишете его текстом, и нейросеть генерит и облик, и способности. Не вместо рисования, а в дополнение, потому что одним проще накидать пальцем, а другим описать словами, и пусть будет два входа в одну и ту же песочницу.
Что я из этого вынес
Главный урок тут даже не про игры, а про то, как вообще встраивать ИИ в продукт, который должен быстро работать. Соблазн всегда дёрнуть нейросеть прямо сейчас, в момент действия, и почти всегда это ошибка по скорости и по деньгам. Гораздо честнее спросить себя: а можно ли вызвать ИИ один раз, заранее, и закешировать результат навсегда? В моём случае ответ был да: один вызов на создание героя вместо вызова на каждый каст, один раз сгенерить спрайт вместо генерации на лету. И вся бизнес-математика тут же становится вменяемой: цент за уникальную способность, которая потом бесплатна для всех остальных, против бесконечных вызовов в каждом бою.
Я пока на стадии, где это архитектура и работающий каркас, а не готовая игра в сторе, и впереди ещё куча шишек: баланс пятидесяти примитивов, защита от того, чтобы кто-то не собрал имбу, модерация чужих описаний. Но скелет, на мой взгляд, правильный: фантазия игрока на входе, конечный язык примитивов в середине, тупой быстрый движок на выходе. А кому интересно, как это поедет дальше, расскажу подробно, когда дойдём до первого живого матча между двумя телефонами.