AI‑GameDev. Учим ИИ азам левел‑дизайна. blender.. blender. cursor.. blender. cursor. unity.. blender. cursor. unity. unity3d.. blender. cursor. unity. unity3d. геймдев.. blender. cursor. unity. unity3d. геймдев. дизайн игр.. blender. cursor. unity. unity3d. геймдев. дизайн игр. искусственный интеллект.. blender. cursor. unity. unity3d. геймдев. дизайн игр. искусственный интеллект. Машинное обучение.. blender. cursor. unity. unity3d. геймдев. дизайн игр. искусственный интеллект. Машинное обучение. Разработка игр.. blender. cursor. unity. unity3d. геймдев. дизайн игр. искусственный интеллект. Машинное обучение. Разработка игр. разработка игр под windows.

Все уже наверняка видели посты на «Бэкдорах», «Эксплойтах» и прочих кибертопорах о том, как кто‑то, особенно с выходом новой модели, естественно, в один промпт сгенерировал копию Call of Duty, Starfield или любой другой игры. По видео выглядит сыровато, но играбельно, однако ключевая проблема здесь в том, что это демонстрационный вариант в формате браузерной игры. То есть совсем не те проекты, где мы с вами увлеченно сидим часами (любители браузерных игр и мобилок простите).

Как любой геймер, я всегда мечтал сделать свою игру. Не то что бы мне недоставало проектов, которые регулярно презентуют на Gamescom, а потом убирают на полку. Но хочется чего‑то своего, людского, с российским колоритом. А наш ААААА‑геймдев только начал подавать признаки жизни.

Я умею в C#, более‑менее понимаю, как устроен Unity, могу поковыряться в Blender и что‑то подрисовать на развертке в фотошопе. Но просто не хочу и все. С бесконечными задачами по работе, хобби и бытовым СДВГ сесть за какой‑то долгострой нет ни времени, ни возможности. А потому меня посетила мысль отработать маркетинг желтушных IT‑каналов на полную и собрать игру исключительно при помощи ИИ. Без единой собственной строчки кода, без единой собранной вручную модели и отрисованной текстуры.

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

В чем идея проекта?

Текущие модели уже позволяют спокойно собирать игры с низкополигональными ассетами, визуальные новеллы, пиксельные рогалики и мобильные игры. Для инди‑разработчиков этот сегмент всегда был доступен и таковым остается. Я же хочу собрать игру от третьего лица с графикой AA‑уровня, интересными механиками, разнообразными врагами, возможно боссами и атмосферным сеттингом. Не думайте, что к типичным инди‑проектам я отношусь предвзято, но выбранный мной подход обусловлен необходимостью отладки дополнительных технических аспектов, чего попросту нет на играх с простой графикой и физикой.

Во‑первых, 2D игры не содержат сложного пространства, на чем ИИ, забегая вперед, сыпется. Логика и физика перемещения в таких играх происходит по двум осям, расстояния между объектам рассчитает даже ребенок, а головная боль в виде масштаба по высоте в зависимости от игрока и NPC отпадает сама собой.

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

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

Инструменты

В качестве движка я выбрал Unity. У него удобный официальный MCP, который релизнулся совсем недавно, и уже перерос в полноценную интеграцию с Unity CLI. В качестве генератора моделей MeshyAI. В качестве инструмента для правки моделей, для авторига — Blender и его аддон Riggify. Анимации также позволяет делать Meshy, но для дополнительного ресурса я решил взять общепризнанный Mixamo. В качестве моего личного работника Rockstar, вынужденного трудиться 24 часа в сутки, я взял Cursor. Уже сейчас могу сказать, что это не самое сильное решение, но оно оказалось под рукой. Следующий на очереди для тестирования в уже отлаженном пайплайне будет Codex, а затем самосборный харнесс.

Также стоит сразу сказать о небольшом читинге, который я использовал и временно использую для тестирования самых узких технических мест. Я использую бесплатные ассеты построек, а также бесплатные или слитые платные контроллеры, внутренние жанровые движки и утилиты вроде RoomGen. Это небольшое отступление от изначальной задумки, так как бесплатные ассеты нуждаются в доработке как минимум текстур, а зачастую и самих моделей. Контроллеры обеспечивают легкую привязку клавиатуры к игровому персонажу, а потому не сильно разрушают мой замысел. Что же касается внутренних движков а‑ля «собери свой хоррор или соулслайк» — это слитые платные ассеты для очень старых версий Unity, поэтому нуждаются в комплексной доработке и адаптации под новую версию. К тому же, мы ведь хотим сделать что‑то новенькое, а потому наиболее интересные механики и игровой баланс позаимствуем и внедрим в наш проект.

