Честно говоря, когда я впервые задумался о добавлении системы строительства, я и представить не мог, насколько это окажется сложным. Я использую Unreal Engine 5 и первая мысль, которая пришла мне в голову: "Ну, это же не должно быть так уж трудно, верно? Может, кто-то уже снял об этом видео!"
Я начал искать на YouTube, просматривать курсы на Udemy и так далее. Udemy оказался практически мёртв в этом вопросе — или мне просто не повезло. YouTube был полон базовых туториалов, которые показывали, как настроить простейшую систему строительства, и на этом всё. Никакой глубины, ничего действительно полезного — только примитивные системы, которые либо едва работали, либо вообще не подходили под мои нужды. Я искал именно систему привязки строительства, похожую на Satisfactory.
Ладно, следующая мысль: "Ну, наверняка должен быть хороший плагин или ассет для этого!" Я обыскал Marketplace Unreal Engine (тогда ещё не было FAB), и ситуация повторилась. Либо ассеты были слишком примитивными, либо просто не подходили под мои цели.
И вот тогда я понял, что придётся разрабатывать свою систему. И вот тут косяк — практически не было информации — не только о том, как создать такую систему, но даже о том, как её описать или определить принципы её работы. Чем больше я размышлял, тем сильнее ощущал, что изобретаю велосипед (классика программирования, да?).
Вот к чему я пришёл
Сначала мне нужно было точно понять, как должна работать моя система. Большинство моих зданий имеют форму куба или прямоугольника, поэтому я решил начать с простого. Я представил себе, что делю одну сторону куба (для удобства буду называть всё кубами) на пять частей.
Когда другой куб пытается прикрепиться к существующему, я вычисляю, на какую зону смотрит камера игрока, и привязываю объект соответственно. Например:
Зона 1 → Привязка к верхней стороне
Зона 2 → Привязка к нижней стороне
Зона 3 → Привязка к левой стороне
Зона 4 → Привязка к передней стороне
Зона 5 → Привязка к правой стороне
Я не хотел использовать коллижн-боксы или что-то подобное. Да, это бы ограничило привязку, потому что игроку пришлось бы целиться прямо на существующую структуру, но зато система была бы оптимизирована.
Затем я начал реализовывать всё на чистой математике. Определение зон оказалось не таким сложным — хаотичным, но возможным. Я даже создал рабочий прототип! Но тут возникли две большие проблемы:
Система была слишком... общей. У меня было мало контроля над ней, и расширять её было болью, потому что, ну... я не так уж силён в математике.
Всё работало нормально, пока куб не поворачивался. Как только он поворачивался... всё шло к чертям. Система просто рушилась.
После нескольких недель попыток исправить эти проблемы я сдался и начал думать о другом подходе. Если я не могу справиться с этим через сложные вычисления, может, стоит попробовать пойти в лоб что называется — что-то, что просто работает, пусть и не будет элегантным решением.
И вот тут началась моя безумная идея...
Вы можете сказать мне, что это бред — я и сам чувствую что вариант не лучший. Но он работает.
Я создал простую модель куба в движке, затем вручную добавил 30 сокетов — по пять на каждую сторону куба — и использовал систему ID для отслеживания, где какой сокет.
Камера игрока смотрит на куб
Из камеры идет трейс луч на куб, который обрамляет любую модель в игре (на которой можно строить).
Я проверяю, какой сокет ближе всего к точке попадания трейса.
Бум! Теперь я точно знаю, куда привязывать новый объект.
Слева - как здание выглядит в игре, справа как оно выглядит если отобразить куб для привязки
Но потом возникла ещё одна проблема, из-за которой система стала ещё сложнее.
Теперь я знал, куда именно смотрит игрок и где должна появиться новая сущность. Но как именно её выровнять относительно существующей структуры? Нужны были правила. Много правил. Так что я их создал. 13 различных наборов правил, если быть точным.
Каждый набор правил представлял собой таблицу данных внутри Unreal Engine, которая определяла, как должна работать привязка в зависимости от взаимного расположения точек.
Создание всех этих наборов правил было сущим адом. Но после множества часов работы я наконец получил то, что хотел — полностью рабочую систему привязки, которую (в основном) можно было настраивать и расширять.
Её не настолько просто менять, как мне бы хотелось, но по крайней мере, я знал, как она работает.
Код до сих пор выглядит как жопа, потому что у меня есть семь различных строительных объектов, и я должен был убедиться, что они все могут корректно соединяться. Это привело к появлению вот такого ужаса:
Но эй, оно работает! И теперь у меня есть:
✅ Привязка к сетке на любых поверхностях и многое другое
Вот как это выглядит в игре:
Я и сейчас продолжаю задаваться вопросом: А не изобрёл ли я велосипед? Не усложнил ли я себе жизнь?
В любом случае, надеюсь, вам понравился этот разбор моей системы! Дайте знать, если есть вопросы или если хочется чтобы я объяснил что-то подробнее.