- BrainTools - https://www.braintools.ru -
Все уже наверняка видели посты на «Бэкдорах», «Эксплойтах» и прочих кибертопорах о том, как кто‑то, особенно с выходом новой модели, естественно, в один промпт сгенерировал копию Call of Duty, Starfield или любой другой игры. По видео выглядит сыровато, но играбельно, однако ключевая проблема здесь в том, что это демонстрационный вариант в формате браузерной игры. То есть совсем не те проекты, где мы с вами увлеченно сидим часами (любители браузерных игр и мобилок простите).
Как любой геймер, я всегда мечтал сделать свою игру. Не то что бы мне недоставало проектов, которые регулярно презентуют на Gamescom, а потом убирают на полку. Но хочется чего‑то своего, людского, с российским колоритом. А наш ААААА‑геймдев только начал подавать признаки жизни.
Я умею в C#, более‑менее понимаю, как устроен Unity, могу поковыряться в Blender и что‑то подрисовать на развертке в фотошопе. Но просто не хочу и все. С бесконечными задачами по работе, хобби и бытовым СДВГ сесть за какой‑то долгострой нет ни времени, ни возможности. А потому меня посетила мысль отработать маркетинг желтушных IT‑каналов на полную и собрать игру исключительно при помощи ИИ. Без единой собственной строчки кода, без единой собранной вручную модели и отрисованной текстуры.
В этой части я расскажу о тестах некоторых технических аспектов. Здесь не будет ничего о сценарии, механиках, кор лупах и даже о концепте. Ведь сперва нам нужно понять, а можно ли в принципе сделать играбельную сцену достойного уровня.
Текущие модели уже позволяют спокойно собирать игры с низкополигональными ассетами, визуальные новеллы, пиксельные рогалики и мобильные игры. Для инди‑разработчиков этот сегмент всегда был доступен и таковым остается. Я же хочу собрать игру от третьего лица с графикой AA‑уровня, интересными механиками, разнообразными врагами, возможно боссами и атмосферным сеттингом. Не думайте, что к типичным инди‑проектам я отношусь предвзято, но выбранный мной подход обусловлен необходимостью отладки дополнительных технических аспектов, чего попросту нет на играх с простой графикой и физикой.
Во‑первых, 2D игры не содержат сложного пространства, на чем ИИ, забегая вперед, сыпется. Логика [1] и физика перемещения в таких играх происходит по двум осям, расстояния между объектам рассчитает даже ребенок, а головная боль [2] в виде масштаба по высоте в зависимости от игрока и NPC отпадает сама собой.
Во‑вторых, низкополигональные модели как правило не имеют отдельных мешей под одежду, либо они также имеют малое количество квадратов, а потому и пяти минут в Blender хватит для того, чтобы поправить руки, влезающие в текстуры груди персонажа и прочие неприятные моменты. К тому же, если вы посмотрите на витрину Meshy AI, увидите именно такой тип моделей. И это неспроста, их попросту легче сгенерировать по картинке или текстовому промпту.
И, наконец, в‑третьих, разработчик, сэкономив время на первых трех проблемах, может сосредоточиться на интересных механиках и взаимодействии с миром, которое не нужно пошагово дебажить.
В качестве движка я выбрал Unity. У него удобный официальный MCP, который релизнулся совсем недавно, и уже перерос в полноценную интеграцию с Unity CLI. В качестве генератора моделей MeshyAI. В качестве инструмента для правки моделей, для авторига — Blender и его аддон Riggify. Анимации также позволяет делать Meshy, но для дополнительного ресурса я решил взять общепризнанный Mixamo. В качестве моего личного работника Rockstar, вынужденного трудиться 24 часа в сутки, я взял Cursor. Уже сейчас могу сказать, что это не самое сильное решение, но оно оказалось под рукой. Следующий на очереди для тестирования в уже отлаженном пайплайне будет Codex, а затем самосборный харнесс.
Также стоит сразу сказать о небольшом читинге, который я использовал и временно использую для тестирования самых узких технических мест. Я использую бесплатные ассеты построек, а также бесплатные или слитые платные контроллеры, внутренние жанровые движки и утилиты вроде RoomGen. Это небольшое отступление от изначальной задумки, так как бесплатные ассеты нуждаются в доработке как минимум текстур, а зачастую и самих моделей. Контроллеры обеспечивают легкую привязку клавиатуры к игровому персонажу, а потому не сильно разрушают мой замысел. Что же касается внутренних движков а‑ля «собери свой хоррор или соулслайк» — это слитые платные ассеты для очень старых версий Unity, поэтому нуждаются в комплексной доработке и адаптации под новую версию. К тому же, мы ведь хотим сделать что‑то новенькое, а потому наиболее интересные механики и игровой баланс позаимствуем и внедрим в наш проект.
Первый опыт [3] взаимодействия со скачанными контроллерами и FPS‑движками моментально уперся в то, что Unity 6 совершенно не умеет (да и не должна) работать с проектами прошлых версий. На одном в качестве зависимости подтянулся старый NavMesh, который ломал буквально все. В новой версии он заменен Ai Navigation и переписывать и перевязывать весь внутренний игровой контроллер оказалось плохой идеей.
Столь же неудачной идеей оказалась и сборка игровой сцены полностью из готовых ассетов. Под выбранную тематику их нашлось достаточно, но разница в стилях и качестве текстур бросалась в глаза, особенно на крупных локациях. Первым решением, которое пришло в голову, было: а почему бы просто не подключить nano banana для общей стилизации и апскейла текстур?
Результат получился неплохим, текстуры стали более качественными, но съехал PBR (это такой набор специальных карт, которые помогают виртуальному свету падать и отражаться на объектах, благодаря нему мы видим шероховатости и текстурность, а также мелкие тени). Так произошло из‑за того, что Nano Banana в рамках стилизации дорисовывала новые трещины, отколы и щели, не меняя по понятным причинам сами карты.
Вместе с этим оказалось, что большинство ассетов внутри представляют из себя не просто пустые коробки, а буквально тоненькие текстурки, натянутые будто на листы картона. Это некритично для дизайна уровня в целом, но игровыми такие зоны не делать.
И чем дальше я продолжал правки, тем больше их становилось. И как это часто бывает с ИИ, одно упущенное действие на этапе его взаимодействия с MCP Blender, например, спустя несколько итераций приводило к тому, что где‑то что‑то не стыкуется.
Первая попытка была исключительно экспериментальной. Я запустил Cursor, дал ему написанное через Perplexity подробное ТЗ и просто наблюдал.
Не буду прилагать ТЗ целиком, но вкратце суть была в короткой демке survival‑horror в обычном российском городе. Это совсем не то, что я планирую сделать в финале, но для обкатки технических тонкостей идеально — много зданий, много переулков, растительность, газоны и NPC.
Пока я позволил себе пару часов, так сказать, повайбить, Cursor собрал рабочий проект, в котором были враги, игровой персонаж, крупная локация, постройки и несколько интерактивных зон. Все за один промпт! Пока без текстур и реальных моделей, но прототип появился прямо у меня перед глазами.
Здесь я столкнулся с первой и главной проблемой. Искусственный интеллект [4] не понимает, что такое 3D‑пространство, во всяком случае исходя из тех данных, что он получает от Unity. Он может его прочитать, но не может визуализировать и самое главное, он не понимает, как должен быть устроен нормальный город и как он заполняется физическими объектами. То есть город есть, но здания расположены так, как вообще‑то они расположены быть попросту не могут, если вы не в цыганском поселке с простирающимся до горизонта самостроем.