Первый опыт взаимодействия со скачанными контроллерами и FPS‑движками моментально уперся в то, что Unity 6 совершенно не умеет (да и не должна) работать с проектами прошлых версий. На одном в качестве зависимости подтянулся старый NavMesh, который ломал буквально все. В новой версии он заменен Ai Navigation и переписывать и перевязывать весь внутренний игровой контроллер оказалось плохой идеей.

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

Результат получился неплохим, текстуры стали более качественными, но съехал PBR (это такой набор специальных карт, которые помогают виртуальному свету падать и отражаться на объектах, благодаря нему мы видим шероховатости и текстурность, а также мелкие тени). Так произошло из‑за того, что Nano Banana в рамках стилизации дорисовывала новые трещины, отколы и щели, не меняя по понятным причинам сами карты.

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

И чем дальше я продолжал правки, тем больше их становилось. И как это часто бывает с ИИ, одно упущенное действие на этапе его взаимодействия с MCP Blender, например, спустя несколько итераций приводило к тому, что где‑то что‑то не стыкуется.

Главная проблема

Первая попытка была исключительно экспериментальной. Я запустил Cursor, дал ему написанное через Perplexity подробное ТЗ и просто наблюдал.

Не буду прилагать ТЗ целиком, но вкратце суть была в короткой демке survival‑horror в обычном российском городе. Это совсем не то, что я планирую сделать в финале, но для обкатки технических тонкостей идеально — много зданий, много переулков, растительность, газоны и NPC.

Пока я позволил себе пару часов, так сказать, повайбить, Cursor собрал рабочий проект, в котором были враги, игровой персонаж, крупная локация, постройки и несколько интерактивных зон. Все за один промпт! Пока без текстур и реальных моделей, но прототип появился прямо у меня перед глазами.

Здесь я столкнулся с первой и главной проблемой. Искусственный интеллект не понимает, что такое 3D‑пространство, во всяком случае исходя из тех данных, что он получает от Unity. Он может его прочитать, но не может визуализировать и самое главное, он не понимает, как должен быть устроен нормальный город и как он заполняется физическими объектами. То есть город есть, но здания расположены так, как вообще‑то они расположены быть попросту не могут, если вы не в цыганском поселке с простирающимся до горизонта самостроем.

AI‑GameDev. Учим ИИ азам левел‑дизайна - 1

Я решил поступить с этой проблемой радикально. Я просто выгрузил с 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 всегда может обратиться к базе знаний и понять, что именно он ставит на карту, какого оно размера и масштаба по отношению к игроку и для какой зоны предназначено — экстерьер или интерьер. А вместе с тем добавил агента, который занимался подсчетом, что и куда было поставлено и в каком количестве использовано, чтобы не произошло банального перенасыщения зоны.

AI‑GameDev. Учим ИИ азам левел‑дизайна - 2

Что получилось сразу и какие уроки я извлек

Cursor быстро сопоставил контроллер Unity с анимациями врагов, а потому уже при первой итерации с использованием ассетов у меня были абсолютно рабочие NPC. Исходя из ТЗ он также быстро раскидал интерактивные зоны, персонажей на‑поговорить и выставил баланс в схватках с разными врагами.

Отдельные зоны активировали плейсхолдер для катсцены, отдельные NPC преследовали игрока, дабы заговорить с ним (также строго в ограниченной зоне), отдельные враги спавнились рандомно в одной из зон, которые для того подходят.

невзрачная, но рабочая зона магазина, отвечающая за быструю покупку ресурсов

невзрачная, но рабочая зона магазина, отвечающая за быструю покупку ресурсов

Так как в исходном промпте было указано, что игра подразумевает выживание, Cursor быстро сообразил, как гармонично выставить усталость, голод, жажду в зависимости от действий игрока.

Главный урок здесь — четкая классификация мира игры. ИИ должен иметь конкретную документацию, в которой обозначено назначение объекта, его тип, расположение и связь с соседними элементами. Вместе с этим любые изменения агент должен документировать и регулярно с ними сверяться.

Второй урок — выстроить пайплайн генерации и создания нового объекта чаще всего сильно проще, чем выстроить оный для исправления того, что сделал кто‑то другой. Ассеты освещения, погоды, генерации объектов и привязки игрового персонажа к контроллеру игрока можно использовать готовые, но только если они актуализированы для свежей версии движка Unity.

И третий урок — не стоит полагаться на то, как ИИ понимает вашу задумку. Она также должна быть максимально конкретизирована и привязана к уже существующей документации.

Автор: sdevg

Источник