Я решил поступить с этой проблемой радикально. Я просто выгрузил с openstreetmap по api подробнейший geojson с координатами расположения построек, их типом, высотой и характеристиками. Немного адаптировал это через Gemini под более универсальный формат и грузанул в Cursor. Получилось что‑то в таком духе:
{
"environment": {
"water_bodies": [
{
"id": "river_aurajoki",
"name": "Аурайоки",
"type": "river",
"width_avg_m": 15.0,
"coordinates_local_xy": [
[-427, 600], [-390, 550], [-237, 160], [-8, -250], [210, -580], [550, -620]
]
},
{
"id": "stream_ruokooja",
"name": "Руокооя",
"type": "stream",
"width_avg_m": 4.0,
"coordinates_local_xy": [
[-2228, -203], [-1800, -270], [-550, -200], [-530, -320]
]
}
],
"tree_rows": [
{
"id": "trees_lenina_street",
"points_local_xy": [[440, -280], [482, -286]]
}
]
},
"road_network": [
{
"name": "Советская улица",
"class": "residential_main",
"surface": "asphalt",
"width_m": 7.0,
"points_local_xy": [
[-220, 153], [-200, 206], [48, 206], [67, 209]
]
},
{
"name": "улица Бусалова",
"class": "residential",
"surface": "dirt_bad",
"width_m": 6.0,
"points_local_xy": [
[386, 858], [542, 428], [455, 163], [253, -4], [198, -134]
]
},
{
"name": "Заброшенная железная дорога",
"class": "railway_abandoned",
"surface": "gravel_rails",
"width_m": 4.0,
"points_local_xy": [
[-496, -284], [-276, -255], [4, -270], [258, -329], [314, -368]
]
}
],
"buildings": [
{
"id": "bld_church_valentina",
"name": "Часовня Св. Великомученика Валентина",
"category": "religious",
"floors": 1,
"height_m": 8.5,
"roof_type": "hipped_with_cupola",
"material": "wood_stone",
"footprint_local_xy": [
[464, -259], [465, -262], [467, -263], [470, -262], [471, -259], [470, -257], [468, -255], [465, -256]
]
},
{
"id": "bld_factory_works_1",
"name": "Цех фанерного комбината",
"category": "industrial",
"floors": 2,
"height_m": 10.0,
"roof_type": "flat",
"material": "industrial_metal_brick",
"footprint_local_xy": [
[361, -576], [380, -613], [397, -604], [378, -567]
]
},
{
"id": "bld_residential_busalova_block",
"name": "Жилой дом (ул. Бусалова)",
"category": "residential_apartment",
"floors": 3,
"height_m": 10.5,
"roof_type": "gabled",
"material": "brick",
"footprint_local_xy": [
[635, 132], [643, 125], [653, 136], [646, 143]
]
},
{
"id": "bld_shop_pyaterochka",
"name": "Пятёрочка",
"category": "commercial_retail",
"floors": 1,
"height_m": 4.5,
"roof_type": "flat",
"material": "composite_panels",
"center_local_xy": [-23, 43]
}
],
"points_of_interest": [
{
"name": "Выставочный зал современных художников",
"category": "culture",
"location_local_xy": [-580, 188]
},
{
"name": "Деревянная скульптура 'Тапио'",
"category": "artwork_prop",
"location_local_xy": [-13, 87]
},
{
"name": "Деревянная скульптура 'Вяйнямейнен'",
"category": "artwork_prop",
"location_local_xy": [-82, 1]
},
{
"name": "Часовня Георгия Победоносца",
"category": "religious",
"location_local_xy": [-66, 154]
}
]
}
После внесенных правок проблема была решена. Но появилась другая.
Забегая немного в следующие части, где мы совсем чуть‑чуть поговорим об основах геймдева, реальный город — не совсем то, что нужно в игре, если мы не делаем нарративную бродилку. Постройки должны иметь сопоставимый с игровым персонажем масштаб, а значит одна проходка из точки А в точку Б будет занимать примерно столько же времени, сколько и у вас в этом самом городе. А значит задача #1 на полях — научить Cursor понимать, как устроен город, при этом научить его достаточно упрощать игровую карту для того, чтобы не задушить игрока. Это несложно, нам достаточно начертить типовую схему города, а дальше дать ИИ непосредственно сценарий нашей сцены.
Вторая итерация учитывала уже известную мне проблему. а потому я решил сделать совсем небольшую сцену с 10–15 домами, несколькими брошенными машинами, одной игровой комнатой внутри здания с простеньким интерьером и дополнительными предметами из скачанных моделек и ассетов.
Здесь проблема номер 1 вернулась в новом виде. Cursor все еще плохо работает (независимо от выбранной модели) с трехмерным пространством, попросту забывая получить и высчитать по каждому новому объекту три координаты и их расстояние друг от друга с учетом масштаба. Здания врезались одно в другое, машинки были то крошечными, то гигантскими, а порой торчали в двери хрущевки.
Все решилось просто. Во‑первых, я попросил Cursor написать скриптик на C#, который при размещении того или иного объекта по простой формуле считал его положение в пространстве по отношению к соседнему. Во‑вторых, я составил файлик с классификацией всех имеющихся у меня объектов.
| Status | Meaning |
|--------|---------|
| `in_project` | Present under `NeoFPS/Assets` (or junction) |
| `external` | On disk outside Unity project |
| `used` | Referenced by campaign scenes / game prefabs |
| `staging` | In project library, not yet in playable zones |
| `demo_only` | Demo scenes/content — purge candidates at ship |
| `skip_heavy` | (deprecated for us) — heavies now `staging_heavy` |
| `staging_heavy` | Large GLB in library; place sparingly |
|`kiosk` | Street kiosk | Outdoor street only | `used` (Z2 Kiosk_Plaza) |
| `low-poly-doors` | Doors | Entrances into enterables; add physics/colliders | `staging` |
| `military-box-ussr` | Ammo crate | **Only inside** buildings | `used` (Z2 INT_EntryHouse) |
| `nine-story-ussr` / `panelka` | Panel silhouettes | Exterior facade / skyline accents | `staging` |
| `old-fridge` | Fridge | **Only inside** | `staging` |
| `old-tv` | CRT TV | **Only inside** (never plaza debris) | `used` (Z2 OldTV_Interior) |
Теперь Cursor всегда может обратиться к базе знаний и понять, что именно он ставит на карту, какого оно размера и масштаба по отношению к игроку и для какой зоны предназначено — экстерьер или интерьер. А вместе с тем добавил агента, который занимался подсчетом, что и куда было поставлено и в каком количестве использовано, чтобы не произошло банального перенасыщения зоны.

Cursor быстро сопоставил контроллер Unity с анимациями врагов, а потому уже при первой итерации с использованием ассетов у меня были абсолютно рабочие NPC. Исходя из ТЗ он также быстро раскидал интерактивные зоны, персонажей на‑поговорить и выставил баланс в схватках с разными врагами.
Отдельные зоны активировали плейсхолдер для катсцены, отдельные NPC преследовали игрока, дабы заговорить с ним (также строго в ограниченной зоне), отдельные враги спавнились рандомно в одной из зон, которые для того подходят.
Так как в исходном промпте было указано, что игра подразумевает выживание, Cursor быстро сообразил, как гармонично выставить усталость, голод, жажду в зависимости от действий игрока.
Главный урок здесь — четкая классификация мира игры. ИИ должен иметь конкретную документацию, в которой обозначено назначение объекта, его тип, расположение и связь с соседними элементами. Вместе с этим любые изменения агент должен документировать и регулярно с ними сверяться.
Второй урок — выстроить пайплайн генерации и создания нового объекта чаще всего сильно проще, чем выстроить оный для исправления того, что сделал кто‑то другой. Ассеты освещения, погоды, генерации объектов и привязки игрового персонажа к контроллеру игрока можно использовать готовые, но только если они актуализированы для свежей версии движка Unity.
И третий урок — не стоит полагаться на то, как ИИ понимает вашу задумку. Она также должна быть максимально конкретизирована и привязана к уже существующей документации.
Автор: sdevg
Источник [5]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/35603
URLs in this post:
[1] Логика: http://www.braintools.ru/article/7640
[2] боль: http://www.braintools.ru/article/9901
[3] опыт: http://www.braintools.ru/article/6952
[4] интеллект: http://www.braintools.ru/article/7605
[5] Источник: https://habr.com/ru/articles/1083108/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1083108
Нажмите здесь для печати.